prerender-spa-plugin的原理

prerender-spa-plugin的原理

prerender-spa-plugin 利用了 Puppeteer的爬取页面的功能。 Puppeteer 是一个 Chrome 官方出品的 headlessChromenode 库。它提供了一系列的 API, 可以在无 UI 的情况下调用 Chrome 的功能, 适用于爬虫、自动化处理等各种场景。它很强大,所以很简单就能将运行时的 HTML 打包到文件中。原理是在 Webpack 构建阶段的最后,在本地启动一个 Puppeteer 的服务,访问配置了预渲染的路由,然后将 Puppeteer 中渲染的页面输出到 HTML 文件中,并建立路由对应的目录。

项目配置

增加必要组件

安装vue-meta-infoprerender-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信息。