简介
通常我们开发为了良好的用户体验和前后端分离,大多都是单页应用,通过接口获取后端数据在浏览器中输出组件,进行生成 DOM 和操作 DOM 来实现用户交互。然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将静态标记"混合"为客户端上完全交互的应用程序,这就是服务器端渲染。
对比单页面项目服务器端渲染有哪些好处
- 更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面,单页应用是根据路由,通过 ajax 异步的更新页面一个部门来实现应用效果,这样抓取工具是无法获取页面。
- 对于缓慢的网络或运行缓慢的设备。可提供获取网页速度,有良好的用户体验,由于单页应用在第一次加载时,需要将一个打包好(requirejs 或 webpack 打包)的 js 发送到浏览器后,才能启动应用。
使用vue SSR
这里我们使用 Node.js server 的服务器端单页面应用程序渲染。
创建项目引入依赖
环境:Node.js 版本 6+ 创建好文件夹后,安装vue以及vue服务端渲染需要的依赖:
npm init
npm install vue vue-server-renderer --save
安装Node.js Web 应用程序框架express:
npm install express --save
新建一个demo.js来引入依赖并启动我们的服务:
const Vue = require('vue');
const vsRenderer = require('vue-server-renderer')
const server = require('express')();
server.get('*', (req, res) => {
res.send('Hello World!')
})
server.listen(8080);
创建页面模板
新建一个index.html模板:
<html>
<head>
<!-- 使用双花括号(double-mustache)进行 HTML 转义插值(HTML-escaped interpolation) -->
<title>{{ title }}</title>
<!-- 使用三花括号(triple-mustache)进行 HTML 不转义插值(non-HTML-escaped interpolation) -->
{{{ metas }}}
</head>
<body>
<!--vue-ssr-outlet-->
</body>
</html>
注意 <!--vue-ssr-outlet-->
注释 -- 这里将是应用程序 HTML 标记注入的地方。
然后,我们可以读取和传输文件到 Vue renderer 中:
const renderer = require('vue-server-renderer').createRenderer({
template: require('fs').readFileSync('./index.html', 'utf-8')
})
renderer.renderToString(app, (err, html) => {
console.log(html) // html 将是注入应用程序内容的完整页面
})
整合
最后我们代码整合一下,完成简单的ssrdemo:
const Vue = require('vue');
const vsRenderer = require('vue-server-renderer')
const server = require('express')();
const template = require('fs').readFileSync('./index.html', 'utf-8');
const renderer = vsRenderer.createRenderer({
template,
});
const context = {
title: 'vue ssr',
metas: `
<meta name="keyword" content="vue,ssr">
<meta name="description" content="vue srr demo">
`,
};
server.get('*', (req, res) => {
const app = new Vue({
data: {
url: req.url
},
template: `<div>Hello SSR</div>`,
});
renderer
.renderToString(app, context, (err, html) => {
console.log(html);
console.log('err', err)
if (err) {
res.status(500).end('Internal Server Error')
return;
}
res.end(html);
});
})
server.listen(8080);