基于vue3实现ssr应用
- 大致流程
搭建Node Server
-
依赖 -> koa webpack webpack-cli webpack-node-externals
-
打包配置 排除包
textconst path = require("path"); const external = require("webpack-node-externals"); module.exports = { target: "node", // 去除 path fs ... mode: "development", entry: "./src/server/index.js", output: { filename: "server_bundle.js", path: path.resolve(__dirname, "../build/server"), }, externals: [external()], //排除node_module的包 }; "start": "nodemon ./src/server/index.js", "build:server": "webpack --config ./config/wp.config.js", "server": "node ./build/server/server_bundle.js"
vue3 + SSR 搭建
-
依赖项 -> vue vue-loader babel-loader @babel/preset-env
-
挂载根组件, 导出创建SSRAPP的方法
textimport { createSSRApp } from "vue"; import App from "./App.vue"; // 防止跨请求状态污染 // 返回app让页面每次创建不同的app export default function createApp() { return createSSRApp(App); } -
访问/ssr时,处理响应,拿到返回的字符串并渲染
text// 拿到vue的str const appStringHTML = await renderToString(ssrApp); ctx.body = ` <!DOCTYPE html> <html lang="en"> <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> <div id="app">${appStringHTML}</div> </body> </html> `; -
对页面进行激活(水合Hydration)
-
创建app -> createApp()
-
打包配置
textconst path = require("path"); const { VueLoaderPlugin } = require("vue-loader/dist"); module.exports = { target: "web", mode: "development", entry: "./src/client/index.js", output: { filename: "client_bundle.js", path: path.resolve(__dirname, "../build/client"), }, module: { rules: [ { test: /\.js$/, loader: "babel-loader", options: { presets: ["@babel/preset-env"], }, }, { test: /\.vue$/, loader: "vue-loader", }, ], }, plugins: [new VueLoaderPlugin()], // 不用externals需要的依赖文件, 因为交互需要使用 }; -
打包后的资源通过静态资源共享挂载到script上
textctx.body = ` <!DOCTYPE html> <html lang="en"> <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> <div id="app">${appStringHTML}</div> </body> <script>${jsStr}</script> </html> `; -
报警告flags VUE_OPTIONS_API, VUE_PROD_DEVTOOLS are not explicitly defined. You are running the esm-bundler build of Vue, which expects these compile-time feature flags to be globally injected via the bundler config in order to get better tree-shaking in the production bundle.
-
不使用optionsapi...,让它treeshaking
textnew DefinePlugin({ __VUE_OPTIONS_API__: false, __VUE_PROD_DEVTOOLS__: false, }), ],
-
跨请求状态污染问题
- 每次访问重新创建一个ssrAPP
-