vue預渲染之prerender-spa-plugin外掛應用

mguy_1發表於2018-12-13

背景

前幾天應需求做了一個網頁測速小工具,經過考慮,進行了一些選型,由於在公司一直用react搬磚,所以這次決定提高全方面能力,接觸並使用vue構建一個小型專案,vue用gizp壓縮後僅有約33KB,加上axios和prerender-spa-plugin以及業務程式碼,壓縮後僅不到50KB,使用者體驗比較良好。

由於使用vue次數不多,所以各種查閱資料,但是感覺過程中非常不順暢,從我的感受看,網上vue平均提供的資料遠不如react提供的資料,踩過一些坑,特別是prerender-spa-plugin外掛遇到了很多網上沒有提及的問題,於是把自己的收穫分享出來,給vue貢獻一份力量。

源起

vue預渲染之prerender-spa-plugin外掛應用
先讀了vue官方的指南,說的很清晰,如果圖省事,而且是小型展示專案的話,用預渲染再好不過,可以解決SEO和使用者載入體驗兩大痛點,聽上去很棒,很符合我現在的需求,於是就開始動手吧!


增加一處說明 : 預渲染是編譯時提前渲染一次,伺服器端渲染ssr是使用者每次請求伺服器,伺服器把相應的內容填進去(這兩者本質的不同,特此說明 !)

安裝

安裝這個外掛是第一個坑點,由於這個小專案是獨立的,所以不需要考慮npm包的版本,直接上最新的vuecli3.0跑整個環境,但是說實話,vuecli3這個腳手架給我的體驗很糟糕,原有的webpack配置被隱藏了,換成了vue.config.js,但是網上資料不多,配置多花了些時間 安裝prerender-spa-plugin時用了nrm切到cnpm,但是總是卡在安裝puppeteer這個地方,prerender-spa-plugin外掛是需要依賴puppeteer的,這個外掛會下載最新版的chromium---谷歌出品的無頭(headless)瀏覽器核心(大約200M+),所以如果不能科學上網,下載的時候就報錯了。我是用的lantern等了很長一段時間,才下載完,版本是72,所以說,經常翻牆很重要啊?

原理

puppeteer是谷歌出品的一個外掛,可以完成很多的操作,廣泛使用在爬蟲、測試自動化等瀏覽器自動化方向的應用,而prerender-spa-plugin這個外掛正是依賴puppeteer操作chromium這個真正的瀏覽器核心對SPA跑了一遍,生成一個靜態的HTML,裡面是已經填好的dom節點和資料,就是這麼簡單粗暴,為了給使用者直接返回有內容的xhtml文件,提前在一個瀏覽器裡跑了一遍,生成了跑過js和css之後index.html(跟路由)和其他文件。這樣的話有兩個缺陷,第一個:無法展示使用者自身的內容,第二個:不適合動態路由多的大型專案。理解了原理,就可以放心使用了?

配置

如果開始使用,第一個要注意的點是要把引入的vue-router模式設定為history(平時我也是推薦用history模式,hash有#很醜,只是history多配置一下回到根目錄),不過如果本身就是一個根路徑,沒有下級路由,那麼不引入vue-router也是會給編譯的。。。

vue預渲染之prerender-spa-plugin外掛應用
在vuecli3.0中,所有的原webpack配置都被放到vue.config.js裡面。 如果時間富裕,建議從頭讀一下github的官方MDvue.config.js裡面先引入

const PrerenderSPAPlugin = require('prerender-spa-plugin');
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
複製程式碼

然後module.exports

configureWebpack: {
        plugins: [
            new PrerenderSPAPlugin({
                staticDir: path.join(__dirname,'dist'),
                routes: ['/'],
                renderer: new Renderer({
                    inject: {
                        foo: 'bar'
                    },
                    headless: false,
                    renderAfterDocumentEvent: 'render-event',
                    //renderAfterTime: 5000,
                    //renderAfterElementExists: 'my-app-element'
                }),
            }),
            ..............
複製程式碼
  • staticDir裡面的dist是輸出資料夾名字,不用多說了
  • routes配置的是你想實現預渲染的路由,這裡我只有根路由需要預渲染,還有其他的路由可以在陣列中繼續新增
  • renderer預渲染提供了三種時機實現,renderAfterDocumentEvent、renderAfterTime、renderAfterElementExists 常用的是renderAfterDocumentEvent和renderAfterTime,意思很簡單,就是一個是在某個事件之後開始預渲染,另一個是在載入後幾秒之後開始預渲染, 如果用renderAfterDocumentEvent要配合在vue生命週期中實現
mounted: function(){
            document.dispatchEvent(new Event('render-event'));
        },
複製程式碼

這樣配置過後,每次打包build,外掛就會自動呼叫chromium核心把路由中的html裡面填上內容,想觀察區別可以通過chrome的preview檢視 沒有經過預渲染(類似效果,百度做了很多處理):

vue預渲染之prerender-spa-plugin外掛應用
經過預渲染之後

vue預渲染之prerender-spa-plugin外掛應用

這樣就大功告成了,水平所限,寫的不夠深刻,感謝大家閱讀!

相關文章