Расшифровать Vue SSR

сервер JavaScript Vue.js HTML
Расшифровать Vue SSR

作者:百度外卖 耿彩丽 李宗原
转载请标明出处


введение

В последнее время автор и мои друзья изучают Vue SSR, но на рынке слишком много статей от 0 до 1, что не очень помогает всем понять принцип, поэтому эта статья будетИз процесса создания Vue SSR, рабочего процесса, характеристик, преимуществ и недостатков SSR.Эти аспекты имеют более подробное введение в Vue SSR. Напоследок будет приложена авторская реализацияДемонстрация удаления корзины семейства Vueкейс.

Разбираем процесс сборки

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

Процесс сборки Vue SSR

файл входа app.js

app.js — наша общая запись. Его функция — создать экземпляр Vue для использования сервером и клиентом. Обратите внимание, что в чисто клиентской программе наш app.js будет монтировать экземпляр в dom. В ssr, эта часть функции помещается в запись клиента, чтобы сделать это.


две записи

Далее давайте посмотрим на запись клиента и запись сервера, которые являются записью клиента и записью сервера соответственно.Функция входа в Client очень проста, она заключается в монтировании нашего экземпляра Vue к указанному элементу dom.; Запись сервера — это функция, экспортируемая с помощью экспорта. Он в основном отвечает за вызов метода сбора данных, определенного в компоненте, получение данных, необходимых для визуализации SSR, и их сохранение в контекстной среде.Эта функция будет вызываться повторно при каждом рендеринге..


сборка пакета webpack

Затем наш код на стороне сервера и код на стороне клиента упаковываются отдельно через веб-пакет для создания пакета сервера и пакета клиента.Первый будет работать на сервере для создания предварительно обработанных строк HTML через узел и отправки их нашему клиенту для завершения рендеринг инициализации; и клиентская связка бесплатна, и первоначальный рендеринг от него вообще не зависит. После того, как клиент получит строку HTML, возвращенную сервером, он «активирует» этот статический HTML, который станет DOM, динамически управляемым Vue, чтобы реагировать на последующие изменения данных.

Анализ запущенного процесса

Здесь следует поговорить о том, как работает программа ssr. Во-первых, нам нужно создать экземпляр Vue, что и сделал app.js, как мы упоминали в предыдущем процессе построения, но это отличается от традиционной программы рендеринга на стороне клиента, мыЕго необходимо инкапсулировать с помощью фабричной функции, чтобы каждый запрос пользователя мог возвращать новый экземпляр, как говорится на официальном веб-сайте, чтобы избежать перекрестного заражения..

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

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

Открываем сеть браузера, видим HTML, который инициализируется и рендерится, и это именно та структура, которую мы хотим инициализировать, и она вообще не зависит от js-файла клиента. После тщательного изучения есть инициализированная структура dom, css и тег скрипта. В теге script данные, которые мы получили в записи сервера, монтируются в окно. Оказалось, что это просто чистая статическая HTML-страница без какой-либо интерактивной логики, так что теперь я знаю, почему сервер должен запускать vue-клиент, а затем запускать другой vue.vue на сервере просто смешивает данные и отображает статическую страницу. цель клиента - добиться взаимодействия!

chrome network

Следуя предыдущей идее, мы должны посмотреть на запись клиента. Здесь клиент получает данные, хранящиеся в окне, и смешивает их с vuex нашего клиента, а затем анализирует данные для выполнения остальных клиентских операций, с которыми мы знакомы.

ССР уникальный

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

Сервер может выполнять только created и beforeCreate в жизненном цикле, потому что сервер не может манипулировать dom, поэтому вполне возможно, что другие циклы не могут быть выполнены.

Рендеринг на стороне сервера отличается от рендеринга на стороне клиента.Для запуска на сервере и клиенте необходимо создать две записи соответственно.И нужен веб-пакет, чтобы упаковать его отдельно;

Запрос сервера SSR без файлов cookie, вам нужно вручную получить файл cookie браузера, чтобы отправить запрос на сервер.Реализация нажмите здесь.

