週末想順便把已經作好靜態頁面的webApp項目作一下SEO優化,因爲不想寫蹩腳的SSR代碼,因此準備採用預渲染,原本想着網上有這麼多預渲染的文章,隨便找個來跟着作不就完了嘛,結果年輕的我付出了整個週末..... 這篇文章就記錄一下最後是怎麼配置的 T.Tcss
聲明:html
base
代替,請自行修改webpack
,其餘模板類推感興趣的同窗能夠加文末的微信羣,一塊兒討論吧~前端
咱們知道SPA有不少優勢,不過一個缺點就是對(不是Google的)愚蠢的搜索引擎的SEO不友好,爲了照顧這些引擎,目前主要有兩個方案:服務端渲染(Server Side Rendering)、預渲染(Prerending)。vue
若是你只須要改善少數頁面(例如 /
, /about
, /contact
等)的 SEO
,那麼你可能須要預渲染。無需使用 web 服務器實時動態編譯 HTML (服務端渲染, SSR),而是使用預渲染方式,在構建時(build time)簡單地生成針對特定路由的靜態 HTML 文件。它主要使用 prerender-spa-plugin 插件,其與SSR同樣均可以加快頁面的加載速度,而且侵入性更小,在已上線的項目稍加改動也能夠輕鬆引入預渲染機制,而SSR方案則須要將整個項目結構推翻;linux
訪問預渲染出來的頁面在訪問時與SSR
同樣快,而且它將服務端編譯HTML的時機提早到了構建時,所以也下降了服務端的壓力,若是你的服務器跟個人同樣買的 1M1G1核 的小水管服務器 ( 窮 ),那麼預渲染可能更適合你。不過SSR和預渲染的使用場景仍是有較明顯的區別的。預渲染的使用場景更可能是簡單的靜態頁面。服務端渲染適用於複雜、較大型、與服務端交互頻繁的功能型網站,好比電商網站。webpack
首先來看看相關技術棧:vue^2.5.二、vue-router^3.0.一、vue-cli^2.9.六、webpack^3.6.0、prerender-spa-plugin^3.3.0nginx
安裝跟其餘庫同樣git
# Yarn
$ yarn add prerender-spa-plugin -D
# or NPM
$ npm install prerender-spa-plugin --save-dev
複製代碼
首先看看文件結構,用的是vue-cli2的webpack模板生成的文件結構github
│ .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
web
// src/router/index.js
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:歡迎你們關注個人公衆號【前端下午茶】,一塊兒加油吧~
另外能夠加入「前端下午茶交流羣」微信羣,長按識別下面二維碼便可加我好友,備註加羣,我拉你入羣~