Vue服务端渲染SSR原理实战学习笔记

什么是 SSR

首先,Vue.js 是一个用于构建客户端应用的框架。默认情况下 Vue 组件的职责实在客户端浏览器中生成和操作 DOM。

然而,Vue 也支持将组件在服务端直接渲染成 HTML 字符串,并作为服务端响应返回给浏览器,最后在浏览器端将静态的 HTML“激活”为能够交互的客户端应用。————》这种服务端渲染技术就是 SSR。

为什么要用 SSR

优势:

  • 更快的首屏加载,原因有二:
    • 服务端渲染的 HTML 无需等到所有的 Javascript 都下载并执行完成之后才显示;
    • 服务端更快的数据库连接(数据接口相关请求).
  • 更好的 SEO,因为搜索引擎爬虫可以直接看到完全渲染的页面。
  • 统一的心智模型,理解引用 Vue 官方的介绍:

    你可以使用相同的语言以及相同的声明式、面向组件的心智模型来开发整个应用,而不需要在后端模板系统和前端框架之间来回切换。

限制和劣势:

  • 开发中的限制:
    • 浏览器端特定的代码只能在某些生命周期钩子中使用;
    • 一些外部库可能需要特殊处理才能在服务端渲染的应用中运行。
  • 更多的与构建配置和部署相关的要求。
    • 服务端渲染的应用需要一个能让 Node.js 服务器运行的环境,不像完全静态的 SPA 那样可以部署在任意的静态文件服务器上。
  • 更高的服务端渲染
    • 在 Node.js 中渲染一个完整的应用要比仅仅托管静态文件更加占用 CPU 资源。

SSR vs SSG

SSG:静态站点生成,也被称为预渲染,是另一种流行的构建快速网站的技术。

SSR 与 SSG 相同之处:

  • 都带来了优秀的首屏加载性能。

SSR 与 SSG 区别:

  • SSG 比 SSR 应用的花销更小,也更容易部署,因为 SSG 输出的是静态 HTML 和资源文件,且 SSG 仅可以用于消费静态数据的页面。

基础教程

服务端渲染一个应用

  • 第一步 创建一个新文件夹 vue-ssr,并在该文件夹下执行npm init -y生成 package.json,编辑 package.json 文件添加一行"type": "module",修改后的 package.json 文件内容如下:

    {
      "name": "vue-ssr",
      "version": "1.0.0",
      "type": "module",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "dependencies": {
        "express": "^4.18.2",
        "vue": "^3.3.4"
      }
    }
    
  • 第二步 安装依赖包

    • 安装 vue npm install vue
    • 安装 express npm install express
  • 第三步 创建 server.js 文件,并写入如下代码:

    import express from "express";
    import { createSSRApp } from "vue";
    // 导入Vue的服务端渲染API
    import { renderToString } from "vue/server-renderer";
    
    const server = express();
    
    server.get("/", (req, res) => {
      const app = createSSRApp({
        data: () => ({ count: 1 }),
        template: `<button @click="count++">{{ count }}</button>`,
      });
    
      renderToString(app).then((html) => {
        res.send(`    <!DOCTYPE html>
        <html>
          <head>
            <title>Vue SSR Example</title>
          </head>
          <body>
            <div id="app">${html}</div>
          </body>
        </html>
      `);
      });
    });
    
    server.listen(3000, () => {
      console.log("Server Started....");
    });
    

    Vue 的服务端渲染 API renderToString() 接受一个 Vue 应用实例作为参数,返回一个 Promise,当 Promise resolve 时返回应用渲染的 HTML。

  • 第四步 运行 node server.js 启动服务,浏览器访问 http://localhost:3000 ,就可以看到页面中按钮了。

客户端激活

什么是客户端激活呢?
细心的同学可能已发现,上文运行服务端代码后,点击浏览器中的按钮数字并没有自增改变。这是因为这段 HTML 代码在客户端是完全静态的,并没有在浏览器中加载 Vue。
那么为了使客户端的应用可交互,Vue 需要执行一个激活步骤。

在激活过程中,Vue 会创建一个于服务端完全相同的应用实例,然后将每个组件与它应该控制的 DOM 节点相匹配,并添加 DOM 事件监听器。

由于实现激活需要重新组织代码结构(下文的代码结构部分会详解),所以此处先展示一个激活的代码片段:

// 该文件运行在浏览器中
import { createSSRApp } from "vue";

const app = createSSRApp({
  // ...和服务端完全一致的应用实例
});

/**
 * 在客户端挂载一个 SSR 应用时,会假定 HTML 是预渲染的,然后执行激活过程,而不是挂载新的 DOM 节点
 */
app.mount("#app");

注意 在激活模式下挂载应用,应该使用createSSRApp() 而不是createApp()

完整 SSR 代码结构

通用代码 app.js

通用代码只是指在客户端和服务端可复用的代码及其依赖项,我们可以把这些拆分到一个或多个独立的文件中。本例中代码逻辑简单,拆分一个 app.js 文件即可:

// app.js
import { createSSRApp } from "vue";

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

客户端入口文件 client.js

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

createApp().mount("#app");

服务端入口文件 server.js
运行服务端文件后,为了在浏览器中加载客户端文件,还需要在 server.js 文件中做以下修改:

  • 增加一行 server.use(express.static('.')) 来托管客户端文件。
  • <script type="module" src="./client.js"></script> 添加到 HTML 外壳以加载客户端入口文件。
  • 通过在 HTML 外壳文件中添加 Import Map 以支持在浏览器中使用 import * from 'vue'

修改后的 server.js 完整代码如下:

import express from "express";
import { renderToString } from "vue/server-renderer";
import { createApp } from "./app.js";

const server = express();

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

  renderToString(app).then((html) => {
    res.send(`
    <!DOCTYPE html>
    <html>
      <head>
        <title>Vue SSR Example</title>
        <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>
    </html>
    `);
  });
});

server.use(express.static("."));

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

此时我们一开始创建的文件夹下的代码结构如下:

vue-ssr
|-- app.js
|-- client.js
|-- server.js
|-- package.json
|-- package-lock.json
|-- node_modules

最后重新运行 node server.js,再访问 http://localhost:3000 页面,点击按钮数字就会自增改变了。

通用解决方案

由于实现一套完整的 SSR 技术构建会非常复杂,因此建议和推荐大家在通过上面实例教程了解到 SSR 原理之后,选择一些成熟的 SSR 解决方案,以提高工作效率。下面推荐几个 Vue 生态中的 SSR 解决方案。

Nuxt 是一个构建于 Vue 生态系统之上的全栈框架,它为编写 Vue SSR 应用提供了丝滑的开发体验。更棒的是,你还可以把它当作一个静态站点生成器来用!我们强烈建议你试一试。

Quasar 是一个基于 Vue 的完整解决方案,它可以让你用同一套代码库构建不同目标的应用,如 SPA、SSR、PWA、移动端应用、桌面端应用以及浏览器插件。除此之外,它还提供了一整套 Material Design 风格的组件库。

  • Vite SSR

    Vite 提供了内置的 Vue 服务端渲染支持,但它在设计上是偏底层的。如果你想要直接使用 Vite,可以看看 vite-plugin-ssr,一个帮你抽象掉许多复杂细节的社区插件。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西涯三锋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值