SSR требует спецификации структуры dom, потому что браузер автоматически добавит в HTML некоторые структуры, например tbody, но когда клиент запутывает HTML, возвращаемый сервером, эти теги не будут добавлены, что приведет к путанице между HTML и HTML-код, отображаемый браузером.

Вопросы производительности требуют большего внимания.

  • Неправильное использование vue.mixin и axios для перехвата запросов приведет к утечке памяти.Причина нажмите здесь
  • lru-cache кэширует данные в памяти, и необходимо разумно кэшировать ресурсы, которые не изменяются часто.

Может быть обоюдоострый меч

Преимущества ССР

  • Лучше для SEO.

Принципы работы разных краулеров схожи, они только сканируют исходный код и не будут выполнять какие-либо скрипты сайта (кроме Google, говорят, что Googlebot может запускать javaScript). После использования Vue или других сред MVVM большинство DOM-элементов страницы динамически генерируются на стороне клиента на основе js, и контент, доступный для анализа сканером, значительно сокращается. Кроме того, поисковые роботы браузера не ждут завершения обработки наших данных, прежде чем сканировать данные нашей страницы. Рендеринг на стороне сервера возвращает клиенту окончательный HTML-код, который получил асинхронные данные и выполнил сценарий JavaScript, а информация о всей странице может быть получена во время веб-сканирования.

  • Больше подходит для первого рендеринга экрана

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


Ограничения SSR

  • Давление со стороны сервера

Первоначально рендеринг выполнялся через клиент, но теперь он унифицирован для службы узла сервера. Особенно в случае большого количества одновременных обращений это займет много ресурсов ЦП сервера;

  • Условия разработки ограничены

При рендеринге на стороне сервера хуки жизненного цикла, отличные от created и beforeCreate, недоступны, поэтому сторонние библиотеки, на которые ссылается проект, не могут использовать другие хуки жизненного цикла, что сильно ограничивает выбор справочных библиотек;

  • Стоимость обучения относительно высока

Помимо знакомства с webpack и Vue, вам также необходимо освоить технологии Node и Express. По сравнению с рендерингом на стороне клиента процесс построения и развертывания проекта более сложен.

Практика SSR по удалению VUEX

Сначала прикрепите демо-адрес,кликните сюда!

Скажите перед:

  • vue-маршрутизатор не нужен, на самом деле сделать vue без маршрутизатораpreRenderВсе, ssr делать совершенно не нужно;
  • векс не нужен, vuex — это ключ к реализации разделения состояния между нашим клиентом и сервером, мы не можем использовать vuex, но мы должны реализовать набор логики предварительной выборки данных;

Демо на официальном сайте большое и полное.В него интегрированы vue-router и vuex.Если мы не будем использовать эти два в нашем проекте, то для их внедрения потребуется стоимость трансформации.Это не "плавный" переход мы хотим.Далее автор шаг за шагом проведет вас, чтобы сделать демонстрацию «ничего».

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

Прежде всего, нам нужно, чтобы наши компоненты «расшаривали» этот EventBus, для чего автор просто инкапсулирует плагин:

export default {
 install (Vue) {
   const EventBus = new Vue({
     data () {
       return {
	      list: [],
	      nav: []
       }
     },
     methods: {
       getList () {
	      // get list
		},
       getNav () {
         // get nav
       }
     }
   })
   
   Vue.prototype.$events = EventBus
   Vue.$events = EventBus
 }
}

Затем нам нужно экспортировать наш EventBus в main.js для использования двух записей. Итак, наш main.js выглядит так:

import Vue from 'vue'
import App from './App'
import EventBus from './event'

Vue.use(EventBus)
Vue.config.devtools = true

export function createApp () {
 const app = new Vue({
   // 注入 router 到根 Vue 实例
   router,
   render: h => h(App)
 })
 
 return { app, router, eventBus: app.$events }
}

Далее две наши записи. Сервер используется для сопоставления нашего компонента и вызова метода asyncData компонента для получения данных, а клиент используется для хранения предварительно обработанных данных в данных в нашей шине событий.

