基于prerender-spa-plugin的Vue.js预渲染实践

5,197 阅读2分钟

使用背景

最近公司基于vue-cli3.0搭建的老项目要做SEO优化,并且路由是hash模式;服务端渲染改造成本很大,看了一些文章后决定试一下预渲染,搭配vue-meta-info定制meta信息达到预期效果。

改造内容

1.路由模式

  • 路由模式切换为history模式,去除URL中的#
const router = new VueRouter({
  mode: 'history',
  routes: [...]
})
  • 路由懒加载,配合预渲染更好做到按需加载
{
    path: "/about",
    name: "About",
    component: () =>
      import(/* webpackChunkName: "about" */ "../views/About.vue")
}
js
├── about.95b9e039.js   <--打包输出后,路由懒加载访问对应js
├── app.7be39401.js
└── chunk-vendors.9cd40e36.js
  • 服务端配置覆盖无静态资源情况下返回的页面,避免直接访问或刷新404

预渲染页面访问路径指向其对应目录下的index.html,其他情况直接指向打包输出根目录下的主入口index.html。

/**
 * 创建本地服务
 */
http
  .createServer((req, res) => {
    const filePath = getFilePath(req);
    const indexFilePath = path.join(__dirname, "/dist/index.html");
    const exists = fs.existsSync(filePath);
    const data = fs.readFileSync(exists ? filePath : indexFilePath);
    writeHead(res, filePath);
    res.end(data);
  })
  .listen(port, hostname, () => {
    console.log(`Server running at http://${hostname}:${port}/`);
  });
dist
├── favicon.ico
├── home             
│   └── index.html  <-- http://localhost:8080/home 返回此预渲染页面
├── index.html      <-- http://localhost:8080/about 返回此候选资源
└── static

2.prerender-spa-plugin使用

  • 安装依赖
 npm install prerender-spa-plugin --save-dev
 or
 --registry https://registry.npm.taobao.org  使用镜像安装  
 or
 cnpm 
  • 添加 vue.config.js 配置
const path = require("path");
const PrerenderSpaPlugin = require("prerender-spa-plugin");
const isProduction = process.env.NODE_ENV === "production";

module.exports = {
  publicPath: "/",
  outputDir: "dist",
  assetsDir: "static",
  productionSourceMap: false,
  configureWebpack: config => {
    if (isProduction) {
      config.plugins.push(
        // 预渲染插件配置
        new PrerenderSpaPlugin({
          // 静态资源路径
          staticDir: path.join(__dirname, "dist"),
          // 预渲染路由
          routes: ["/home"]
        })
      );
    }
  }
};
  • build后生成dist目录,结构如下:
dist
├── favicon.ico
├── home     
│   └── index.html   <-- 预渲染页面   
├── index.html       <-- 主入口页面
└── static
    ├── css
    ├── img
    └── js

3.vue-meta-info 使用

  • 安装依赖
 npm install vue-meta-info --save-dev
  • 全局注册
import Vue from 'vue'
import MetaInfo from 'vue-meta-info'

Vue.use(MetaInfo)
  • 组件中静态用法,定制的meta信息在预渲染时也会写入页面
<template>
  ...
</template>

<script>
  export default {
    metaInfo: {
      // set a title
      title: 'Home',
      // set meta
      meta: [{                
        name: 'keyword',
        content: 'My Example Keyword'
      }],
      // set link
      link: [{                 
        rel: 'asstes',
        href: 'https://xxx.com/'
      }]
    }
  }
</script>

4.试试效果

完整示例地址

示例工程中内置了命令,打包输出dist目录后自动运行本地服务进行预览。

总结

  • 对比服务端渲染,简单易上手
  • 适用于页面数量少且偏静态的页面
  • 预渲染页面数据异步加载会有空白期,先加载预渲染部分;此时可以适当加入加载状态或骨架屏避免尴尬