Я работаю в Namecheap старшим инженером-программистом. В нашей компании мы часто используем Vue.js в интерфейсе с рендерингом на стороне сервера (SSR). Однако настроить SSR в первую очередь не всегда так просто. Вот почему я решил описать этот процесс простыми шагами, чтобы облегчить понимание.

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

В этой статье мы расскажем, как настроить готовый к работе SSR для приложения Vue, используя:

  • Webpack 4
  • Вавилон-7
  • Node.js Express сервер
  • Webpack-dev-middleware и webpack-hot-middleware для удобной среды разработки.
  • Vuex для управления состоянием
  • vue-meta плагин для управления метаданными

Замечу, что мы не будем рассматривать основы этих технологий. Мы сосредоточимся только на SSR и сразу же приступим к делу. Надеюсь, вы найдете это полезным ... А теперь давайте перейдем к делу!

Шаг 1. Настройте Webpack

На данный момент у вас, вероятно, уже есть приложение Vue, и если у вас его нет, не стесняйтесь использовать мое репо в качестве шаблона.

Во-первых, давайте взглянем на структуру наших папок и файлов:

Как видите, он довольно стандартен, за исключением пары вещей, которые могут вам понравиться:

  • есть две отдельные конфигурации веб-пакетов для клиентской и серверной сборок: webpack.client.config.js и webpack.server.config.js.
  • есть два соответствующих файла ввода: client-entry.js и server-entry.js.

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

Конфигурация клиента - это та, с которой вы, вероятно, уже имели дело. В основном он предназначен для сборки приложения в виде простых файлов JS и CSS.

Конфигурация сервера интересная. Он нужен нам для генерации специального пакета JSON файл - сервер, который будет использоваться на стороне сервера для рендеринга простого HTML приложения Vue. Для этого мы используем vue-server-renderer/server-plugin.

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

Как вы уже догадались, все общие настройки для клиентских и серверных конфигураций мы помещаем в базовую конфигурацию.

Шаг 2. Создайте записи приложения

Прежде чем мы перейдем к записям о клиенте и сервере, давайте взглянем на файл app.js:

Обратите внимание, что вместо простого создания экземпляра приложения мы экспортируем фабричную функцию createApp(). Если бы наше приложение работало только в среде браузера, нам не нужно было бы беспокоиться о том, что пользователи получат новый новый экземпляр Vue для каждого запроса. Но поскольку мы создаем приложение в процессе node.js, наш код будет оценен один раз и останется в памяти того же контекста.

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

Каждое реальное приложение будет иметь некоторые метаданные, такие как заголовок или описание, которые должны отличаться от страницы к странице. Вы можете добиться этого с помощью плагина vue-meta. Нажмите здесь, чтобы понять, почему мы используем ssrAppId вариант.

В записи клиента мы вызываем createApp(), передавая начальное состояние, введенное сервером. После того, как маршрутизатор завершил начальную навигацию, мы монтируем приложение в DOM. Также в этом файле вы можете импортировать глобальные стили и инициализировать директивы или плагины, которые работают с DOM.

Запись на сервере в значительной степени описывается комментариями в коде. Единственное, что я хотел бы добавить относительно обратного вызова router.onReady(), это то, что если мы используем ловушку serverPrefetch() для предварительной выборки данных в некоторых из наших компонентов, она будет ждать, пока обещание, возвращаемое из ловушки, не будет разрешено. Чуть позже мы увидим пример того, как его использовать.

Теперь мы можем добавить скрипты для создания нашего приложения в package.json:

Шаг 3. Запустите Express Server с помощью Bundle Renderer

Чтобы преобразовать приложение в обычный HTML-код на стороне сервера, мы будем использовать vue-server-renderer модуль и ./dist/vue-ssr-server-bundle.json файл, который мы создали с помощью build:server скрипта. Давайте пока не будем думать о режиме разработки, мы обсудим его на следующем этапе.

Во-первых, нам нужно создать средство визуализации, вызвав метод createBundleRenderer() и передав два аргумента: пакет, который мы сгенерировали ранее, и следующие параметры:

  • runInNewContext

Вы помните проблему с разделением состояния приложения между несколькими запросами, которую мы обсуждали на предыдущем шаге? Этот вариант призван решить эту проблему. Но создание нового контекста V8 и повторное выполнение пакета для каждого запроса - дорогостоящая операция, поэтому рекомендуется установить этот флаг на false из-за возможных проблем с производительностью. Также остерегайтесь использования синглтонов с отслеживанием состояния в приложении.

  • template

Есть специальный комментарий <! — vue-ssr-outlet — >, который будет заменен HTML-кодом, созданным средством визуализации. Кстати, используя параметр template, средство визуализации автоматически добавит скрипт с объявлением глобальной переменной __INITIAL_STATE__, которую мы используем в client-entry.js для создания нашего приложения.

Теперь, когда у нас есть экземпляр средства визуализации, мы можем сгенерировать HTML, вызвав метод renderToString(), передав начальное состояние и текущий URL-адрес для маршрутизатора.

Шаг 4. Настройте среду разработки

Что нам нужно для комфортной среды разработки? Я бы сказал следующее:

  • запустить только один сервер node.js без использования дополнительного webpack-dev-server
  • повторно генерировать vue-ssr-server-bundle.json файлов каждый раз, когда изменяется наш исходный код
  • горячая перезарядка

Чтобы выполнить все это, мы можем использовать функцию setupDevServer() в server.js (см. Предыдущий шаг).

Эта функция принимает два аргумента:

  • app - приложение «Экспресс»;
  • onServerBundleReady() - обратный вызов, который вызывается каждый раз, когда изменяется исходный код и создается новый vue-ssr-server-bundle.json. В качестве аргумента он принимает связку.

В server.js мы передаем обратный вызов onServerBundleReady() как стрелочную функцию, которая принимает новый пакет и повторно создает средство визуализации.

Обратите внимание, что нам нужны все зависимости внутри функции setupDevServer(), они нам не нужны для использования нашей памяти процесса в производственном режиме.

Теперь давайте добавим сценарий npm для запуска сервера в режиме разработки с использованием nodemon:

“dev”: “cross-env NODE_ENV=development nodemon ./server.js”,

Шаг 5. Используйте ServerPrefetch ()

Скорее всего, вам нужно будет получить данные с сервера при инициализации вашего приложения. Вы можете сделать это, просто вызвав конечную точку API после монтирования корневого компонента. Но в этом случае вашему пользователю придется наблюдать за счетчиком - не лучший пользовательский опыт. Вместо этого мы можем получить данные во время SSR, используя компонент serverPrefetch(), который был добавлен в версии 2.6.0 Vue. Давайте добавим конечную точку на наш сервер.

Мы вызовем эту конечную точку в getUsers действии. Теперь давайте рассмотрим пример использования ловушки serverPrefetch() в компоненте.

Как видите, мы используем serverPrefetch() вместе с хук mounted(). Он нам нужен в случаях, когда пользователь попадает на эту страницу с другого маршрута на стороне клиента, поэтому массив users пуст и мы вызываем API.

Также проверьте, как мы определяем метаданные заголовка и описания для конкретной страницы в свойстве metaInfo, предоставляемом плагином vue-meta.

Ну вот и все. Я думаю, что мы рассмотрели все основные моменты настройки SSR для Vue.js, и я надеюсь, что эти шаги помогли вам лучше понять этот процесс.