什么是预渲染
用户请求前的服务器渲染即为「预渲染」。
用户请求后的服务器渲染即为「服务端渲染」。
最近,SSR(Server-Side-Rendering)风靡JavaScript前端世界。事实上,你现在可以在服务器上呈现你的站点和应用程序,然后再将它们发送给你的客户端,这绝对是一个革命性的想法(而且完全不是每个人都在做什么,在JS客户端应用程序开始流行之前…)
然而,对于PHP、ASP、JSP(以及类似的)站点,同样的批评也适用于今天的服务器端呈现。它很慢,很容易中断,而且很难正确实现。
问题是,不管大家怎么说,你可能不需要SSR。通过使用预渲染,几乎可以获得它的所有优点(没有缺点)。预渲染基本上是启动一个无头浏览器,加载应用程序的路由,并将结果保存到一个静态HTML文件中。然后,您可以使用以前使用的任何静态文件服务解决方案来服务它。它只适用于HTML5导航等。无需更改代码或添加服务器端渲染解决方案。
cnpm i prerender-spa-plugin
const PrerenderSPAPlugin = require('prerender-spa-plugin')
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, '../dist'),
routes: ['/intermediate-registration'],
renderer: new PrerenderSPAPlugin.PuppeteerRenderer({//这样写renderAfterTime生效了
renderAfterTime: 5000
})
})
main.js:
mounted () {
document.dispatchEvent(new Event('render-event'))
},
1. 出现 webpackJsonp is not defined 是因为 manifest.js
加载在vendor文件后面了,下面我们调整manifest.js文件在头部加载
这里使用 html-webpack-plugin 的事件:html-webpack-plugin-alter-asset-tags ,修改manifest.js到头部加载
cnpm i html-webpack-plugin-alter-asset-tags
在webpack.prod.conf.js同级目录中,新建一个my-plugin.js文件,内容如下:
function MyPlugin(options) {
this.options = options;
}
MyPlugin.prototype.apply = function(compiler) {
compiler.plugin('compilation', function(compilation) {
/*
出现 webpackJsonp is not defined 是因为 manifest.js 加载在vendor文件后面了,下面我们调整manifest.js文件在头部加载
这里使用插件:html-webpack-plugin-alter-asset-tags
来修改manifest.js到顶部加载
*/
compilation.plugin('html-webpack-plugin-alter-asset-tags', function(htmlPluginData, callback) {
console.log(33333333333)
console.log(htmlPluginData.head)
console.log(htmlPluginData.body)
//**********************修改manifest开始*********
//因为manifest存在于htmlPluginData.body里
//先获取manifest.js
let manifest = '';
if (htmlPluginData.body && htmlPluginData.body.length) {
let index = 0;
let manifestindex = 0;
htmlPluginData.body.forEach(item => {
if (item.attributes) {
let src = item.attributes.src;
if(src.indexOf('manifest') !== -1){
manifest = item
manifestindex = index;
}
}
index++;
});
if(manifest){
htmlPluginData.body.splice(manifestindex,1)
}
}
//修改头部数据
//把每个 href 带有 css/ 字符串的标签加上 id
if (htmlPluginData.head && htmlPluginData.head.length) {
htmlPluginData.head.forEach(item => {
if (item.attributes) {
let href = item.attributes.href;
item.attributes.id = href.substring(href.indexOf('css/') + 4, href.indexOf('.'));
}
});
}
//把 manifest.js 插入到头部中去
htmlPluginData.head.unshift(manifest)
console.log(htmlPluginData.head)
console.log(htmlPluginData.body)
//**********************修改manifest结束*********
callback(null, htmlPluginData);
});
});
};
module.exports = MyPlugin;
修改webpack.prod.conf.js,加载 my-plugin.js,修改内容如下:
const MyPlugin = require('./my-plugin.js')
plugins: [
// 预渲染报错处理
new MyPlugin({options: ''}),
有个问题就是,intermediate-registration页面会报js和css路径找不到,所以我自己手动复制static文件到intermediate-registration文件夹下面(有朋友知道怎么解决的,可以留言一起探讨预渲染的问题)
多出来的html文件
发现打包出来的html的TDK描述的内容(元信息meta动态加进)
设置元信息代码:
方法一,自己写js
方法二:
可以引用vue-meta-info插件,(设置vue 单页面meta info信息,如果需要单页面SEO,可以和 prerender-spa-plugin形成更优的配合)
npm install vue-meta-info --save
import Vue from 'vue'
import MetaInfo from 'vue-meta-info'
Vue.use(MetaInfo)
组件内静态使用 metaInfo
<template>
...
</template>
<script>
export default {
metaInfo: {
title: 'My Example App', // set a title
meta: [{ // set meta
name: 'keyWords',
content: 'My Example App'
}]
link: [{ // set link
rel: 'asstes',
href: 'https://assets-cdn.github.com/'
}]
}
}
</script>
如果你的 title 或者 meta 是异步加载的,那么你可能需要这样使用
<template>
...
</template>
<script>
export default {
name: 'async',
metaInfo () {
return {
title: this.pageName
}
},
data () {
return {
pageName: 'loading'
}
},
mounted () {
setTimeout(() => {
this.pageName = 'async'
}, 2000)
}
}
</script>