对vue SSR的理解和实例

895 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情

简介及优缺点

服务端渲染SSR(Server side Render):后端渲染出完整的DOM并返回,前端拿到内容包括首屏及spa结构,应用激活后依然按照spa的方式运行,这种渲染的页面方式称作为服务端渲染(SSR) 1649753417(1).jpg

  • 与SSR的区别
  1. 传统web开发 传统web的开发,网页内容在服务端渲染完成,一次性传输到浏览器,其中包括查询数据库拼接html字符串(模板),浏览器拿到的时全部的dom结构

1649754035(1).jpg

  1. 单页面应用Single Page App 单页面应用有着优秀的用户的体验,使其逐步成为主流,页面内容由JS渲染出来,这种方式称为客户端渲染,浏览器只拿到仅有的宿主元素#app,并没有内容 1649753980(1).jpg
  • 优点
  1. 方便SEO优化,保证浏览器搜索引擎爬虫抓取主要内容数据
  2. 响应更快,浏览器只需解析DOM,并直接构建DOM树即可
  • 缺点
  1. 渲染计算要放到客户端进行,会消耗CPU和内存资源
  2. 浏览器一些常用的api,无法使用

应用

创建工程和安装依赖

  1. vue-cli创建工程
vur create ssr
  1. 安装依赖 要确保vue、vue-server-renderer的版本一致
npm install vur-server-renderer

启动

  1. 创建一个express服务器,将vue ssr集成进来
const express = require("express");
const app = express()
  1. 导入VUE构造函数
const Vue = require("vue");
  1. createRenderer获取渲染器
const { createRenderer } = require("vue-server-renderer")
const renderer = createRenderer()
  1. 创建一个待渲染的Vue实例(模板) 用new Vue创建一个template模板并设置data参数,renderTostring将vue实例渲染为html字符串、并返回一个promise,最后返回到客户端(res.send()),如果渲染出错返回500错误,并返回,这里用tryCatch,防止报错不往下进行
app.get("/", async (req, res) => {
  const vm = new Vue({
  data: { name: "hello" },
  template: `
  <div >
  <h1>{{name}}</h1>
  </div>`
});
try { 
  const html = await renderer.renderToString(vm);
  res.send(html);
} catch (error) {
    res.status(500).send("Internal Server Error");   
  }
});

路由

SSR支持vur-router所以咱们继续使用这个

  • 创建路由实例
  1. 引入vue-router
const Router = require('vue-router')
Vue.use(Router)
  1. 挂载 在内通过new Router创建路由对象并在内配置路由routers:[{path:''}]等和传统的一样,随后在内创建vue实例引入router-link和router-vuew,并将它挂载上去
  app.get('*', async function (req, res) {
    const vm = new Vue({
      data: { msg: 'hello' },
      template: `
      <div>
          <router-link to="/">index</router-link>
          <router-view></router-view>
      </div>`,
      router, 
    })

    try {
      router.push(req.url);
      const html = await renderer.renderToString(vm)
    res.send(html) 
    } catch (error) {
      res.status(500).send('渲染出错')
    }
  })

通过try Catch判断跳转至相应的路由并开始渲染模板并返回给客户端,如果渲染出错返回500返回给客户端

同构开发ssr流程

对于同构开发,我们依然使用webpack进行打包,其中需要解决两个问题,服务端渲染和客户端激活

  • 构建流程 目标是生成一个服务器bundle,用于服务器首屏渲染,和一个客户端bundle用于客户端激活
  1. 代码结构 除了两个不同入口之外,其他的结构和之前vue完全一致
src
├── router
├────── index.js # 路由声明
├── store
├────── index.js # 全局状态
├── main.js # ⽤于创建vue实例
├── entry-client.js # 客户端⼊⼝,⽤于静态内容“激活”
└── entry-server.js # 服务端⼊⼝,⽤于⾸屏内容渲染
  1. 服务端入口 上面的bundel就是webpack打包服务器的bundel,我们需要编写服务器入口文件src/entry-server.js它的任务是创建vue实例并根据数据传入url指定首屏
  import { createApp } from "./main";
  export default context => {
  return new Promise((resolve, reject) => {
    const { app, router } = createApp(context);
    // 跳转到⾸屏的地址
    router.push(context.url);
    // 路由就绪,返回结果
    router.onReady(() => {
      resolve(app);
      }, reject);
    });
  };

它需要返回一个函数,接收请求的上下文context,返回一个创建vue的实例,在内返回一个Promise,确保路由或者组件准备就绪,在Promise内设置跳转到首屏的地址,随后挂载并返回挂载结果。

  1. 客户端入口 客户端入口只需要创建vue实例并执行挂载,这步成为激活,创建entry-client.js
import { createApp } from "./main";
const { app, router } = createApp();
router.onReady(() => {
  app.$mount("#app");
});

引入createApp并创建vue和router实例,路由准备就绪后,执行挂载

运行

npm run build:client //构建客户端
npm run build:serve  //构建服务端

参考资料

vue ssr官网介绍

服务端渲染SSR及实现原理