Vue项⽬中服务端渲染的⼏种⽅式
服务端渲染在很早的时候就有了,可以追溯到 ASP、JSP 的时代,就是在后端返回⼀个静态页⾯给浏览器,由浏览器直接显⽰。summit
但是在 React 以及 nodejs 普及之后,开始出现同构渲染,简单来说就是在服务端渲染前端组件然后返回给浏览器显⽰。
00 背景
同构渲染简称 SSR(Server-Side Render),也叫页⾯直出。具体的优势可以看这篇⽂章《⼿把⼿教你 ReactJS 和 VueJS 的服务端渲染》。SSR 是由 React 的虚拟 dom 可以直接在 nodejs 中渲染出 dom string, 就是类似于
<div> xxxx </div>
Vue.js 的服务端渲染的⽅式和 React 还有点不⼀样。
下⾯介绍下 Vue.js 整个直出的过程。
01 开始叔母
Vue SSR 官⽅⽂档《Vue.js 服务器端渲染指南》. 直接上例⼦
const Vue = require('vue')
const rver = require('express')()
四大发明英语
const renderer = require('vue-rver-renderer').createRenderer({
template: require('fs').readFileSync('./plate.html', 'utf-8')
})
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
<('*', (req, res) => {
const app = new Vue({
data: {
url: req.url
},
template: `
<div id="components-demo">
<button-counter></button-counter>
</div>
`
})
const context = {
title: 'hello',
meta: `
<meta ...>
<meta ...>
pet是什么`
}
res.status(500).end('Internal Server Error')
return
}
console.log(html)
})
rver.listen(8080)
同构渲染的关键就是 renderToString, ⽆论是 vue 还是 react 都是通过这个⽅法输出 dom string.
上⾯ console.log(html) 输出结果
日文翻译器<html>
<head>
<!-- 使⽤双花括号(double-mustache)进⾏ HTML 转义插值(HTML-escaped interpolation) -->
<title>hello</title>
<!-- 使⽤三花括号(triple-mustache)进⾏ HTML 不转义插值(non-HTML-escaped interpolation) -->
<meta ...>
<meta ...>
</head>
<body>
<div id="components-demo" data-rver-rendered="true"><button>You clicked me 0 times.</button></div> </body>
</html>
<html>
<head>
<!-- 使⽤双花括号(double-mustache)进⾏ HTML 转义插值(HTML-escaped interpolation) -->
<title>hello</title>
<!-- 使⽤三花括号(triple-mustache)进⾏ HTML 不转义插值(non-HTML-escaped interpolation) -->
<meta ...>
<meta ...>
</head>
<body>
<div id="components-demo" data-rver-rendered="true"><button>You clicked me 0 times.</button></div> </body>
</html>
但是真正⽤ vue 构建的复杂的应⽤应该是由很多 *.vue ⽂件组成的,但是 commonjs 规范根本识别不了 *.vue ⽂件,所以需要对 vue ⽂件做服务端构建。
02 复杂应⽤下服务端构建
由于前端也需要构建,所以抽出⼀个公⽤的 fig.js,
const path = require('path')
const utils = require('./utils')
const vueLoaderConfig = require('./f')
const webpack = require("webpack")
function resolve(dir) {
return path.join(__dirname, '..', dir)
}
context: solve(__dirname, '../'),
output: {适用于英文
path: solve(__dirname, '../dist'),
boraxfilename: '[name].[chunkhash:8].js',
进行中英文publicPath: './'
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),bdp
}
},
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
joyinclude: [resolve('src'), resolve('test'), resolve('/node_modules/element-ui/src'),
resolve('/node_modules/element-ui/packages'), resolve('node_modules/webpack-dev-rver/client')] },
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 1000,
name: utils.astsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',