前端prerender-spa-plugin預渲染
prerender-spa-plugin預渲染:構建階段生成匹配預渲染路徑的 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.PuppeteerRenderer
plugins: [ 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或者其他代理工具代理線上資料