Статьи

Расширенный рендеринг на стороне сервера с Laravel и Vue: многостраничное приложение

Несколько недель назад я написал учебник по новым возможностям рендеринга на стороне сервера для Laravel. В этом руководстве основное внимание уделялось настройке SSR в среде Laravel, поэтому у меня было время продемонстрировать простое приложение «Hello World» без каких-либо существенных функций.

Теперь я хочу развить этот предыдущий учебник и продемонстрировать, как выполнить серверную визуализацию приложения Vue, включающего несколько страниц, с помощью Vue Router, поскольку большинство ваших проектов Laravel будут иметь более одной страницы.

Вы можете получить готовый код для этого урока здесь, на GitHub .

Примечание: эта статья была первоначально размещена  здесь в блоге разработчиков  Vue.js 2017/11/27

Монтаж

Этот учебник расширит приложение, созданное мной в предыдущей статье, « Рендеринг на стороне сервера с помощью Laravel & Vue.js 2.5» . Убедитесь, что вы знакомы с его работой и настроили подходящую среду разработки, например, с установленным расширением php-v8js.

Если у вас нет этого кода, клонируйте его и настройте:

$ git clone https://github.com/anthonygore/vue-js-laravel-ssr
$ cd vue-js-laravel-ssr
$ cp .env.example .env
$ composer install
$ npm i

Затем установите Vue Router:

$ npm i --save-dev vue-router

Модуль маршрутизатора

Мы начнем с создания файла для конфигурации нашего маршрутизатора, который экспортирует экземпляр маршрутизатора для использования в приложении.

Я составил несколько примеров маршрутов, каждый из которых отображал компонент, сгенерированный из метода pageComponent. Этот фабричный метод возвращает простой компонент, который ничего не делает, кроме отображения имени страницы. Это все, что нам нужно для доказательства работ SSR маршрутизации.

ресурсы / активы / JS / router.js

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router);

function PageComponent(name) {
 return {
   render: h => h('h3', `Hello from the ${name} page`)
 };
}

export default new Router({
  mode: 'history',
  routes: [
    { path: '/', component: PageComponent('Home'), name: 'home' },
    { path: '/about', component: PageComponent('About'), name: 'about' },
    { path: '/contact', component: PageComponent('Contact'), name: 'contact' }
  ]
});

В основном файле приложения мы теперь импортируем модуль маршрутизатора и добавим его в приложение, как в любом проекте Vue. Затем экземпляр приложения экспортируется для использования в файлах входа клиента и сервера.

ресурсы / активы / JS / app.js

import App from './components/App.vue';
import Vue from 'vue';
import router from './router'

export default new Vue({
  router,
  render: h => h(App)
});

Маршруты Ларавела

Обратите внимание, что наш экземпляр Vue Router находится в режиме истории, поэтому маршруты будут откатываться к серверу при обновлении или загрузке подстраницы с панели навигации.

Это означает, что любой маршрут, который мы создали во внешнем приложении, также должен быть создан на стороне сервера. Все они могут указывать на один и тот же метод контроллера get:

<?php

Route::get('/', 'AppController@get');
Route::get('/about', 'AppController@get');
Route::get('/contact', 'AppController@get');

Теперь нам нужно настроить многостраничный SSR в контроллере. Это модификация логики в базовом приложении, поэтому убедитесь, что вы знакомы с тем, как это работает.

Чтобы создать многостраничное приложение SSR, нам нужно сообщить приложению сервера Vue (как определено в entry-server.js ), какой текущий URL-адрес запрашивается. Это гарантирует, что когда приложение загружается в песочницу, оно отображает правильный компонент страницы.

Для этого мы передаем URL, то есть $request->path(), через renderметод из getметода. Затем мы сохраняем URL-адрес в глобальной переменной JavaScript, urlкоторая будет доступна из серверного приложения Vue при запуске в песочнице.

приложение / HTTP / Контроллеры / AppController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Routing\Route;

class AppController extends Controller
{
  private function render($path) {
    $renderer_source = File::get(base_path('node_modules/vue-server-renderer/basic.js'));
    $app_source = File::get(public_path('js/entry-server.js'));

    $v8 = new \V8Js();

    ob_start();

    $js = 
<<<EOT
var process = { env: { VUE_ENV: "server", NODE_ENV: "production" } }; 
this.global = { process: process }; 
var url = "$path";
EOT;

    $v8->executeString($js);
    $v8->executeString($renderer_source);
    $v8->executeString($app_source);

    return ob_get_clean();
  }

  public function get(Request $request) {
    $ssr = $this->render($request->path());
    return view('app', ['ssr' => $ssr]);
  }
}

Приложение Vue Server

Последний важный шаг — изменить приложение сервера Vue, чтобы мы могли программно установить URL-адрес, а не ждать, пока пользователь сделает это.

Логика для этого находится внутри функции обратного вызова Promise. Вот что он делает:

  • Маршрутизатор устанавливается на правильный URL, нажав глобальную переменную url
  • Когда маршрутизатор готов, мы видим, отображаются ли какие-либо компоненты страницы в результате этого нажатия, сообщая нам, что маршрут действителен. Если нет, мы бросаем 404. Если это так, мы возвращаем экземпляр приложения.

Обещание используется, потому что маршрутизатор загружается асинхронно. Как только это обещание разрешится, мы можем использовать метод рендеринга сервера renderVueComponentToStringдля SSR экземпляра и, наконец, использовать printдля возврата вывода обратно в нашу среду Laravel.

ресурсы / активы / JS / вход-server.js

import app from './app'
import router from './router';

new Promise((resolve, reject) => {
  router.push(url);
  router.onReady(() => {
    const matchedComponents = router.getMatchedComponents();
    if (!matchedComponents.length) {
      return reject({ code: 404 });
    }
    resolve(app);
  }, reject);
})
  .then(app => {
    renderVueComponentToString(app, (err, res) => {
      print(res);
    });
  })
  .catch((err) => {
    print(err);
  });

Файл приложения

Логика SSR для многостраничного приложения завершена. Давайте создадим некоторые ссылки на маршрутизатор на странице, чтобы мы могли протестировать приложение в браузере:

ресурсы / активы / JS / компоненты / App.vue

<template>
  <div id="app">
    <h1>{{ title }}</h1>
    <router-view></router-view>
    <router-link :to="{ name: 'about' }">About</router-link>
    <router-link :to="{ name: 'contact' }">Contact</router-link>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        title: 'Welcome To My Site'
      }
    }
  }
</script>

Загрузка домашней страницы будет выглядеть так:

Настоящим тестом является посещение маршрута в навигационной панели, поэтому маршруты сервера обрабатывают запрос и, как мы надеемся, подтвердят приложение. Для этого посетите http://localhost:9000/aboutи проверьте разметку источника. Как вы можете видеть, оно включает отображаемое приложение по правильному URL:

Станьте старшим разработчиком Vue в 2020 году.

Узнайте и узнайте, что знают профессионалы о создании, тестировании и развертывании полнофункциональных приложений Vue в нашем последнем курсе.

Выучить больше