prerender-spa-plugin預渲染:構建階段生成匹配預渲染路徑的 html 文件(注意:每個需要預渲染的路由都有一個對應的
html)。構建出來的 html 文件已有部分內容。
prerender-spa-plugin使用
- 安裝prerender-spa-plugin
npm install prerender-spa-plugin --save
-
webpack.prod.config.js中引入
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRendererplugins: [ new PrerenderSPAPlugin({ staticDir: path.join(__dirname, '../dist'), // outputDir: path.join(__dirname, '../prerendered'), indexPath: path.join(__dirname, '../dist', 'index.html'), routes: ['/mobile/home.html', '/mobile/doctor_team.html', '/mobile/about.html'], renderer: new Renderer({ inject: { foo: 'bar' }, headless: false, renderAfterDocumentEvent: 'render-active' // renderAfterElementExists: '.container', // renderAfterTime: 5000 }) }) ]
staticDir:代碼打包目錄
indexPath:模板頁面
routes:要預渲染的頁面路由
inject:默認掛在window.__PRERENDER_INJECTED對象上,可以通過window.__PRERENDER_INJECTED.foo在預渲染頁面取值
headless:渲染時顯示瀏覽器窗口。對調試很有用。
renderAfterDocumentEvent:等到事件觸發去渲染,此處我理解爲是Puppeteer獲取頁面的時機
renderAfterDocumentEvent 這個則很關鍵,這個是監聽 document.dispatchEvent
事件,決定什麼時候開始預渲染。需要在鉤子函數中觸發事件,如
new Vue({
el: '#app',
router,
render: h => h(App),
mounted () {
// You'll need this for renderAfterDocumentEvent.
document.dispatchEvent(new Event('render-active'))
}
});
renderAfterElementExists:等到dom元素出現時去渲染
renderAfterTime:5000ms後去渲染
- webpack打包編譯
結合項目,執行打包編譯命令
npm run build:prod
在dist目錄下生成以下頁面,雖然生成了兩層目錄,但是還是映射到'/mobile/home.html', '/mobile/doctor_team.html', '/mobile/about.html'
查看打包以後的頁面,body內容已經渲染好了
啓動http-server訪問http://127.0.0.1:8080/mobile/about.html,效果跟正常訪問一致
原理
prerender-spa-plugin 利用了 Puppeteer 的爬取頁面的功能。 Puppeteer 是一個 Chrome官方出品的 headlessChromenode 庫。它提供了一系列的 API, 可以在無 UI 的情況下調用 Chrome 的功能, 適用於爬蟲、自動化處理等各種場景。它很強大,所以很簡單就能將運行時的 HTML 打包到文件中。原理是在 Webpack 構建階段的最後,在本地啓動一個 Puppeteer 的服務,訪問配置了預渲染的路由,然後將 Puppeteer 中渲染的頁面輸出到 HTML 文件中,並建立路由對應的目錄。
圖片描述(最多50字)
具體代碼可以結合render-puppeteer下的代碼來看
圖片描述(最多50字)
在render.js中,啓動本地服務,通過page.goto依次訪問
http://localhost:8000/mobile/about.html,
http://localhost:8000/mobile/home.html
http://localhost:8000/mobile/doctor_team.html
通過page.content()獲取html
總結
結合項目實踐了下這個插件,也有不少坑
1.在config/index.js中assetsPublicPath原先寫的是/dist,導致預渲染的頁面body沒有渲染出來,是空白頁面,改成/就能預渲染出來,但是這樣導致不需要預渲染的頁面資源路徑不對
2.該插件在webpack此版本下不支持路由懶加載,
"webpack": "^4.6.0",
網上提到npm i [email protected]可以解決,果然升級了webpack版本後支持路由懶加載
3.在需要請求動態數據的頁面中,預渲染只能保證靜態部分不更改,如果不想寫死,要做動態數據代理,webpack的devserver代理數據無效,需要用nginx或者其他代理工具代理線上數據