重学 Vue3 之服务端渲染

206 阅读2分钟

概念

Vue 不仅可以用于客户端渲染,还可以用在服务端渲染。一个服务端的 Vue 应用被认为是同构的,因为大部分代码都会在客户端和服务端中运行。

服务端渲染相比客户端渲染有很多优势。它可以缩短首屏渲染时间,服务端生成 html 字符串后响应给浏览器,浏览器直接渲染 html 就可以看到页面内容,不需要再等待 javascript 获取和加载。它也可以提高 SEO,服务器生成 html 字符串后,爬虫就可以从中获取到网页信息。

例子

实现一个精简版的服务端渲染可以更好的理解服务端渲染的特点。

  1. 生成 package.json 并修改配置。初始化项目目录后, 就可以安装依赖 express 和 vue,express 用于启动一个服务器,vue 用于生成页面代码
// a. 生成 package.json 
npm init -y  

// b. 安装依赖
npm i express 
npm i vue
// c. 修改 package.json
{
  "name": "starting",
  "version": "1.0.0",
  "description": "",
  "main": "test.js",
  "type": "module",
  ... // 省略部分代码
  "dependencies": {
    "express": "^4.18.2",
    "vue": "^3.2.47"
  }
}

  1. 创建公共文件 app.js。包含数据 count 和点击修改 count 的事件,这部分代码服务端和客户端都需要。注意这里是 SSR 激活模式,所以需要使用 createSSRApp() 而不是 createApp()。
import { createSSRApp } from "vue";

export function createApp() {
  return createSSRApp({
    data: () => ({ count: 1 }),
    template: `<div @click="count++">{{count}}</div>`,
  });
}

  1. 客户端和服务端代码。客户端代码只需将 app.js 的内容渲染到浏览器上,而服务端代码做的事情比较多。它通过 express 创建一个服务器,响应根路由(/)的 get 请求,使用 renderToString 将组件转化成一个返回 string 的 promise,最后使用一个 html 模版渲染页面内容。
// server.js
import { renderToString } from "vue/server-renderer";
import express from "express";
import { createApp } from "./app.js";

const server = express();

server.get("/", ({ req, res }) => {
  const app = createApp();

  renderToString(app).then((html) => {
    res.send(`
    <head>
    <script type="importmap">
    {
      "imports": {
        "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
      }
    }
  </script>
      <script type="module" src="/client.js" ></script>
    </head>
    <body>
      <div id="app">${html}</div>
    </body>
    `);
  });
});

server.use(express.static(".")); // 将当前目录作为静态资源的根目录

server.listen("3000", () => {
  console.log("ready");
});

import { createApp } from "./app.js";

createApp().mount("#app");
  1. 整体流程分析。首先浏览器输入 URL 后得到 express 服务器的响应,将 server.js 生成的 html 字符串返给浏览器即可显示出页面内容。然后加载 script 脚本 client.js ,该脚本使用到了 import map 方法,从 cdn 获取到 vue 代码,再次渲染页面。这时候的页面即可以显示内容,又可以触发事件。

image.png

总结

理解服务端渲染的关键在于理解同构的思想,为了实现页面和渲染和内容可交互,把大部分代码进行了两次构建,一次是客户端,另一次和服务端。缩短了首屏渲染时间,提高 SEO,但也加大了服务端的负载。