前言

在了解Vue SSR之前,我们要搞明白两个东西先:SSR浏览器的渲染,
涉及到的技术:

  1. Vue
  2. vue-server-renderer
  3. Nodejs
  4. Express

1. 什么是SSR

SSR是Server Side Render简称;页面上的内容是通过服务端渲染生成的,浏览器直接显示服务端返回的html就可以了。

2. 从输入页面URL到页面渲染完成流程

  1. 解析URL
  2. 浏览器本地缓存
  3. DNS解析
  4. 建立TCP/IP连接,发送HTTP请求
  5. 服务器处理请求并返回HTTP报文
  6. 浏览器根据返回的html进行构建DOM树,CSS规则树,如遇到script标签就加载对应的js

开始实践

(1) 第一步: vue-server-renderer

首先我们运用vue-server-renderer来创建一个文件,通过vue-server-renderer把我们的一个vue实例进行转化为字符串。
我们创建一个文件: server.js

const Vue = require('vue')
const app = new Vue({
    template: `<div>Hi Vue SSR!</div>`
})

const renderer = require('vue-server-renderer').createRenderer()

renderer.renderToString(app, (err, html) => {
    if(err) throw err

    console.log(html)
})

我们用node执行server.js 就会返回html字符串

node server.js

go语言vue服务端渲染 vue实现服务端渲染_html

(2) 第二步: 搭建本地服务器,借助express框架,渲染html

修改一下server.js

const Vue = require('vue')
const express = require('express')
const server = express()
const renderer = require('vue-server-renderer').createRenderer()

server.get('*', (req, res) => {
    const app = new Vue({
        data: {
            url: req.url
        },
        template: `<div>Hi Vue SSR! current url: {{url}}</div>`
    })

    renderer.renderToString(app, (err, html) => {
        if (err) {
            res.status(500).end('服务器错误: 500')
            return
        }
        res.end(
            `<!DOCTYPE html>
            <html lang="en">
            <head><title>vue ssr</title></head>
            <body>${html}</body>
            </html>`
        )
    })
})
server.listen(8080, () =>{
    console.log('服务器已开启: 127.0.0.1:8080')
})

然后执行我们的本地服务器 就可以看到我们的Vue实例渲染在页面上了。

node server.js

go语言vue服务端渲染 vue实现服务端渲染_go语言vue服务端渲染_02


按下F12查看一下html的编码

go语言vue服务端渲染 vue实现服务端渲染_html_03

现在,我们简单的把一个Vue实例通过SSR渲染在页面上啦

(3) 扩展: 借助<!--vue-ssr-outlet-->模板渲染html

首先创建后一个index.template.html文件,如何必须要在body插入一条注释<!--vue-ssr-outlet-->

<!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>Vue SSR template</title>
</head>
<body>
    <!--vue-ssr-outlet-->
</body>
</html>

修改我们的server.js文件,读取模板,把模板配置到vue-server-renderer

const Vue = require('vue')
const express = require('express')
const vueServerRender = require('vue-server-renderer')
const fs = require('fs')

// 1. 创建本地服务器
const server = express()

// 2. 读取VUE SSR的模板
const template = fs.readFileSync('./index.template.html', 'utf-8')

// 3. 把模板引入到renderer
const renderer = vueServerRender.createRenderer({
    template
})

server.get('*', (req, res) => {
    const app = new Vue({
        data: {
            url: req.url
        },
        // 这里的内容都会插入到<!--vue-ssr-outlet-->注释的下面
        template: `<div>Hi Vue SSR! current url: {{url}}</div>`
    })

    renderer.renderToString(app, (err, html) => {
        if (err) {
            res.status(500).end('服务器错误: 500')
            return
        }
        res.end(html)
    })
})

server.listen(8080, () =>{
    console.log('服务器已开启: 127.0.0.1:8080')
})

打开页面,查看html编码,已经把我们的内容插入到模板内容的下面

go语言vue服务端渲染 vue实现服务端渲染_go语言vue服务端渲染_04

(4)在模板上插值:context

我们在server.js文件创建一个context上下文变量,然后传入到renderer的第二个参数

const Vue = require('vue')
const express = require('express')
const vueServerRender = require('vue-server-renderer')
const fs = require('fs')

// 1. 创建本地服务器
const server = express()

// 2. 读取VUE SSR的模板
const template = fs.readFileSync('./index.template.html', 'utf-8')

// 3. 把模板引入到renderer
const renderer = vueServerRender.createRenderer({
    template
})

// 4. 定义一个上下文
const context = {
    title: 'Vue-SSR',
    metas: `
        <meta name="keyword" content="vue,ssr">
        <meta name="description" content="vue-ssr-demo">
    `
}

server.get('*', (req, res) => {
    const app = new Vue({
        data: {
            url: req.url
        },
        // 这里的内容都会插入到<!--vue-ssr-outlet-->注释的下面
        template: `<div>Hi Vue SSR! current url: {{url}}</div>`
    })
    // 传入vue实例,上下文context
    renderer.renderToString(app, context, (err, html) => {
        if (err) {
            res.status(500).end('服务器错误: 500')
            return
        }
        res.end(html)
    })
})

server.listen(8080, () =>{
    console.log('服务器已开启: 127.0.0.1:8080')
})

注意: index.template.html文件对于标签的插入,我们是要用三个大括号,不然插入的内容会被转译为字符串:

标签两个括号的情况下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{title}}</title>
    {{metas}}
</head>
<body>
    <!--vue-ssr-outlet-->
</body>
</html>

渲染问题

页面渲染的结果:

go语言vue服务端渲染 vue实现服务端渲染_html_05

我们要把标签的插入改为三个大括号就可以解决:

go语言vue服务端渲染 vue实现服务端渲染_go语言vue服务端渲染_06

go语言vue服务端渲染 vue实现服务端渲染_vue.js_07

现在我们已经学会了如何通过ExpressNodejs,还有vue-server-renderer来进行vue的服务端渲染啦。