Vue 預(yù)渲染實(shí)現(xiàn)方案

前言

Ajax 技術(shù)的出現(xiàn)涡拘,讓我們的 Web 應(yīng)用能夠在不刷新的狀態(tài)下顯示不同頁面的內(nèi)容,這就是單頁應(yīng)用据德。在一個單頁應(yīng)用中鳄乏,往往只有一個 html 文件跷车,然后根據(jù)訪問的 url 來匹配對應(yīng)的路由腳本,動態(tài)地渲染頁面內(nèi)容橱野。單頁應(yīng)用在優(yōu)化了用戶體驗(yàn)的同時朽缴,也給我們帶來了許多問題,例如 SEO 不友好水援、首屏可見時間過長等不铆。服務(wù)端渲染(SSR)和預(yù)渲染(Prerender)技術(shù)正是為解決這些問題而生的。

服務(wù)端渲染與預(yù)渲染區(qū)別

  • 客戶端渲染:用戶訪問 url裹唆,請求 html 文件誓斥,前端根據(jù)路由動態(tài)渲染頁面內(nèi)容。關(guān)鍵鏈路較長许帐,有一定的白屏?xí)r間劳坑;

  • 服務(wù)端渲染:用戶訪問 url,服務(wù)端根據(jù)訪問路徑請求所需數(shù)據(jù)成畦,拼接成 html 字符串距芬,返回給前端。前端接收到 html 時已有部分內(nèi)容循帐;

  • 預(yù)渲染:構(gòu)建階段生成匹配預(yù)渲染路徑的 html 文件(注意:每個需要預(yù)渲染的路由都有一個對應(yīng)的 html)框仔。構(gòu)建出來的 html 文件已有部分內(nèi)容

下圖簡單展示了客戶端渲染、服務(wù)端渲染和預(yù)渲染的請求流程拄养。


image.png

服務(wù)端渲染與預(yù)渲染共同點(diǎn)

針對單頁應(yīng)用离斩,服務(wù)端渲染和預(yù)渲染共同解決的問題:

  • SEO:單頁應(yīng)用的網(wǎng)站內(nèi)容是根據(jù)當(dāng)前路徑動態(tài)渲染的,html 文件中往往沒有內(nèi)容瘪匿,網(wǎng)絡(luò)爬蟲不會等到頁面腳本執(zhí)行完再抓弱斯!;
  • 弱網(wǎng)環(huán)境:當(dāng)用戶在一個弱環(huán)境中訪問你的站點(diǎn)時棋弥,你會想要盡可能快的將內(nèi)容呈現(xiàn)給他們核偿。甚至是在 js 腳本被加載和解析前;
  • 低版本瀏覽器:用戶的瀏覽器可能不支持你使用的 js 特性顽染,預(yù)渲染或服務(wù)端渲染能夠讓用戶至少能夠看到首屏的內(nèi)容漾岳,而不是一個空白的網(wǎng)頁。
    預(yù)渲染能與服務(wù)端渲染一樣提高 SEO 優(yōu)化粉寞,但前者比后者需要更少的配置尼荆,實(shí)現(xiàn)成本低。弱網(wǎng)環(huán)境下仁锯,預(yù)渲染能更快地呈現(xiàn)頁面內(nèi)容耀找,減少頁面可見時間。

什么場景下不適合使用預(yù)渲染

  • 個性化內(nèi)容:對于路由是 /my-profile 的頁面來說,預(yù)渲染就失效了野芒。因?yàn)轫撁鎯?nèi)容依據(jù)看它的人而顯得不同蓄愁;

  • 經(jīng)常變化的內(nèi)容:如果你預(yù)渲染一個游戲排行榜,這個排行榜會隨著新的玩家記錄而更新狞悲,預(yù)渲染會讓你的頁面顯示不正確直到腳本加載完成并替換成新的數(shù)據(jù)撮抓。這是一個不好的用戶體驗(yàn);

  • 成千上萬的路由:不建議預(yù)渲染非常多的路由摇锋,因?yàn)檫@會嚴(yán)重拖慢你的構(gòu)建進(jìn)程丹拯。

Prerender SPA Plugin

prerender-spa-plugin 是一個 webpack 插件用于在單頁應(yīng)用中預(yù)渲染靜態(tài) html 內(nèi)容。因此荸恕,該插件限定了你的單頁應(yīng)用必須使用 webpack 構(gòu)建乖酬,且它是框架無關(guān)的,無論你是使用 React 或 Vue 甚至不使用框架融求,都能用來進(jìn)行預(yù)渲染咬像。

prerender-spa-plugin 原理

那么 prerender-spa-plugin 是如何做到將運(yùn)行時的 html 打包到文件中的呢?原理很簡單生宛,就是在 webpack 構(gòu)建階段的最后县昂,在本地啟動一個 phantomjs,訪問配置了預(yù)渲染的路由陷舅,再將 phantomjs 中渲染的頁面輸出到 html 文件中倒彰,并建立路由對應(yīng)的目錄。

