如果你需要改善少数页面的seo,或者加快少数页面的打开时间。预渲染是个不错的选择。

预渲染相对于服务端 ssr 开发成本 更低,代码 侵入性 更低。

插件原理

npm run build 将代码打包成功以后,prerender-spa-plugin 插件会在指定目录开启一个服务,使用google开发的无头浏览器 puppeteer 模拟打开打包好的项目,爬取指定的预渲染页面,生成html文件。此时我们访问生成好的html页面就如同访问静态页面一样。

解决seo优化之预渲染prerender-spa-plugin

1,安装 prerender-spa-plugin

npm install --save prerender-spa-plugin

2,配置vue.config.js

// SEO 优化
const PrerenderSPAPlugin = require('prerender-spa-plugin');
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
const isProduction = process.env.NODE_ENV === 'production';
// 这里做二级目录部署
module.exports = {
    ...
    productionSourceMap: false,
    //资源拼接路径
    process.env.NODE_ENV == "production" ? "/web/": "./"
    // 打包后输出文件的目录
    outputDir: process.env.NODE_ENV == "production" ? "dist/web/":"dist",
    // outputDir的静态资源(js、css、img、fonts)目录
    assetsDir: "static", 
    const plugins = [];
    configureWebpack: config => {
        if (isProduction) {
             plugins.push(
                 new PrerenderSPAPlugin({
                      // 生成文件的路径,也可以与webpakc打包的一致。
                     // 下面这句话非常重要!!!
                    // 这个目录只能有一级,如果目录层次大于一级,在生成的时候不会有任何错误提示,在预渲染的时候只会卡着不动。
                   //staticDir: path.join(__dirname, process.env.VUE_APP_OUTPUT_DIR),如果直接用path 可能会报						错 不要问为什么我要特意备注一下 
                     // 读取vue-cli已打包文件的根目录 prerender-spa-plugin会在这里开启一个服务
                     staticDir: path.join(__dirname,'dist'),
                     // 经过prerender-spa-plugin处理的文件最终保存的地方
                     outputDir: path.join(__dirname, '/dist/web/'),
                     // 指定入口html
                     indexPath: path.join(__dirname, 'dist/web/index.html'), 
                     // 对应自己的路由文件,比如a有参数,就需要写成 /a/param1
                     routes: ['/','/index','/parcel','/warehouse','/artery','/scheme','/software','/port','/press','/hydt','/details','/map','/order','/issue','/job','/about','/company','/history','/cooperation','/contact','/404'],
                     // 这个很重要,如果没有配置这段,也不会进行预编译
                     renderer: new Renderer({
                      inject: {
                       foo: 'bar'
                      },
                      headless: false,
                      renderAfterDocumentEvent: 'render-event',
                      args: ['--no-sandbox', '--disable-setuid-sandbox']
                     })
                }),
             )
        }
    }
    ...
}

以上配置在 npm run build 后会打包到 dist/web/ 目录下,所有的静态资源会拼接上 /web/ 二级目录。prerender-spa-plugin 插件会读取 dist 目录,经过 prerender-spa-plugin 插件处理的文件也会覆盖放到 dist/web/ 目录下。

以上配置假定会部署到域名的根目录下。在部署时,直接将 dist 文件夹下的 vue 文件夹放到服务器的根目录下,通过 http://www.xxxxx.com/web/ 即可访问。

使用预渲染vue-router必须使用history模式(v4.x)

// vue-router 文件
import {
  createRouter,
  createWebHistory
} from 'vue-router'
const routes = [];
let base = process.env.NODE_ENV == "production" ?'/web/':'';
const router = createRouter({
  history: createWebHistory(base),
  routes,
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      return {
        top: 0
      }
    }
  }
})

App.vue 配置

<template>
	<div></div>
</template>
<script>
import { defineComponent,onMounted } from 'vue';
export default defineComponent({
setup() {
    onMounted(() => {
      // 在这里添加 预渲染事件
      document.dispatchEvent(new Event('render-event'))
    })
	return {}
}
})
</script>
<style lang='less' scoped>
</style>

main.js 配置

import {
    createApp
import {
    createApp
} from 'vue'
import App from './App.vue'

const app = createApp(App)
app.config.globalProperties.$SeoUpdate = (SeoTitle, SeoKeywords, SeoDescription) =>{
    let _headDom = '',_title = '',_meta = ''; 
    //获取head节点
    _headDom = document.getElementsByTagName('head')[0];
    //获取head节点下的title节点 
    _title = _headDom.getElementsByTagName("title")[0]; 
    //获取head节点下的meta节点,它一般是一个数组 
    _meta = _headDom.getElementsByTagName("meta"); 
    _title.innerText = SeoTitle;
    for (let index = 0; index < _meta.length; index++) { 
        switch (_meta[index].name) {
            case 'keywords':
                _meta[index].content = SeoKeywords;
                break;
            case 'description':
                _meta[index].content = SeoDescription;
                break;
            case 'searchtitle':
                _meta[index].content = SeoDescription;
                break;

            default:
                break;
        }
    }
    console.log(SeoTitle, SeoKeywords, SeoDescription)
}
app.mount('#app')

在需要修改的页面使用,举例home.vue

<template>
	<div></div>
</template>
<script>
import { defineComponent,getCurrentInstance,onMounted } from 'vue';
export default defineComponent({
    setup() {
        const { proxy } = getCurrentInstance();
        onMounted(() => {
          proxy.$SeoUpdate('seo标题','关键词1,关键词2,关键词3,关键词4,关键词5','网站描述--描述这个网站具体是围绕什么业务开展的')
        });
        return {}
    }
})
</script>
<style lang='less' scoped>
</style>

执行 npm run build 执行构建编译 预编译生成的页面 可以看到设置的seo标题、描述、关键字等,举例如下图:

构建生成文件的目录结构,可以看出页面已经提前渲染出来了

打赏作者
微信
支付宝

发表评论

返回顶部