声明:本文部分参考了 kang_k 大神的文章 vue做seo优化 https://blog.csdn.net/kang_k/article/details/100514042
最近要开始开发一个门户网站,此项目需要SEO优化,考虑了两种方案 SSR 服务端渲染和 预渲染;由于服务端渲染需要后端配合,而前期需求基本是静态html页面,人工成本和时间较高,所以选择了vue官方推荐的预渲染技术;
此项目主要使用vue-cli4进行搭建,(也可以使用vue-cli3,差别不大)而预渲染技术,核心就是使用插件 prerender-spa-plugin;
"dependencies": {
"amfe-flexible": "^2.2.1",
"axios": "0.21.1",
"core-js": "^3.6.5",
"jquery": "^3.5.1",
"lodash": "^4.15.17",
"normalize.css": "8.0.0",
"qs": "^6.5.1",
"vue": "^2.6.11",
"vue-meta-info": "^0.1.7",
"vue-router": "^3.2.0",
"vuex": "^3.4.0",
"vuex-persist": "^2.2.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/eslint-config-standard": "^5.1.2",
"babel-eslint": "^10.1.0",
"babel-plugin-dynamic-import-node": "^2.3.3",
"babel-plugin-import": "^1.13.3",
"eslint": "^6.7.2",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^6.2.2",
"postcss-pxtorem": "^4.0.1",
"prerender-spa-plugin": "^3.4.0", // 预渲染插件
"sass": "^1.26.5",
"sass-loader": "^8.0.2",
"script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "0.7.2",
"serve-static": "^1.13.2",
"vue-template-compiler": "^2.6.11"
},
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
// eslint-disable-next-line no-unused-vars
const webpack = require('webpack')
const path = require('path')
module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV !== 'production') return
return {
plugins: [
new PrerenderSPAPlugin({
// 生成文件的路径,也可以与webpakc打包的一致。
// 这个目录只能有一级,如果目录层次大于一级,在生成的时候不会有任何错误提示,在预渲染的时候只会卡着不动。
staticDir: path.join(__dirname, 'dist'),
// 对应自己的路由文件,比如a有参数,就需要写成 /a/param1。
routes: ['/', '/about'],
// 这个很重要,如果没有配置这段,也不会进行预编译
renderer: new Renderer({
inject: { //默认挂在window.__PRERENDER_INJECTED对象上,可以通过window.__PRERENDER_INJECTED.foo在预渲染页面取值
},
headless: false,
executablePath: "./chromium/chrome-win/chrome.exe", // windows系统下谷歌浏览器的可执行文件
// 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。
renderAfterDocumentEvent: 'render-event'//等到事件触发去渲染,此处我理解为是Puppeteer获取页面的时机
})
})
]
}
},
}
showMessage(){
if(window.__PRERENDER_INJECTED && window.__PRERENDER_INJECTED.foo =='bar') return;
this.message = '我是测试预加载拦截';
}
renderAfterDocumentEvent 这个则很关键,这个是监听 document.dispatchEvent 事件,决定什么时候开始预渲染。
new Vue({
router,
store,
render: h => h(App),
//添加到这里,这里的render-event和vue.config.js里面的renderAfterDocumentEvent配置名称一致
mounted () {
document.dispatchEvent(new Event('render-event'))
}
}).$mount('#app')
router.js里面把mode要为’history’,hash模式会打包的时候生成同样的页面,所以一定要history
再build的过程中会遇到很多坑,其中大概率会出现 Error: Chromium revision is not downloaded. Failed to download Chromium 这条报错,这是因为prerender-spa-plugin插件中会使用puppeteer,Puppeteer 是 Chrome 开发团队在 2017 年发布的一个 Node.js 包,用来模拟 Chrome 浏览器的运行。目的是项目在打包过程中通过浏览器预渲染完成,然后输出html和其他css, js资源,而由于Chromium一般很容易安装失败,就需要下载到本地,这是Chromium的淘宝镜像地址, https://npm.taobao.org/mirrors/chromium-browser-snapshots/
首先查看 /node_modules/puppeteer下packag.json中所依赖的Chromium版本号,然后到镜像地址下载对应的文件,注意根据自己的开发环境区分windows 和linux的版本,下载完成后,在项目根目录新建文件夹chromium,把下载好的 chrome-win.zip 解压,放到chromium文件夹内,下载完成。
之后再vue.config.js 进行配置 executablePath: “./chromium/chrome-win/chrome.exe”,指定可运行的浏览器程序,具体文件地址可根据自己的项目结构配置。
执行npm run build 后,把dist文件放到服务器上,或者本地启动一个服务器,打开网页可看到渲染结果。
然后就是为这些打包的静态页面分配title和meta标签,需要用到 vue-meta-info
安装
npm install vue-meta-info --save
main.js里面引入vue-meta-info
import MetaInfo from 'vue-meta-info'
Vue.use(MetaInfo)
这样在组件页面中就可以使用了
假设你要给about.vue添加title,meta标签
about.vue
<template>
...
</template>
<script>
export default {
metaInfo: {
title: '我是about头', // set a title
meta: [{ // set meta
name: 'keyWords',
content: '我是about关键字'
},
{
name: 'description',
content: '我是about描述'
}],
link: [{ // set link
rel: 'asstes',
href: '
}]
}
}
</script>
这样再结合prerender-spa-plugin,打包之后,在dist文件夹找到about文件夹下的index.html
打开你会发现就有title和meta的关键字和描述标签了
本地起服务或者发布到线上运行项目,在页面右键–查看源代码–就可以看到页面的title和meta标签了。
特别注意:
在项目中发现,build打包过程中会出现弹窗,
这个弹窗后请立即关闭弹窗,否则会打包失败,目前原因未知,会再以后过程解决。