// server
import { createApp } from './main'

export default context => {
 return new Promise((resolve, reject) => {
   const { app, eventBus, App } = createApp()
   // 这里笔者的demo比较简单,仅app组件需要预取数据,复杂业务可以递归遍历哈;
   const matchedComponents = [App]

   Promise.all(matchedComponents.map(({ asyncData }) => asyncData && asyncData({
     eventBus
   }))).then(() => {
     context.state = eventBus._data
     resolve(app)
   }).catch(reject)
 })
}


// client
import Vue from 'vue'
import { createApp } from './main'
const { app, eventBus } = createApp()

if (window.__INITIAL_STATE__) {
 eventBus._data = window.__INITIAL_STATE__
}

app.$mount('#app')

Затем нам нужно преобразовать наши компоненты.Нам нужно только определить асинхронный метод для вызова метода в EventBus, чтобы получить его.Учитывая, что сервер выполняет только два жизненных цикла beforeCreate и created, а beforeCreate не может получить данные, нам нужно использовать создано в создано для получения данных.

// 服务端渲染数据预取;
asyncData ({ store, eventBus }) {
 return eventBus.getNav()
}
// 将服务端拿到的数据混入vue组件中;
created () {
 this.nav = this.$events.nav
}


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

Первый — это webpack.server.conf.js, который используется для создания пакета сервера для передачи функции createBundleRenderer для вызова на сервере узла.Файл входа — это наш входной сервер:


const webpack = require('webpack')
const merge = require('webpack-merge')
const nodeExternals = require('webpack-node-externals')
const baseConfig = require('./webpack.base.conf.js')
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
// 去除打包css的配置
baseConfig.module.rules[1].options = ''

module.exports = merge(baseConfig, {
 entry: './src/entry-server.js',
 // 以 Node 适用方式导入
 target: 'node',
 // 对 bundle renderer 提供 source map 支持
 devtool: '#source-map',
 output: {
   filename: 'server-bundle.js',
   libraryTarget: 'commonjs2'
 },
 externals: nodeExternals({
   whitelist: /\.css$/
 }),
 plugins: [
   new webpack.DefinePlugin({
     'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
     'process.env.VUE_ENV': '"server"'
   }),
   // 这是将服务器的整个输出
   // 构建为单个 JSON 文件的插件。
   // 默认文件名为 `vue-ssr-server-bundle.json`
   new VueSSRServerPlugin()
 ]
})

Далее идет webpack.client.conf.js, где мы можем сгенерировать clientManifest в соответствии с официальной конфигурацией, автоматически вывести и внедрить предварительную загрузку ресурсов и связать теги css/script с отображаемым HTML. Запись — это наш клиент-сервер:


const webpack = require('webpack')
const merge = require('webpack-merge')
const base = require('./webpack.base.conf')
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')

const config = merge(base, {
 entry: {
   app: './src/entry-client.js'
 },
 plugins: [
   new webpack.DefinePlugin({
     'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
     'process.env.VUE_ENV': '"client"'
   }),
   new webpack.optimize.CommonsChunkPlugin({
     name: 'vendor',
     minChunks: function (module) {
       return (
         /node_modules/.test(module.context) &&
         !/\.css$/.test(module.request)
       )
     }
   }),
   // 这将 webpack 运行时分离到一个引导 chunk 中,
   // 以便可以在之后正确注入异步 chunk。
   // 这也为你的 应用程序/vendor 代码提供了更好的缓存。
   new webpack.optimize.CommonsChunkPlugin({
     name: 'manifest'
   }),
   new VueSSRClientPlugin()
 ]
})


С локального хоста мы видим, что данные, предварительно извлеченные ssr, были успешно освобождены, и все готово!

Эпилог

В этой статье представлен процесс построения и работы SSR Vue, а также анализируются характеристики, преимущества и недостатки SSR, в надежде помочь вам понять SSR. Наконец, представлена ​​схема реализации SSR без vuex.Если вам интересно или есть вопросы, оставьте сообщение для связи.