Skip to content

SSR初体验

渲染Vue应用

import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'
// 创建一个 Vue 实例
const app = createSSRApp({
template: `
<div>
<h1>Hello, Server-Side Rendering!</h1>
<p>{{ message }}</p>
<button @click="count++">{{ count }}</button>
</div>
`,
data: () => ({
count: 1,
message: 'This is a server-side rendered page',
}),
})
const html = await renderToString(app)
console.log(html)

之后 node server.js 就能看到生成的 html 字符串:

Terminal window
> node server.js
<div><h1>Hello, Server-Side Rendering!</h1><p>This is a server-side rendered page</p><button>1</button></div>

搭建服务器

安装 express

Terminal window
pnpm install express

然后修改 server.js,代码如下:

import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'
import express from 'express'
// 创建服务器实例
const server = express()
// 创建一个 Vue 实例
const app = createSSRApp({
template: `
<div>
<h1>Hello, Server-Side Rendering!</h1>
<p>{{ message }}</p>
<button @click="count++">{{ count }}</button>
</div>
`,
data: () => ({
count: 1,
message: 'This is a server-side rendered page',
}),
})
server.get('/', async (req, res) => {
try {
const html = await renderToString(app)
res.send(html)
} catch (err) {
res.status(500).send('Server Error')
}
})
server.listen(3000, () => {
console.log('服务器启动成功,监听3000端口...')
})

为了方便,我们安装 nodemon 并且在 pacakge.json 中增加如下的脚本:

"scripts": {
"start": "nodemon --watch server.js server.js"
},

之后就可以使用 pnpm start 来启动服务器,并且在 server.js 内容发生改变后自动重启服务器。

使用HTML模板

接下来继续,在浏览器中右键,点击 “View Page Source” 查看网页源码,可以看到目前拿到的就是渲染出来的那一段字符串,这显然是不太合适的。我们想要浏览器拿到的是一个完整的 HTML 文档,有 head、meta、body 这些元素。

此时我们可以指定一个 HTML 模板。在 demo 根目录下创建一个 index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ title }}</title>
{{ meta }}
</head>
<body>
<!-- 注意这里一定要保证挂载点和外层div在同一行,否则后面同构的时候会找不到挂载点 -->
<div id="app"><!--vue-ssr-outlet--></div>
</body>
</html>

然后修改 server.js

import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'
import express from 'express'
import fs from 'fs'
// 创建服务器实例
const server = express()
// 创建一个 Vue 实例
const app = createSSRApp({
template: `
<div>
<h1>Hello, Server-Side Rendering!</h1>
<p>{{ message }}</p>
<button @click="count++">{{ count }}</button>
</div>
`,
data: () => ({
count: 1,
message: 'This is a server-side rendered page',
}),
})
// 定义一个配置对象,表示页面相关信息,title,meta
const desc = {
title: '这是一个ssr页面',
meta: '<meta name="description" content="服务器端渲染"></meta>',
}
server.get('/', async (req, res) => {
try {
const content = await renderToString(app, desc)
// 读取模板文件
const template = fs.readFileSync('./index.html', 'utf-8')
// 插入渲染内容到模板中
const html = template
.replace('{{ title }}', desc.title)
.replace('{{ meta }}', desc.meta)
.replace('<!--vue-ssr-outlet-->', content)
res.send(html)
} catch (err) {
console.log(err, 'err')
res.status(500).send('Server Error')
}
})
server.listen(3000, () => {
console.log('服务器启动成功,监听3000端口...')
})

在上面的代码中,通过 node.js 的 fs 模块来读取 index.html 文件,读取到的内容是字符串的形式,之后使用字符串的 replace 方法进行内容替换,最后再返回给客户端。


-EOF-