Эта статья будет продолжением моего предыдущего поста, где мы реализовали базовый рендеринг на стороне сервера. Теперь добавим увлажнение. Если приложение полагается на внешний ресурс, например данные, полученные из внешней конечной точки, данные должны быть извлечены и обработаны до того, как мы вызовем renderer.renderToString
.
Исходный код доступен здесь.
В этом примере мы получим сообщение из JSONPlaceholder. Данные выглядят так:
Стратегия будет выглядеть так:
Отрисовка на стороне клиента:
- в ловушке
mounted
жизненного цикла приложения,dispatch
a Vuexaction
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 (как на стороне сервера, так и на стороне клиента)
- более надежная выборка данных
- добавить несколько модульных тестов
Исходный код доступен здесь.
Изначально опубликовано в блоге Лахлана.