1.简介

  • 服务器端渲染:Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序。
  • 服务器渲染的 Vue.js 应用程序也可以被认为是"同构"或"通用",因为应用程序的大部分代码都可以在服务器和客户端上运行。
  • 服务器端渲染优势:
  1. 更好的SEO。Google 和 Bing 可以很好对同步 JavaScript 应用程序进行索引。但是若一开始你的页面是loading状态,之后通过网络请求获取数据,抓取工具不会等待你请求结束后抓取内容,这时你就需要SSR来解决此问题。
  2. 更快的内容到达时间,可以产生更好的用户体验。
  • 服务器端渲染不足:
  1. 浏览器特定代码,只能在某些生命周期钩子函数中才能使用,外部扩展库需要处理才能够运行。
  2. 涉及构建和部署的更多要求。服务器端渲染应用程序,需要处于Node.js server运行环境。
  3. 更多的服务器负载。比仅仅提供静态文件更加占用CPU资源,要准备好服务器负载,并进行合适的缓存。

2.渲染一个Vue实例

2.1 准备工作

  • 新建项目 SSR
  • yarn init -y 初始化package.json文件
  • yarn add vue vue-server-renderer 安装vue和vue-server-renderer
  • 新建app.js文件
app.js中

// 第1步:创建一个Vue实例
const Vue = require('vue');
const app = new Vue({
    template:`<div>hello SSR!</div>`
})

// 第2步:创建一个renderer
const renderer = require('vue-server-renderer').createRenderer();

// 第3步:将Vue实例渲染为HTML
renderer.renderToString(app,(err,html) =>{
    if(err) throw err;
    console.log(html) 
})
  • 执行node app.js 查看打印内容

2.2 与服务器集成

  • 在页面中引入Vue,使用vue语法
  • 引入express框架
  • 引入renderer
const Vue = require('vue');  // 引入Vue,可使用vue语法
const server = require('express')();	// 引入express框架
const renderer = require('vue-server-renderer').createRenderer(); // 引入renderer

server.get('*',(req,res)=>{
    // 创建vue实例,定义data,页面template内容
    const app = new Vue({
        data:{
            url:req.url
        },
       template:`<div>
            <h2>访问的URL是:</h2>
            <h4 style="color:red">{{url}}</h4>
        </div>` // 可以写任意html结构,每次修改时需要重启服务器
    })

    // renderer
    renderer.renderToString(app,(err,html)=>{
        if(err){
            res.status(500).end('Internal Server Error!')
            return 
        }
        res.end(`
            <!DOCTYPE html>
            <html lang="en">
                <head>
                    <title>Hello SSR</title>  	// title
                    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> // 编码
                </head>
                <body>${html}</body> // 页面内容
            </html>
        `)
    })
})
server.listen(8888)

2.3 使用页面模板

  • 定义一个html文件,定义页面中的内容
  • 单独在app.js中引入html文件,并使用它
  • node 文件.js 查看页面显示内容和终端打印内容
index.template.html

<!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>SSR渲染模板</title>
</head>
<body>
    <h3>ssr-outlet上面的内容</h3>
    <!--vue-ssr-outlet-->
    <h2>Hello SSR!</h2>
    <p>注意 <!--vue-ssr-outlet--> 注释 -- 这里将是应用程序 HTML 标记注入的地方。</p>
    <div style="color: aqua;">
        你学废了吗?
    </div>
</body>
</html>
app.js 

// 渲染单独模板文件中的内容
const Vue = require('vue')
const renderer = require('vue-server-renderer').createRenderer();
const server = require('express')();

server.get('*',(req,res)=>{
    const app = new Vue({
        template:require('fs').readFileSync('./index.template.html','utf-8'),
    })
    renderer.renderToString(app,(err,html)=>{
        if(err){
            res.status(500).end('Internal Server Error!')
            return
        }
        console.log(html) // 打印的HTML是index.template.html中的全部内容
        // 结果会将index.template.html文件body中定义的内容展示在页面中
        res.end(
            `
            <!DOCTYPE html>
            <html lang="en">
                <head>
                    <title>Hello SSR</title> 
                    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
                </head>
                <body>${html}</body>
            </html>
            `
        )
    })
})
server.listen(8888);

2.4 模板插值

  • index.template.html文件中定义变量,可以插值修改
  • app.js中当执行时,将想要插给html的值传送过去
  • 在执行node app.js时,终端会打印插值后的结果
index.template.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- 使用双花括号(double-mustache)进行 HTML 转义插值(HTML-escaped interpolation) -->
    <title>{{title}}</title>
    <!-- 使用三花括号(triple-mustache)进行 HTML 不转义插值(non-HTML-escaped interpolation) -->
    {{{ meta }}}
</head>
<body>
    <!--vue-ssr-outlet-->
</body>
</html>
app.js


const Vue = require('vue');
const server = require('express')();
// 引入模板
const template = require('fs').readFileSync('./index.template.html','utf-8');
const renderer = require('vue-server-renderer').createRenderer({
    template,
})

const context = {
    title:'自定义title,模板插值',
    meta:`
        <meta charset="UTF-8">
    `
}
server.get('*',(req,res)=>{
    const app = new Vue({
        data:{
            url:req.url
        },
        template:`<div>访问的URL是: {{url}}</div>`,
    });
    renderer.renderToString(app,context,(err,html)=>{
        console.log(html)
        if(err){
            res.status(500).end('Internal Server Error!')
            return
        }
        res.end(html)
    })
})
server.listen(9999)
  • 使用双花括号形式的插值变量,在模板输出html字符串时是会自动进行字符转义的,这样的目的是为了防止xss攻击等。但是也可以设置不进行转义,就须要用3个花括号的形式定义插值变量

总结用法,希望可以帮助到你,
我是Ably,你无须超越谁,只要超越昨天的自己就好~