Apakah itu SSR? Artikel berikut akan memperkenalkan kepada anda kaedah melaksanakan pemaparan sisi pelayan SSR dalam vue saya harap ia akan membantu anda!
Server-Side Rendering
Kami memanggilnya SSR
, yang bermaksud pemaparan sebelah pelayan
merujuk kepada teknologi pemprosesan halaman yang melengkapkan HTML
penyambungan struktur halaman pada bahagian pelayan, menghantarnya ke penyemak imbas, dan kemudian mengikat status dan acara kepadanya untuk menjadi halaman interaktif sepenuhnya. [Cadangan berkaitan: tutorial video vuejs]
Mari kita lihat dahulu sejarah pembangunan 3 peringkat Web
:
Halaman web kandungan dipaparkan pada bahagian pelayan ⼀Pindahkan ke penyemak imbas pada satu masa
Buka halaman untuk melihat kod sumber yang diperolehi oleh penyemak imbas ialah keseluruhan dom
struktur
Pengalaman pengguna yang sangat baik bagi aplikasi satu halaman secara beransur-ansur menjadikan ia menjadi arus perdana Kandungan halaman dipaparkan oleh JS
Ini kaedah dipanggil pemaparan sisi klien
Buka halaman untuk melihat kod sumber Penyemak imbas hanya mendapat elemen hos #app
dan tiada kandungan
SSR
Penyelesaian: Bahagian belakang memaparkan struktur dom
lengkap skrin pertama dan mengembalikannya Kandungan yang diperolehi bahagian hadapan termasuk skrin pertama dan struktur spa
yang lengkap Selepas aplikasi diaktifkan, ia masih berjalan dalam mod spa
Selepas melihat pembangunan bahagian hadapan, mari kita lihat penjelasan rasmi Vue
tentang SSR
:
Vue.js digunakan untuk membina bingkai aplikasi klien. Secara lalai, komponen Vue boleh dikeluarkan dalam penyemak imbas untuk menjana DOM dan memanipulasi DOM. Walau bagaimanapun, anda juga boleh membuat komponen yang sama seperti rentetan HTML sebelah pelayan, menghantarnya terus ke penyemak imbas, dan akhirnya "mengaktifkan" teg statik ini sebagai aplikasi interaktif sepenuhnya pada klien
Rendering Pelayan A Aplikasi Vue.js juga boleh dianggap "isomorphic" atau "universal" kerana kebanyakan kod aplikasi boleh dijalankan pada kedua-dua pelayan dan klien
Kami mendapatkannya dari Laman Utama Diterangkan Kesimpulan berikut:
Vue SSR
ialah pemaparan sisi pelayan yang dipertingkatkan pada SPA
halaman yang dipaparkan melalui Vue SSR
akan mengandungi dua bahagian: skrin pertama yang diberikan oleh pelayan, termasuk interaktif Vue SSR
SPA
seo: Enjin carian mengutamakan merangkak halaman
struktur Apabila menggunakanHTML
ssr
HTML
pemaparan skrin pertama: pengguna boleh melihat paparan halaman tanpa menunggu semua seo
halaman dimuatkan (tekanan datang kepada pelayan, jadi adalah perlu untuk menimbang sama ada untuk menggunakan rendering sisi pelayan , yang diserahkan kepada pelanggan) js
Tetapi menggunakan SSR
Setiap permintaan adalah untuk
contoh Buat, jika tidak, ia akan tercemar, dan penggunaan akan menjadi sangat besarn
, node serve
Turun taraf: Monitor ngin
, penggunaan memori terlalu banyak, cuma cpu
spa
SSR
SEO
Di sini anda perlu menjana fail pelayan bundle
untuk pemaparan skrin pertama pelayan dan fail bundle
klien untuk pengaktifan klien
Sebagai tambahan kepada struktur kod Kecuali untuk dua pintu masuk yang berbeza, struktur lain adalah sama seperti aplikasi vue
sebelumnya
src ├── router ├────── index.js # 路由声明 ├── store ├────── index.js # 全局状态 ├── main.js # ⽤于创建vue实例 ├── entry-client.js # 客户端⼊⼝,⽤于静态内容“激活” └── entry-server.js # 服务端⼊⼝,⽤于⾸屏内容渲染
konfigurasi penghalaan
import Vue from "vue"; import Router from "vue-router"; Vue.use(Router); //导出⼯⼚函数 export function createRouter(){ return new Router({ mode: 'history', routes: [ // 客户端没有编译器,这⾥要写成渲染函数 { path: "/", component: { render: h => h('div', 'index page') } }, { path: "/detail", component: { render: h => h('div', 'detail page') }} ] }); }
fail utama main.js
adalah sama seperti sebelum Berbeza, fail utama adalah kilang yang bertanggungjawab untuk mencipta contoh vue
Setiap permintaan akan mempunyai penciptaan contoh vue
bebas
import Vue from "vue"; import App from "./App.vue"; import { createRouter } from "./router"; // 导出Vue实例⼯⼚函数,为每次请求创建独⽴实例 // 上下⽂⽤于给vue实例传递参数 export function createApp(context) { const router = createRouter(); const app = new Vue({ router, context, render: h => h(App) }); return { app, router }; }
Tulis entri pelayan src/entry-server.js
.
ia Tugasnya adalah untuk mencipta contoh Vue
dan menulis portal pelanggan berdasarkan url
masuk dengan menyatakan skrin pertama
import { createApp } from "./main"; // 返回⼀个函数,接收请求上下⽂,返回创建的vue实例 export default context => { // 这⾥返回⼀个Promise,确保路由或组件准备就绪 return new Promise((resolve, reject) => { const { app, router } = createApp(context); // 跳转到⾸屏的地址 router.push(context.url); // 路由就绪,返回结果 router.onReady(() => { resolve(app); }, reject); }); };
entry-client.js
Portal pelanggan hanya perlu mencipta contoh vue
Dan laksanakan pelekap, langkah ini dipanggil pengaktifan
import { createApp } from "./main"; // 创建vue、router实例 const { app, router } = createApp(); // 路由就绪,执⾏挂载 router.onReady(() => { app.$mount("#app"); });
Konfigurasikanwebpack
Pasang kebergantungan
npm install webpack-node-externals lodash.merge -D
Ya vue.config.js
Konfigurasikan
// 两个插件分别负责打包客户端和服务端 const VueSSRServerPlugin = require("vue-server-renderer/server-plugin"); const VueSSRClientPlugin = require("vue-server-renderer/client-plugin"); const nodeExternals = require("webpack-node-externals"); const merge = require("lodash.merge"); // 根据传⼊环境变量决定⼊⼝⽂件和相应配置项 const TARGET_NODE = process.env.WEBPACK_TARGET === "node"; const target = TARGET_NODE ? "server" : "client"; module.exports = { css: { extract: false }, outputDir: './dist/'+target, configureWebpack: () => ({ // 将 entry 指向应⽤程序的 server / client ⽂件 entry: `./src/entry-${target}.js`, // 对 bundle renderer 提供 source map ⽀持 devtool: 'source-map', // target设置为node使webpack以Node适⽤的⽅式处理动态导⼊, // 并且还会在编译Vue组件时告知`vue-loader`输出⾯向服务器代码。 target: TARGET_NODE ? "node" : "web", // 是否模拟node全局变量 node: TARGET_NODE ? undefined : false, output: { // 此处使⽤Node⻛格导出模块 libraryTarget: TARGET_NODE ? "commonjs2" : undefined }, // https://webpack.js.org/configuration/externals/#function // https://github.com/liady/webpack-node-externals // 外置化应⽤程序依赖模块。可以使服务器构建速度更快,并⽣成较⼩的打包⽂件。 externals: TARGET_NODE ? nodeExternals({ // 不要外置化webpack需要处理的依赖模块。 // 可以在这⾥添加更多的⽂件类型。例如,未处理 *.vue 原始⽂件, // 还应该将修改`global`(例如polyfill)的依赖模块列⼊⽩名单 whitelist: [/\.css$/] }) : undefined, optimization: { splitChunks: undefined }, // 这是将服务器的整个输出构建为单个 JSON ⽂件的插件。 // 服务端默认⽂件名为 `vue-ssr-server-bundle.json` // 客户端默认⽂件名为 `vue-ssr-client-manifest.json`。 plugins: [TARGET_NODE ? new VueSSRServerPlugin() : new VueSSRClientPlugin()] }), chainWebpack: config => { // cli4项⽬添加 if (TARGET_NODE) { config.optimization.delete('splitChunks') } config.module .rule("vue") .use("vue-loader") .tap(options => { merge(options, { optimizeSSR: false }); }); } };
Konfigurasikan skrip dan pasang kebergantungan
npm i cross-env -D
"scripts": { "build:client": "vue-cli-service build", "build:server": "cross-env WEBPACK_TARGET=node vue-cli-service build", "build": "npm run build:server && npm run build:client" }
Laksanakan pembungkusan: npm run build
Fail hos terakhir diubah suai/public/index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>Document</title> </head> <body> <!--vue-ssr-outlet--> </body> </html>
ialah lokasi kemasukan pemaparan sebelah pelayan Berhati-hati untuk tidak menambah ruang sebelum dan selepasnya untuk demi penampilan.
vuex
pelayan dalam fail
npm install -S vuex
Lakukan pemerolehan data satu langkah dalam
vuex
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export function createStore () { return new Vuex.Store({ state: { count:108 }, mutations: { add(state){ state.count += 1; } } }) }
main.js
Prafetching data sisi pelayan, store
import { createStore } from './store' export function createApp (context) { // 创建实例 const store = createStore() const app = new Vue({ store, // 挂载 render: h => h(App) }) return { app, router, store } }
Klien dipasang pada aplikasi Sebelum ini,
sepatutnya mendapat status,store
export function createStore() { return new Vuex.Store({ mutations: { // 加⼀个初始化 init(state, count) { state.count = count; }, }, actions: { // 加⼀个异步请求count的action getCount({ commit }) { return new Promise(resolve => { setTimeout(() => { commit("init", Math.random() * 100); resolve(); }, 1000); }); }, }, }); }
export default { asyncData({ store, route }) { // 约定预取逻辑编写在预取钩⼦asyncData中 // 触发 action 后,返回 Promise 以便确定请求结果 return store.dispatch("getCount"); } };
ubah suai fail permulaan pelayanentry-server.js
import { createApp } from "./app"; export default context => { return new Promise((resolve, reject) => { // 拿出store和router实例 const { app, router, store } = createApp(context); router.push(context.url); router.onReady(() => { // 获取匹配的路由组件数组 const matchedComponents = router.getMatchedComponents(); // 若⽆匹配则抛出异常 if (!matchedComponents.length) { return reject({ code: 404 }); } // 对所有匹配的路由组件调⽤可能存在的`asyncData()` Promise.all( matchedComponents.map(Component => { if (Component.asyncData) { return Component.asyncData({ store, route: router.currentRoute, }); } }), ) .then(() => { // 所有预取钩⼦ resolve 后, // store 已经填充⼊渲染应⽤所需状态 // 将状态附加到上下⽂,且 `template` 选项⽤于 renderer 时, // 状态将⾃动序列化为 `window.__INITIAL_STATE__`,并注⼊ HTML context.state = store.state; resolve(app); }) .catch(reject); }, reject); }); };
Ringkasanstore
entry-client.js
// 导出store const { app, router, store } = createApp(); // 当使⽤ template 时,context.state 将作为 window.__INITIAL_STATE__ 状态⾃动嵌⼊到最终的 HTML // 在客户端挂载到应⽤程序之前,store 就应该获取到状态: if (window.__INITIAL_STATE__) { store.replaceState(window.__INITIAL_STATE__); }
Tiada mod tunggal apabila menggunakan main.js
, dan contoh
Vue.mixin({ beforeMount() { const { asyncData } = this.$options; if (asyncData) { // 将获取数据操作分配给 promise // 以便在组件中,我们可以在数据准备就绪后 // 通过运⾏ `this.dataPromise.then(...)` 来执⾏其他任务 this.dataPromise = asyncData({ store: this.$store, route: this.$route, }); } }, });
// 获取⽂件路径 const resolve = dir => require('path').resolve(__dirname, dir) // 第 1 步:开放dist/client⽬录,关闭默认下载index⻚的选项,不然到不了后⾯路由 app.use(express.static(resolve('../dist/client'), {index: false})) // 第 2 步:获得⼀个createBundleRenderer const { createBundleRenderer } = require("vue-server-renderer"); // 第 3 步:服务端打包⽂件地址 const bundle = resolve("../dist/server/vue-ssr-server-bundle.json"); // 第 4 步:创建渲染器 const renderer = createBundleRenderer(bundle, { runInNewContext: false, // https://ssr.vuejs.org/zh/api/#runinnewcontext template: require('fs').readFileSync(resolve("../public/index.html"), "utf8"), // 宿主⽂件 clientManifest: require(resolve("../dist/client/vue-ssr-clientmanifest.json")) // 客户端清单 }); app.get('*', async (req,res)=>{ // 设置url和title两个重要参数 const context = { title:'ssr test', url:req.url } const html = await renderer.renderToString(context); res.send(html) })
ssr
vue
tak segerak pada skrin pertama, yang sepatutnya diselesaikan semasa pra-pemarahan sebelah pelayan
cangkuk Pemerolehan datassr
(Video pembelajaran perkongsian: asyncData
tutorial vuejs
Atas ialah kandungan terperinci Apakah SSR? Bagaimana untuk melaksanakan pemaparan sisi pelayan SSR dalam vue?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!