Vue.js项目使用prerender-spa-plugin和vue-meta-info实现SEO功能
prerender-spa-plugin的原理
prerender-spa-plugin 利用了 Puppeteer的爬取页面的功能。 Puppeteer 是一个 Chrome 官方出品的 headlessChromenode 库。它提供了一系列的 API, 可以在无 UI 的情况下调用 Chrome 的功能, 适用于爬虫、自动化处理等各种场景。它很强大,所以很简单就能将运行时的 HTML 打包到文件中。原理是在 Webpack 构建阶段的最后,在本地启动一个 Puppeteer 的服务,访问配置了预渲染的路由,然后将 Puppeteer 中渲染的页面输出到 HTML 文件中,并建立路由对应的目录。
项目配置
增加必要组件
安装vue-meta-info
和prerender-spa-plugin
npm install vue-meta-info --save
npm install prerender-spa-plugin --save
如果安装了淘宝cnpm镜像,可以使用cnpm命令安装
cnpm install vue-meta-info --save
cnpm install prerender-spa-plugin --save
修改配置文件
prerender-spa-plugin
仅支持history路由模式,需要修改路由配置文router/index.js
mode:'history',
history模式需要修改nginx配置用于解决刷新页面不存在的问题
location / {
try_files $uri $uri/ /index.html;
}
因为prerender-spa-plugin
需要预先渲染页面生成静态文件,所以部署在根目录和子目录的配置有所不同。
部署在根目录
修改 build/webpack.prod.conf.js
// 头部增加插件依赖
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
// plugins配置增加插件配置
new PrerenderSPAPlugin({
// 生成文件的路径,也可以与webpakc打包的一致。
staticDir: path.join(__dirname, '../dist'),
// 对应自己的路由文件,比如index有参数,就需要写成 /index/param1。
routes: ['/', '/index', '/fundindex', '/fundmore'],
// 这个很重要,如果没有配置这段,也不会进行预编译
renderer: new Renderer({
inject: {
foo: 'bar'
},
headless: false,
// 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。
renderAfterDocumentEvent: 'render-event'
})
})
参数说明:
staticDir:预渲染输出的页面地址
routes:需要预渲染的路由地址
inject:预渲染过程中都能获取到的值,可以通过window.__PRERENDER_INJECTED.foo获取
headless:是否显示渲染弹窗,需要调试可以打开
renderAfterDocumentEvent:监听 document.dispatchEvent 事件决定渲染时间
修改项目入口文件 main.js
new Vue({
el: '#app',
router,
render: h => h(App),
mounted () {
// You'll need this for renderAfterDocumentEvent.
document.dispatchEvent(new Event('render-event'))
}
});
render-event
需要与webpack.prod.conf.js
中的配置对应
部署在子目录
修改打包路径 config/index.js
build: {
// Template for index.html
// index: path.resolve(__dirname, '../dist/templates/index.html'),
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, "../dist/"),
assetsSubDirectory: 'lcsm/static', // 修改静态文件目录
assetsPublicPath: "/",
}
修改 build/webpack.prod.conf.js
build: {
// Template for index.html
// index: path.resolve(__dirname, '../dist/templates/index.html'),
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, "../dist/"),
assetsSubDirectory: 'lcsm/static', // 修改静态文件目录
assetsPublicPath: "/",
}
配置子目录需要将路由配置都设置为实际目录
修改build/utils.js
,注释下面内容中的publicPath配置
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
// publicPath: '../',
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
修改项目入口文件 main.js
new Vue({
el: '#app',
router,
render: h => h(App),
mounted () {
// You'll need this for renderAfterDocumentEvent.
document.dispatchEvent(new Event('render-event'))
}
});
render-event
需要与webpack.prod.conf.js
中的配置对应
vue-meta-info 配置
修改配置文件
修改项目入口文件 main.js
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'
}]
}
}
</script>
组件内动态使用 metaInfo
:这种方式可以动态生成META标签的内容,一般META标签的内容需要根据变量去变化的时候,可以选用这种方式。
<template>
...
</template>
<script>
export default {
name: 'async',
metaInfo () {
return {
title: this.pageName
}
},
data () {
return {
pageName: 'loading'
}
},
mounted () {
setTimeout(() => {
this.pageName = 'async'
}, 2000)
}
}
</script>
至此项目配置完成,项目打包后会在dist目录下生成配置路由的静态文件,实际访问会调用vue-meta-info配置的标题和meta信息。
最新评论