Эта статья будет продолжением моего предыдущего поста, где мы реализовали базовый рендеринг на стороне сервера. Теперь добавим увлажнение. Если приложение полагается на внешний ресурс, например данные, полученные из внешней конечной точки, данные должны быть извлечены и обработаны до того, как мы вызовем renderer.renderToString.

Исходный код доступен здесь.

В этом примере мы получим сообщение из JSONPlaceholder. Данные выглядят так:

Стратегия будет выглядеть так:

Отрисовка на стороне клиента:

  • в ловушке mounted жизненного цикла приложения, dispatch a Vuex action
  • commit ответ
  • рендерить как обычно

Рендеринг на стороне сервера:

  • проверьте статическую asyncData функцию, которую мы сделаем
  • передать магазин asyncData и позвонить dispatch(action)
  • зафиксировать результат
  • теперь у нас есть необходимые данные, звоните renderer.renderToString

Настраивать

Нам нужны новые модули. А именно:

  • axios - HTTP-клиент, работающий в браузере и в среде узлов.
  • vuex - для хранения данных

Установите их с помощью:

Создать магазин

Давайте сначала создадим магазин, и он будет работать на сервере разработки. Создайте магазин, запустив touch src/store.js. Внутри добавьте следующее:

Стандартный Vuex, ничего особенного, поэтому я не буду вдаваться в подробности.

Теперь нам нужно воспользоваться магазином. Обновление create-app:

Сейчас мы возвращаем { app, store, App }. Это потому, что нам понадобится доступ как к App, так и к store в src/server.js позже.

Если вы запустите npm run dev и посетите localhost:8080, все должно работать. Обновите src/Hello.vue, чтобы отправить действие в mounted и получить его, используя свойство computed:

computed: {    
  post() {      
    return this.$store.state.post    
  }   
}

localhost:8080 теперь должен отображать title, а также Hello.

Получение ресурсов на сервере

Запустите npm run build && node src/server.js, затем посетите localhost:8000. Вы заметите, что Hello отображается, а post.title - нет. Это потому, что mounted работает только в браузере. При использовании SSR нет динамического обновления, выполняются только created и beforeCreate. Смотрите здесь для получения дополнительной информации. Нам нужен другой способ отправки действия.

В Hello.vue добавьте функцию asyncData. Это не часть Vue, это обычная функция JavaScript.

Мы должны передать store в качестве аргумента. Это потому, что asyncData не является частью Vue, поэтому у него нет доступа к this, поэтому мы не можем получить доступ к хранилищу - фактически, поскольку мы вызовем эту функцию перед вызовом renderer.renderToString, this еще даже не существует.

Теперь обновите src/server.js для вызова asyncData:

Теперь при рендеринге app, store.state уже должен содержать post! Давайте попробуем:

Просмотр localhost:8000 вызывает отображение ошибки в терминале:

XMLHttpRequest - это веб-API, которого нет в среде узла. Но почему это происходит? axios предназначен для работы как на клиенте, так и на сервере, верно?

Давайте посмотрим на axios:

Есть куча всего. Интересующие поля: browser и main:

browser является источником проблемы. Узнайте больше о браузере на npm. Обычно, если есть поле browser, а target сборки веб-пакета - web, оно будет использовать поле browser вместо main. Давайте рассмотрим наш config/server.js:

Мы не указали target. Если мы проверим документацию здесь, то увидим, что значение по умолчанию для target - web. Это означает, что мы используем сборку axios, предназначенную для клиента, вместо сборки Node.js. Обновить config.server.js:

Теперь беги

и посетите localhost:8000. title визуализирован! Сравните это с localhost:8080, используя сервер разработки - вы можете видеть, что, когда мы выполняем выборку на стороне клиента, заголовок ненадолго остается пустым, пока запрос не будет завершен. При посещении localhost:8000 этой проблемы нет, поскольку данные извлекаются еще до того, как приложение будет отрисовано.

Заключение

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

В этом посте мы узнали:

  • о package.json, в частности о свойстве browser
  • свойство webpack target
  • как выполнить запрос ajax как на клиенте, так и на сервере

Улучшения

Осталось много улучшений:

  • использовать Vue Router (как на стороне сервера, так и на стороне клиента)
  • более надежная выборка данных
  • добавить несколько модульных тестов

Исходный код доступен здесь.

Изначально опубликовано в блоге Лахлана.