prerender-vue
文章目录
场景
目前大部分接触到的页面都会使用SPA来实现。但是SPA会有个问题,就是对于SEO的支持不是很好。
对于vue项目来说,可以使用nuxt一把梭😹。
但对于简单的场景来说,其实也可以用预渲染的方式来只对首页和文档部分做静态渲染。
这样既满足了SEO的支持,也和原本vue的写法一样。
依赖
prerender-spa-plugin
预渲染依赖 prerender-spa-plugin
插件。
prerender-spa-plugin
是 webpack
的插件,所以用 webpack
打包的单页面(react
,vue
,angular
等)都能使用。
prerender-spa-plugin
原理就是使用浏览器内核预先加载页面渲染数据得到完整页面后生成完整的html
文件。
sitemap.js
百度爬虫非常喜欢Sitemap,Sitemap协议使你能够告知搜索引擎网站中可供抓取的网址,sitemap的生成就是让搜索引擎更好的去访问网站从而给网站的收录产生一个好的作用。
所以用sitemap
库来自动生成 sitemap.xml
文件对SEO有很大帮助。
实践
安装依赖
1 | yarn add prerender-spa-plugin sitemap -D |
将vue router mode属性改为history
mode必须为history,如果不改为history,在hash模式下,prerender-spa-plugin打包出来的静态html只有首页的html是完整的,其他页面还是用的首页骨架,然后动态生成生成html替换,就达不到seo的效果。
配置webpack文件
修改build/webpack.prod.conf.js 文件:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62const path = require('path')
const resolve = dir => path.join(__dirname, '..', dir);
// pre-render
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const routes = ['/'] // 确定需要预渲染的页面路由和生成sitemap的路由,这两个也可以分开
// sitemap url容器
const sitemap = require('sitemap');
const siteMapUrls = [];
const webpackConfig = merge(baseWebpackConfig, {
plugins: [
// pre render
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, '../dist'),
// Output directory
outputDir: path.join(__dirname, '../dist/rendered'),
routes,
postProcess (context) {
//content 参数
const {originalRoute, route, html} = context;
//将路由添加到全局sitemap容器
siteMapUrls.push(originalRoute);
//当当前路由为最后一个生成路由时
if (route === routes[routes.length - 1]) {
//去除重复的链接
let currentSiteMapUrls = Array.from(new Set(siteMapUrls));
// //过滤掉链接中的锚点后内容
currentSiteMapUrls = currentSiteMapUrls.map(url => {
const isMao = url.indexOf('#') > -1;
//生成sitemap所需数据,具体参数参详sitemap.js官网
return {url: isMao ? url.split('#')[0] : url, changefreq: 'weekly', priority: 1, lastmod: new Date().toLocaleDateString()}
});
//生成siteMap文件
const sm = sitemap.createSitemap({
//路由前缀地址,全地址自动不会添加hostname
hostname: 'https://matpool.com',
cacheTime: 600000, //600 sec (10 min) cache purge period
urls: currentSiteMapUrls
});
//将sitemap文件添加搭配打包文件夹dist中
fs.writeFileSync(resolve('dist/sitemap.xml'), sm.toString());
}
// 解决闪屏问题
context.html = html.replace('id="app"', 'id="app" data-server-rendered="true"');
//返回当前contet对象
return context
},
renderer: new Renderer({
inject: {
foo: 'bar'
},
headless: true,
renderAfterDocumentEvent: 'render-event',
//puppeteer参数,标签意思:完全信任在Chrome中打开的内容
args: ['--no-sandbox', '--disable-setuid-sandbox']
})
}),
]
})
上面webpack文件中 postProcess
是用来配合sitemap
库生成sitemap.xml
文件的。
PrerenderSPAPlugin 插件中其他代码是用来生成预渲染页面的。
修改main.js
1 | new Vue({ |
遇到的问题
依赖包不能下载
prerender-spa-plugin
依赖 google 的 puppeteer
库。所以install的时候需要翻墙,或者设置淘宝源。
Linux不能正常打包
本地打包没有问题,linux服务器打包可能会出现ERROR: Fail to lauunch chrome!
原因一:linux 环境缺少一些依赖
所以需要先在Linux上装好这些依赖。
因为我是用docker来构建部署的,这里提供下dockerfile:
1 | FROM ubuntu:18.04 |
闪屏
在预渲染构建完成之后,访问页面,可能会出现闪屏的现象。
解决方法:在 PrerenderSPAPlugin.postProcess
中加入下面这段代码(上面的例子中已经加了)1
context.html = html.replace('id="app"', 'id="app" data-server-rendered="true"');
其他页面刷新时不能正常访问
在预渲染页面之外的页面刷新时,可能会出现不能正常渲染的情况。
解决方法:配置 nginx
文件:1
2
3
4
5
6
7
8
9
10
11
12
13
14http {
server {
# pre-rendered routes
location = / {
try_files $uri /rendered/index.html;
}
# all other dynamic routes
location / {
index index.html;
try_files $uri $uri/ /index.html;
}
}
}
这里面的 /rendered/
文件夹要和上面webpack.prod.conf.js
中 PrerenderSPAPlugin.outputDir
保持一致