周末想顺便把已经作好静态页面的webApp项目作一下SEO优化,因为不想写蹩脚的SSR代码,因此准备采用预渲染,原本想着网上有这么多预渲染的文章,随便找个来跟着作不就完了嘛,结果年轻的我付出了整个周末..... 这篇文章就记录一下最后是怎么配置的 T.Tcss
声明:html
base
代替,请自行修改webpack
,其余模板类推咱们知道SPA有不少优势,不过一个缺点就是对(不是Google的)愚蠢的搜索引擎的SEO不友好,为了照顾这些引擎,目前主要有两个方案:服务端渲染(Server Side Rendering)、预渲染(Prerending)。前端
若是你只须要改善少数页面(例如 /
, /about
, /contact
等)的 SEO
,那么你可能须要预渲染。无需使用 web 服务器实时动态编译 HTML (服务端渲染, SSR),而是使用预渲染方式,在构建时(build time)简单地生成针对特定路由的静态 HTML 文件。它主要使用 prerender-spa-plugin 插件,其与SSR同样均可以加快页面的加载速度,而且侵入性更小,在已上线的项目稍加改动也能够轻松引入预渲染机制,而SSR方案则须要将整个项目结构推翻;vue
访问预渲染出来的页面在访问时与SSR
同样快,而且它将服务端编译HTML的时机提早到了构建时,所以也下降了服务端的压力,若是你的服务器跟个人同样买的 1M1G1核 的小水管服务器 ( 穷 ),那么预渲染可能更适合你。不过SSR和预渲染的使用场景仍是有较明显的区别的。预渲染的使用场景更可能是简单的静态页面。服务端渲染适用于复杂、较大型、与服务端交互频繁的功能型网站,好比电商网站。linux
首先来看看相关技术栈:vue^2.5.二、vue-router^3.0.一、vue-cli^2.9.六、webpack^3.6.0、prerender-spa-plugin^3.3.0webpack
安装跟其余库同样nginx
# Yarn $ yarn add prerender-spa-plugin -D # or NPM $ npm install prerender-spa-plugin --save-dev
首先看看文件结构,用的是vue-cli2的webpack模板生成的文件结构git
│ .babelrc │ index.html │ package.json │ README.md ├─build │ build.js │ check-versions.js │ utils.js │ vue-loader.conf.js │ webpack.base.conf.js │ webpack.dev.conf.js │ webpack.prod.conf.js ├─config │ dev.env.js │ index.js │ prod.env.js ├─src │ │ App.vue │ │ main.js │ │ │ ├─assets │ ├─components │ ├─router │ │ index.js │ ├─styles │ ├─utils │ └─views │ BigData.vue │ CompanyHonor.vue
而后是router/index.js的配置,预渲染要求是histroy模式,有的文章说不须要history模式,这是错的,不然生成的页面都是同一个html。另外注意加上base
不然若是你但愿跳转到二级页面的localhost/base/home
时候,在页面中点击<router-link to="/home">home</router-link>
的时候会跳转localhost/home
github
// src/router/index.jsweb
import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) export default new Router({ mode: 'history', base: '/base/', routes: [...] })
而后是config,这里注意assetsPublicPath
不是./
,
// config/index.js
const path = require("path") module.exports = { build: { index: path.resolve(__dirname, "../base/index.html"), assetsRoot: path.resolve(__dirname, ".."), assetsSubDirectory: "base/static", assetsPublicPath: "/", } }
而后是插件的配置,是放在prod
中的,由于只有build的时候会用
// build/webpack.prod.conf.js
const path = require('path') const config = require('../config') const PrerenderSPAPlugin = require('prerender-spa-plugin') const Renderer = PrerenderSPAPlugin.PuppeteerRenderer const webpackConfig = merge(baseWebpackConfig, { new PrerenderSPAPlugin({ staticDir: config.build.assetsRoot, outputDir: path.join(config.build.assetsRoot, 'base'), indexPath: config.build.index, // 对应路由文件的path routes: [ '/', '/BigData', '/CompanyHonor' ], renderer: new Renderer({ headless: false, // 无桌面系统去掉 renderAfterDocumentEvent: 'render-event' }) }) })
注意了,若是你的项目是部署在linux/centOS之类没有桌面的系统,须要把headless: false
去掉,若是centOS报没有找到lib的错,请参考 issue-200 的解决办法。
另外注意上面一个renderAfterDocumentEvent: 'render-event'
了么,这个意思是在render-event
事件触发以后执行prerender,这个事件咱们在main.js中mounted钩子触发
// src/main.js
import Vue from 'vue' import App from './App' new Vue({ el: '#app', render: h => h(App), mounted() { document.dispatchEvent(new Event('render-event')) } })
还有个配置要注意下在 build/utils.js 中的 ExtractTextPlugin.extract
的 publicPath
,不然一些vue中引用的资源会找不到
// build/utils.js
ExtractTextPlugin.extract({ use: loaders, fallback: 'vue-style-loader', // publicPath: '../../' })
这时候执行npm run build
就能够生成刚刚配置在PrerenderSPAPlugin
插件中routes中的页面html了,这过程当中会一闪而过的短暂打开chromium浏览器,不用管。
最后生成的目录树:
│ index.html ├─BigData │ index.html ├─CompanyHonor │ index.html └─static ├─css ├─fonts ├─img └─js
最后若是但愿进一步优化生成出来页面的SEO,能够配合 vue-meta-info 这个网上有不少文章,就不赘述了
顺便贴一下nginx配置
server { listen 80; server_name localhost; root /nginx-1.14.0/html; error_page 500 502 503 504 /50x.html; location ~ ^/base/ { try_files $uri $uri/ /base/index.html; } location = /50x.html { root html; } }
网上的帖子大多深浅不一,甚至有些先后矛盾,在下的文章都是学习过程当中的总结,若是发现错误,欢迎留言指出~
参考:
PS:欢迎你们关注个人公众号【前端下午茶】,一块儿加油吧~
另外能够加入「前端下午茶交流群」微信群,长按识别下面二维码便可加我好友,备注加群,我拉你入群~