基于Vue3的 ssr 自实现

Category:

Tags:

基于vue3实现ssr应用

  • 大致流程

搭建Node Server

  1. 依赖 -> koa webpack webpack-cli webpack-node-externals

  2. 打包配置 排除包

    text
    const 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 搭建

  1. 依赖项 -> vue vue-loader babel-loader @babel/preset-env

  2. 挂载根组件, 导出创建SSRAPP的方法

    text
    import { createSSRApp } from "vue"; import App from "./App.vue"; // 防止跨请求状态污染 // 返回app让页面每次创建不同的app export default function createApp() {  return createSSRApp(App); } ​
  3. 访问/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>  `;
  4. 对页面进行激活(水合Hydration)

    1. 创建app -> createApp()

    2. 打包配置

      text
      const 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需要的依赖文件, 因为交互需要使用 }; ​
    3. 打包后的资源通过静态资源共享挂载到script上

      text
         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>  <script>${jsStr}</script> </html>  `;
    4. 报警告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.

      1. 不使用optionsapi...,让它treeshaking

        text
           new DefinePlugin({      __VUE_OPTIONS_API__: false,      __VUE_PROD_DEVTOOLS__: false,   }), ],

    跨请求状态污染问题

    • 每次访问重新创建一个ssrAPP

效果