預(yù)渲染升級(jí)成服務(wù)端渲染
回顧預(yù)渲染 是基于 prerender-spa-plugin
在項(xiàng)目構(gòu)建時(shí)堕花,通過(guò)無(wú)頭瀏覽器模擬瀏覽器請(qǐng)求文狱,將得到的數(shù)據(jù)插入給出的模板中,從而生成已經(jīng)包含數(shù)據(jù)的html(這里其實(shí)有個(gè)天坑缘挽,最初嘗試預(yù)渲染時(shí)為了方便瞄崇,使用webpack-dev-server的proxy選項(xiàng)做了一次代理請(qǐng)求三方接口,然后預(yù)渲染并沒(méi)有渲染出這些動(dòng)態(tài)的數(shù)據(jù)到踏。原因是因?yàn)轭A(yù)渲染的無(wú)頭瀏覽器并不會(huì)走dev-server的代理,必須在客戶(hù)端再配一層nginx代理尚猿,才能將請(qǐng)求轉(zhuǎn)發(fā)窝稿,從而拿到動(dòng)態(tài)數(shù)據(jù)插入模板)。
SSR升級(jí)相比預(yù)渲染得到了什么
- 更快的構(gòu)建速度凿掂,SSR是動(dòng)態(tài)插入數(shù)據(jù)伴榔,并不會(huì)在構(gòu)建時(shí)就去預(yù)加載數(shù)據(jù),而是輸入url后在服務(wù)端請(qǐng)求庄萎,拿到返回的數(shù)據(jù)插入模板后再返回給客戶(hù)端踪少。
- 嵌套路由下的個(gè)性化頁(yè)面加載速度,個(gè)性化頁(yè)面無(wú)法進(jìn)行預(yù)渲染糠涛,ssr卻可以解決援奢。
- 更好的SEO。
- 更快的首屏加載速度忍捡。( 請(qǐng)求業(yè)務(wù)數(shù)據(jù)集漾,和將數(shù)據(jù)轉(zhuǎn)為html片段都在服務(wù)端進(jìn)行了,瀏覽器負(fù)責(zé)加載資源砸脊,請(qǐng)求CDN資源具篇,css渲染。到達(dá)時(shí)間縮短凌埂。之后走的依舊是前端路由驱显,然后前端預(yù)取數(shù)據(jù),所以這里僅僅首屏 )。
官方流程圖
官方demo
升級(jí)要做哪些處理
一埃疫,使用SSR伏恐,后端掌握權(quán)應(yīng)在自己手里,具體如何實(shí)現(xiàn)熱更新熔恢,是后面的事脐湾。server.js做了什么。
服務(wù)端數(shù)據(jù)必須與客戶(hù)端數(shù)據(jù)保持一致叙淌,引入Vuex
- express生成一個(gè)服務(wù)器實(shí)例秤掌。
- 客戶(hù)端使用打包好的index.html,因?yàn)橹筮€是要走前端路由鹰霍,這個(gè)由
html-webpack-plugin
生成好的注入了前端打包好的腳本的html需要作為renderer的模板闻鉴。 - 服務(wù)端entry-server.js打包好的入口傳入createBundleRenderer做祝,這里產(chǎn)出的是首屏html的主體部分私植。
- 通過(guò)2,3
vue-server-renderer
會(huì)將它們拼合成一個(gè)整體针炉,再傳至前端督勺。
二渠羞,打包
打包分為客戶(hù)端文件的打包和服務(wù)端文件的打包。將公用的部分分離到webpack.base.config.js
智哀。合并可以通過(guò)webpack-merge或者簡(jiǎn)單地通過(guò)Object.assign組合兩種config次询。
- 客戶(hù)端打包文件與正常SPA的打包文件沒(méi)有什么區(qū)別,入口為entry-client.js瓷叫。
- 服務(wù)端打包文件注意指定執(zhí)行環(huán)境為node屯吊,打包使用commonjs規(guī)范,因?yàn)橹笠诜?wù)端跑的呀摹菠,入口為entry-server.js盒卸。
-
webpack.base.config
也沒(méi)什么,默認(rèn)entry為entry-client.js次氨。webpack4以上記得指定打包模式蔽介。
三,入口entry-server.js&&entry-client.js
- 服務(wù)端入口通過(guò)app.vue導(dǎo)出的createApp生成一個(gè)新的實(shí)例煮寡。
- 傳入執(zhí)行上下文中的url屉佳,以此匹配對(duì)應(yīng)的所有組件,循環(huán)執(zhí)行所有匹配到組件中的asyncData()即所需獲取的異步數(shù)據(jù)洲押。獲取的數(shù)據(jù)存儲(chǔ)在store.state中武花。
- 執(zhí)行完畢后,將store.state注入context(之后客戶(hù)端入口可以通過(guò)window.INITIAL_STATE)獲取到這個(gè)已經(jīng)全部獲取過(guò)的store.state杈帐,以此保持服務(wù)端與客戶(hù)端數(shù)據(jù)的一致性体箕。此處若出錯(cuò)會(huì)導(dǎo)致混合失敗专钉,服務(wù)端數(shù)據(jù)被覆蓋。瀏覽器用客戶(hù)端的數(shù)據(jù)重新渲染
- 客戶(hù)端入口通過(guò)app.vue導(dǎo)出的createApp生成一個(gè)新的實(shí)例累铅。
- 將window.INITIAL_STATE注入store跃须。
- 之后走前端路由,asyncData()中預(yù)取的操作在服務(wù)端已不再執(zhí)行娃兽,所以此時(shí)前端預(yù)取菇民。通過(guò)
router.beforeResolve((to, from, next)=>{})
匹配路由并預(yù)取數(shù)據(jù)。(注意投储,在同一嵌套路由下的組件的數(shù)據(jù)不要再重新獲取了第练,diff實(shí)現(xiàn))。 - 預(yù)取完畢后玛荞,將該實(shí)例掛載到根組件娇掏。
四,前端入口文件src/index.js
從以上也可以看出勋眯,index.js必須作為一個(gè)工廠函數(shù)婴梧,導(dǎo)出一個(gè)生成vue實(shí)例的函數(shù),并且包含store客蹋,router這些在入口中使用到的實(shí)例塞蹭。
五,熱更新做了什么讶坯?
setup-dev-server.js導(dǎo)出一個(gè)接收express實(shí)例和處理index.html和server-bundle.js的函數(shù)番电。
- 生產(chǎn)模式下,依賴(lài)
webpack-dev-middleware
執(zhí)行代碼監(jiān)聽(tīng)并熱更新打包闽巩,依賴(lài)webpack-hot-middleware
執(zhí)行頁(yè)面熱更新钧舌。 - 導(dǎo)出內(nèi)存中的打包好的index.html和server-bundle.js担汤。在server.js入口涎跨,通過(guò)vue-server-renderer整合模板和服務(wù)端入口。
官方文檔崭歧,很多地方值得深究和細(xì)細(xì)推究隅很,寫(xiě)了個(gè)小demo便于學(xué)習(xí)吧。
如果你依賴(lài)由組件生命周期鉤子函數(shù)填充的上下文數(shù)據(jù)率碾,則不建議使用流式傳輸模式叔营。??????