日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > vue >内容正文

vue

基于Vue-SSR优化方案归纳总结

發(fā)布時(shí)間:2024/2/28 vue 63 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于Vue-SSR优化方案归纳总结 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
Vue-SSR相信大家都不陌生,與傳統(tǒng) SPA 相比,服務(wù)器端渲染 (SSR) 能夠具備更好的SEO,方便搜索引擎爬蟲抓取工具可以直接查看完全渲染的頁(yè)面,除此之外,SSR能夠在更短的時(shí)間內(nèi)渲染出頁(yè)面內(nèi)容,通過在服務(wù)端填充數(shù)據(jù)吐出到客戶端的方式,讓用戶有更好的用戶體驗(yàn)。前言基于VueSSR的頁(yè)面優(yōu)化常有,而針對(duì)VueSSR的再優(yōu)化不常有。前段時(shí)間有幸作為宇宙無(wú)敵上級(jí)特派看門員參加了前端tweb大會(huì),聽取了騰訊視頻Web高級(jí)工程師lucien(段隆賢) 分享了針對(duì)SSR場(chǎng)景下的一些優(yōu)化,由于筆者之前也有在項(xiàng)目中實(shí)現(xiàn)SSR渲染,所以也針對(duì)Vue-SSR的優(yōu)化進(jìn)行了實(shí)踐和歸納總結(jié),并且在前人的基礎(chǔ)上進(jìn)行了新的優(yōu)化嘗試,當(dāng)然,不同的項(xiàng)目不同的場(chǎng)景下,優(yōu)化效果、優(yōu)化方案可能不盡相同,需要讀者們自行選取~(本文將討論常見的SSR優(yōu)化方案以及筆者個(gè)人的優(yōu)化嘗試)
CSR與SSR的區(qū)別首先,還是要不厭其煩地過一遍CSR和SSR的區(qū)別,在理清整個(gè)流程后,才能發(fā)現(xiàn)性能瓶頸以及關(guān)鍵耗時(shí)在哪里。
CSR一般由靜態(tài)資源服務(wù)器(CDN)等直接返回HTML資源,之后瀏覽器解析HTML加載CSS、JS資源(CSS加載結(jié)束后頁(yè)面會(huì)盡快進(jìn)行首屏渲染FP),JS依賴加載結(jié)束后,Vue實(shí)例初始化,拉取頁(yè)面數(shù)據(jù),頁(yè)面渲染(FMP)。
SSR由nodejs服務(wù)器來(lái)直出頁(yè)面,請(qǐng)求到達(dá)后端后,后端拉取cgi接口數(shù)據(jù),根據(jù)直出bundle生成render對(duì)象,render對(duì)象將執(zhí)行客戶端代碼構(gòu)建VDOM,生成HTML string,填充進(jìn)模板HTML,返回HTML資源,瀏覽器解析后加載CSS、JS資源,(在CSS加載結(jié)束后觸發(fā)FP和FMP),Vue實(shí)例初始化,接管后端直出的HTML,頁(yè)面可響應(yīng)。