image.png

查看 prerender-spa-plugin 源碼 prerender-spa-plugin/lib/phantom-page-render.js莱睁。

// 打開頁面
page.open(url, function (status) {
  ...
  // 沒有設(shè)置捕獲鉤子時待讳,在腳本執(zhí)行完捕獲
  if (
    !options.captureAfterDocumentEvent &&
    !options.captureAfterElementExists &&
    !options.captureAfterTime
  ) {
    // 拼接 html
    var html = page.evaluate(function () {
      var doctype = new window.XMLSerializer().serializeToString(document.doctype)
      var outerHTML = document.documentElement.outerHTML
      return doctype + outerHTML
    })
    returnResult(html) // 捕獲輸出
  }
  ...
})

項(xiàng)目實(shí)例

該實(shí)列基于Vue.js 2.0 + vue-router,使用 vue-cli3.0 生成

安裝
npm install prerender-spa-plugin --save
vue.config.js中增加
const PrerenderSPAPlugin = require('prerender-spa-plugin');
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
const path = require('path');
module.exports = {
    configureWebpack: config => {
        if (process.env.NODE_ENV !== 'production') return;
        return {
            plugins: [
                new PrerenderSPAPlugin({
                    // 生成文件的路徑缩赛,也可以與webpakc打包的一致耙箍。
                    // 下面這句話非常重要W贰K肘伞!
                    // 這個目錄只能有一級阅酪,如果目錄層次大于一級旨袒,在生成的時候不會有任何錯誤提示,在預(yù)渲染的時候只會卡著不動术辐。
                    staticDir: path.join(__dirname,'dist'),
                    // 對應(yīng)自己的路由文件砚尽,比如a有參數(shù),就需要寫成 /a/param1辉词。
                    routes: ['/', '/product','/about'],
                    // 這個很重要必孤,如果沒有配置這段,也不會進(jìn)行預(yù)編譯
                    renderer: new Renderer({
                        inject: {
                            foo: 'bar'
                        },
                        headless: false,
                        // 在 main.js 中 document.dispatchEvent(new Event('render-event')),兩者的事件名稱要對應(yīng)上敷搪。
                        renderAfterDocumentEvent: 'render-event'
                    })
                }),
            ],
        };
    }
}
在main.js中增加
new Vue({
  router,
  store,
  render: h => h(App),
  mounted () {
    document.dispatchEvent(new Event('render-event'))
  }
}).$mount('#app')
router.js 中設(shè)置mode: “history”

預(yù)渲染的單頁應(yīng)用路由需要使用 History 模式而不是 Hash 模式兴想。原因很簡單,Hash 不會帶到服務(wù)器赡勘,路由信息會丟失嫂便。vue-router 啟用 History 模式參考這里。

驗(yàn)證是否配置成功

運(yùn)行npm run build闸与,看一下生成的 dist 的目錄里是不是有每個路由名稱對應(yīng)的文件夾毙替。然后找個 目錄里 的 index.html 用IDE打開,看文件內(nèi)容里是否有該文件應(yīng)該有的內(nèi)容践樱。有的話厂画,就設(shè)置成功了

如果你想修改每個頁面的meta 信息,這里推薦使用 vue-meta(https://github.com/nuxt/vue-meta)

首先生成一個項(xiàng)目并安裝依賴拷邢,組件開發(fā)過程我們不關(guān)注木羹,具體可以查看示例源代碼。

原文鏈接:https://blog.csdn.net/huangjianfeng21/article/details/92421738

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末解孙,一起剝皮案震驚了整個濱河市坑填,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弛姜,老刑警劉巖脐瑰,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異廷臼,居然都是意外死亡苍在,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門荠商,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寂恬,“玉大人,你說我怎么就攤上這事莱没〕跞猓” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵饰躲,是天一觀的道長牙咏。 經(jīng)常有香客問我,道長嘹裂,這世上最難降的妖魔是什么妄壶? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮寄狼,結(jié)果婚禮上丁寄,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好伊磺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布宁舰。 她就那樣靜靜地躺著,像睡著了一般奢浑。 火紅的嫁衣襯著肌膚如雪蛮艰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天雀彼,我揣著相機(jī)與錄音壤蚜,去河邊找鬼。 笑死徊哑,一個胖子當(dāng)著我的面吹牛袜刷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播莺丑,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼著蟹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了梢莽?” 一聲冷哼從身側(cè)響起萧豆,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎昏名,沒想到半個月后涮雷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡轻局,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年洪鸭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仑扑。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡览爵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出镇饮,到底是詐尸還是另有隱情蜓竹,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布盒让,位于F島的核電站梅肤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏邑茄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一俊啼、第九天 我趴在偏房一處隱蔽的房頂上張望肺缕。 院中可真熱鬧,春花似錦、人聲如沸同木。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽彤路。三九已至秕硝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間洲尊,已是汗流浹背远豺。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坞嘀,地道東北人躯护。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像丽涩,于是被迫代替她去往敵國和親棺滞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容