(以下流程圖引自:https://www.jianshu.com/p/10b6074d772c)

時(shí)序圖(注:FP即First paint,首屏渲染,可能是沒有數(shù)據(jù)的狀態(tài)。FMP即First meaningful paint,處于已經(jīng)渲染數(shù)據(jù)的狀態(tài)。可交互:頁(yè)面數(shù)據(jù)填充結(jié)束且可響應(yīng)。)

SSR存在的缺陷:

1、對(duì)服務(wù)器提出更高的要求,生成虛擬DOM如果相對(duì)較長(zhǎng)的運(yùn)行和計(jì)算耗時(shí);2、由于cgi拉取和vdom直出后才吐出HTML頁(yè)面,FMP雖然提前了,但是FP相對(duì)延遲了;3、相比CSR,SSR渲染后,由于仍然需要進(jìn)行依賴、vue初始化,頁(yè)面可交互時(shí)間并沒有較大改善。常見優(yōu)化方法

雖然SSR仍有許多不足之處,但是也不是沒有改善的空間。

一、緩存優(yōu)化

1、頁(yè)面級(jí)別緩存:vuessr官網(wǎng)給我們提供了一種方法,如果頁(yè)面并非千人千面,總是為所有用戶渲染相同的內(nèi)容,我們可以利用名為 micro-caching 的緩存策略,來(lái)大幅度提高應(yīng)用程序處理高流量的能力。這通常在 Nginx 層完成,也可以在 Node.js 中實(shí)現(xiàn)。

2、組件級(jí)別緩存:通過對(duì)組件設(shè)置serverCacheKey的方式,如果組件serverCacheKey相同,將復(fù)用之前渲染的組件產(chǎn)物,不需要重新渲染。具體是類似這樣的:export default {
name: 'myComponent', // 必填選項(xiàng)
props: ['item'],
serverCacheKey: props => props.item.id,
render (h) {
return h('div', this.item.id)
}
}3、cgi接口緩存:如果部分cgi接口返回的數(shù)據(jù)是固定的, 我們可以在node后端拉取cgi的時(shí)候,設(shè)置cgi緩存,緩存至memcache或其他輕量存儲(chǔ)服務(wù),當(dāng)然,你也需要設(shè)置好緩存更新策略。

二、代碼實(shí)現(xiàn)優(yōu)化

1、減少組件嵌套層次,優(yōu)化HTML結(jié)構(gòu):由于組件最初需要在node后端進(jìn)行VDOM計(jì)算和渲染,優(yōu)化組件層次結(jié)構(gòu),減少過深曾經(jīng)的DOM嵌套,可以減少VDOM計(jì)算耗時(shí)。

2、減少首頁(yè)渲染數(shù)據(jù)量:根據(jù)業(yè)務(wù)調(diào)整用戶首屏可見的所需渲染的數(shù)據(jù),其他數(shù)據(jù)懶加載或異步加載。

三、資源加載

1、流式傳輸:vuessr官網(wǎng)給我們介紹了一種方法,render對(duì)象會(huì)暴露renderToStream方法,把原有的直出結(jié)果以流的形式輸出,讓我們可以更快的響應(yīng)數(shù)據(jù)到客戶端,能減少首屏渲染時(shí)間,更早開始加載頁(yè)面資源。(流式傳輸需要在asyncData執(zhí)行結(jié)束后開始,否則沒有數(shù)據(jù),這意味著流失傳輸受限于cgi拉取耗時(shí))

2、分塊傳輸:lucien大佬在tweb大會(huì)上給我們帶來(lái)了新的思路,由模板的語(yǔ)法樹, 分析代碼的上下文,分析數(shù)據(jù)和模板間的依賴,用異步數(shù)據(jù)分割模板,分塊逐步輸出。(相比流式傳輸,前置位的cgi數(shù)據(jù)一旦ready,就會(huì)渲染輸出,而不需要等待所有的gi拉取到后才開始渲染輸出,但是該方案改造成本較大)

一張圖說(shuō)明白這兩者的區(qū)別:

四、改造SSR算法

SSR算法改造:在tweb大會(huì)上lucien給我們介紹了一個(gè)新的思路,改造直出算法,不用vue-loader而用自研的aga-loader,將vdom渲染轉(zhuǎn)換為字符串模板,具有更高的渲染性能。

性能提高的同時(shí),由于沒有完整的組件運(yùn)行環(huán)境,也帶來(lái)了部分語(yǔ)法上的約束,同時(shí),也不支持vuex。

思考

看到這里,讀者們應(yīng)該對(duì)SSR了如如來(lái)神掌且熟悉了常見的優(yōu)化方法,但是回頭思考一下,Vue-SSR的優(yōu)化無(wú)非是在 cgi拉取 和 VDOM直出渲染 上下功夫,因?yàn)檫@兩者就是node后端最耗時(shí)的步驟,其次,由于這種耗時(shí)會(huì)同步阻塞頁(yè)面的FP,所以更進(jìn)一步的方法是流式輸出或分塊,減少首屏渲染時(shí)間。

然而,但是并不是所有的cgi都能緩存,類似拉取用戶個(gè)人信息的cgi就無(wú)法緩存,SSR算法改造成本大,約束也大。再看看流式傳輸和分塊傳輸,兩者雖然都對(duì)FP時(shí)間優(yōu)化了,但流式傳輸受限于cgi拉取時(shí)間,分塊傳輸改造成本大。而且兩者存在的一個(gè)共性問題,那就是可交互時(shí)間仍然沒有優(yōu)化。

當(dāng)然,這里并不是要否定所有的優(yōu)化方法,而是方法各有優(yōu)劣,比較優(yōu)缺點(diǎn)大家才能根據(jù)自己的業(yè)務(wù)需求和優(yōu)化場(chǎng)景選取合適的優(yōu)化方法。受流式傳輸和分塊傳輸?shù)膯l(fā),我們能不能在這上面下功夫?在請(qǐng)求到來(lái)時(shí),先返回一份完整的HTML空頁(yè)面,讓客戶端更快的FP,其次,后端拉取cgi和渲染VDOM 與?前端拉取CSS、JS資源?兩者同步進(jìn)行,之后再吐出直出的HTML string 與 頁(yè)面store,再次渲染頁(yè)面,這樣的話FP提前了,和CSR的FP時(shí)間一毛一樣,其次,FMP相比CSR大大提高,更重要的是,由于JS資源的加載讓Vue初始化觸發(fā)的更早,意味著頁(yè)面可響應(yīng)時(shí)間也會(huì)提高。

為了闡明這種區(qū)別,我們看一下流程圖:
新方案探索與實(shí)踐

先吐空頁(yè)面,之后再吐直出后的數(shù)據(jù),但是關(guān)鍵是怎么讓直出后的數(shù)據(jù)再渲染上去,同時(shí)不要讓JS先執(zhí)行了,導(dǎo)致頁(yè)面直接變成CSR了。

思考?xì)v程:不要讓JS執(zhí)行,等直出數(shù)據(jù)回來(lái)了再執(zhí)行,這可咋辦,筆者最初想實(shí)現(xiàn)一個(gè)JS加載控制器,不通過script來(lái)引入js,而是自己去拉取js代碼,eval函數(shù)執(zhí)行,這樣js的執(zhí)行控制權(quán)就在自己手上了,但是有幾個(gè)問題,eval函數(shù)解析只是把字符串當(dāng)js來(lái)執(zhí)行,那錯(cuò)誤上報(bào)就會(huì)出問題,接了sentry錯(cuò)誤上報(bào)是基于js文件、錯(cuò)誤行列來(lái)定位的,除此之外,ajax來(lái)拉取js代碼會(huì)不會(huì)存在性能問題,和瀏覽器加載js資源速度上是否存在差異?還有第三方j(luò)s不能直接ajax拉取,需要設(shè)置跨域頭。于是筆者開始換一種思路,能不能給每個(gè)js文件包裹一層函數(shù),通過setTimeout(fn,0)的方式來(lái)延遲調(diào)用,但是這又有問題,有多個(gè)js文件且文件已經(jīng)是打包好了的,改了js文件,map映射不就亂了嗎?錯(cuò)誤上報(bào)不就亂了嗎?

源碼在自己手里,為啥不直接在源碼上提供一個(gè)調(diào)用入口,來(lái)觸發(fā)js執(zhí)行,最后直出的時(shí)候吐出<script>window.render()<script>來(lái)控制js執(zhí)行不就可以了嗎?

開始改造

客戶端改造:

原有的直出存在entry-client和entry-server兩個(gè)js文件,分開兩個(gè)入口各自打包,我們需要改造的是entry-client,讓其可控制,開頭筆者只是對(duì)new App()和mount 包裹了一層函數(shù),但是后來(lái)發(fā)現(xiàn),第三方j(luò)s依賴執(zhí)行了,其實(shí)如果你明白webpack的打包原理,那么require的時(shí)候就會(huì)觸發(fā)相應(yīng)的依賴執(zhí)行,我們要在entry-client之外再包一層來(lái)控制。新增entry-runner文件:window.__GLOBAL_RENDER__ = function() {
require("./entry-client.js");
console.log("__GLOBAL_RENDER__ ENDING"); // eslint-disable-line
};

以這個(gè)為打包入口,加載完js后就不會(huì)執(zhí)行了(當(dāng)然,還會(huì)執(zhí)行webpack的運(yùn)行時(shí)代碼,控制chunk執(zhí)行的,忽略不計(jì))

改造服務(wù)端直出代碼:module.exports = functionhandle(req,res){
res.writeHead(200, {
'Content-Type': 'text/html',
});
res.write(FP_html.replace(/<\/body>[\s\S]*<\/html>/g,''));
// ...other code
}

FP_html是客戶端打包的時(shí)候生成的index.html,里面已經(jīng)插入好了css、js依賴,你只需要把尾部body和html的結(jié)束標(biāo)簽去掉。

接下來(lái)是在直出后吐出直出數(shù)據(jù)。constcontext = {
url: req.REQUEST.pathname
};
consthtml = awaitrenderToString(context);
consthtml_render = html.match(/(<div data-server-rendered[\s\S]*<\/div>)[\s\S]*(<script>window.__INITIAL_STATE__[\s\S]*injected -->)/g);
constinnerHTML = RegExp.$1;
conststate = RegExp.$2;
res.write(`
<script>
document.body.innerHTML = \`${innerHTML}\`
</script>
${state}
<script>
setTimeout(()=>{
window.__GLOBAL_RENDER__ && window.__GLOBAL_RENDER__()
},0)
</script>
</body>
</html>
`);
res.end();

通過正則提取出渲染結(jié)果html以及store,之后write吐會(huì)給前端,innerHTML會(huì)覆蓋第一次吐給前端的頁(yè)面中的div#app,接下來(lái)state即全局的store初始化,最后setTimeout控制window.__GLOBAL_RENDER__執(zhí)行即可,因?yàn)関ue判斷是否直出是根據(jù)div以及全局的store是否初始化來(lái)判斷的,所以我們這樣做沒有問題。其次,為了優(yōu)先觸發(fā)一次FMP,我們需要通過setTimeout的方式調(diào)用全局渲染方法。

接下來(lái)我們來(lái)比較一下CSR、SSR以及改造后的效果:

CSR:

SSR:

優(yōu)化后的SSR:各項(xiàng)數(shù)據(jù)對(duì)比:
類型\指標(biāo)FPFMP可交互時(shí)間
CSR0.4s1.1s1.2s
SSR0.7s0.7s1s
優(yōu)化SSR0.4s0.6-0.7s0.8s

可以明顯的看到,優(yōu)化后的SSR,FP時(shí)間跟CSR一樣,讓我們的首屏渲染更快了(可優(yōu)先渲染頁(yè)面骨架圖),其次,FMP時(shí)間跟SSR相差不大,最后是可交互時(shí)間,由于JS依賴較早開始加載,所以頁(yè)面直出結(jié)束后可馬上執(zhí)行vue初始化邏輯,所以可交互時(shí)間縮短到0.8s。

我們找到了一種成本不是很高,不僅優(yōu)化了FP、FMP時(shí)間還優(yōu)化了可交互時(shí)間的方法!

最后

文章看到了這里,相信你對(duì)Vue-SSR有了更加深刻的認(rèn)識(shí)和了解,本文比較了CSR和SSR,并總結(jié)歸納了Vue-SSR的常見方法,最后在新的方案上進(jìn)行嘗試,達(dá)到了一定程度上的優(yōu)化。優(yōu)化方案各有優(yōu)劣,也有成本開銷,根據(jù)自己業(yè)務(wù)需求來(lái)選擇合適的優(yōu)化方法,才是最有效的。希望本文能給你帶來(lái)幫助~ 也歡迎討論其他方法~

總結(jié)

以上是生活随笔為你收集整理的基于Vue-SSR优化方案归纳总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。