2020.06.27
前提
我是喜歡做一些前端優(yōu)化相關(guān)的工作的陪蜻,最近又做了一些,也踩了一些坑。于是就分享記錄一下间学。
之前遇到的問題
之前遇到的顯著問題是由于歷史債,或者說為了省事印荔,在做一些webpack相關(guān)的流程的時候低葫,采用了在入口處將所有資源都打出去的做法。然后將一些體積比較大的npm包仍律,或者用處比較多的npm包嘿悬,通過webpack的external方式來分離出去,通過這樣的操作水泉,讓主入口的index.js文件盡可能地小善涨。
這樣的做法有什么優(yōu)缺點呢?
優(yōu)點:
只需要一個index.js文件草则,其他的資源都可以通過external的方式獲取钢拧。
用戶從著陸頁跳轉(zhuǎn)到其他的頁面的時候,只要是在SPA之下炕横,就無需再請求webpack打包后的其他資源源内,這樣地話,打開這些頁面會很快份殿,因為資源早就預(yù)先加載過了膜钓。
缺點:
由于將整個項目中用到的所有資源都打包到了入口中(除了external的資源),致使有一些頁面卿嘲,盡管并不會被用戶訪問颂斜,也已經(jīng)直接在打包的文件中了。那必然導(dǎo)致拾枣,這個index.js 體積很大沃疮,那么如何解決這個問題呢?
舉一個形象的例子盒让,當(dāng)時的做法就是費了很大的力氣,我用卡車拉了一車的水果到你家門口忿磅,西瓜糯彬,蘋果,大鴨梨葱她,應(yīng)有盡有撩扒。你想要什么水果,我能夠立刻就把你要的水果給到你吨些。但是搓谆,我可能只是想要兩個蘋果,你卻要為此浪費那么多汽油豪墅。
我的方案泉手,其實是一個通用的方案,也就是React 官方文檔推薦的code-splitting 的方式偶器,用到了Suspense
以及Lazy
這兩個方法來實現(xiàn)斩萌。
其他的,也就是Webpack 4中配置dynamic-imports 的方法了屏轰。
這里需要解釋的是颊郎,其實我早在上家公司的時候,就已經(jīng)使用這樣的方式來進行code spliting霎苗。 之所以這次又做了這方面的工作姆吭,也是因為當(dāng)前公司項目的一些技術(shù)債。
一個項目唁盏,多個項目
我來這家公司之前内狸,對微前端只停留在認知層面,并沒有太多了解厘擂。后來昆淡,來到這家公司,慢慢地發(fā)現(xiàn)原來還有我們這樣的項目刽严。
產(chǎn)品究竟是什么
產(chǎn)品是SAAS的昂灵,面向企業(yè)的軟件。它的最終目的是希望能夠幫助企業(yè)在遇到危機或者突發(fā)事件的時候港庄,合理地調(diào)配倔既,處理一些事情恕曲。比如颶風(fēng)來襲之前鹏氧,向颶風(fēng)所在地的員工發(fā)送短信,郵件提醒佩谣,管理員需要能夠快速執(zhí)行一個預(yù)案把还,這個預(yù)案也可以說是一個任務(wù)列表,逐個任務(wù)去完成,直到所有任務(wù)完成吊履,它的工作才算完成安皱,這所有的一切都是這個軟件提供的。
然而雖然大體上說是一個軟件艇炎,但是更具體地來說酌伊,應(yīng)該是多端的服務(wù)。
首先是需要一個管理終端缀踪,這個終端能夠去為所有SAAS用戶設(shè)置相應(yīng)的權(quán)限居砖,依據(jù)它們所購買的產(chǎn)品。這個管理終端驴娃,我們可以跟它叫做admin portal.
另外奏候,還需要一個SAAS用戶的管理終端,這個終端可以依據(jù)你購買的產(chǎn)品唇敞,提供相應(yīng)的服務(wù)蔗草。這些服務(wù),包括發(fā)送消息疆柔,包括發(fā)布任務(wù)等等咒精。這個SAAS用戶的管理終端,我們可以跟它叫做manager portal.
其次婆硬,還需要一個普通用戶終端狠轻,這個終端接受來自manager portal的指令,例如下達的任務(wù)等彬犯。我們可以跟它叫做member portal.
我們現(xiàn)在搞清楚了向楼,這樣一個大的SAAS產(chǎn)品,需要多端來進行支持谐区。
如果你還不明白湖蜕,也可以有個更加通俗易懂的解釋。我們普通用戶逛的淘寶宋列,其實是淘寶買家版昭抒,淘寶的賣家也需要一個終端來管理和維護商品,這就是淘寶賣家版炼杖。除此之外灭返,還有一個淘寶的員工才能用的終端,通過它可以看到所有的賣家數(shù)據(jù)坤邪,可以在這個終端上面熙含,設(shè)置一些全場優(yōu)惠券。所以艇纺,我們可以看到怎静,一個大的產(chǎn)品邮弹,下面相應(yīng)地會有多端產(chǎn)品。
而即便是一個淘寶買家版蚓聘,也會根據(jù)用戶使用設(shè)備不同而分成不同版本腌乡,比如PC網(wǎng)頁版,手機網(wǎng)頁版夜牡,安卓手機APP版与纽,蘋果手機APP版,Ipad版本等等塘装,所以一個產(chǎn)品需要維護的內(nèi)容實際上是相當(dāng)多的渣锦。
好了,我們現(xiàn)在不談淘寶了氢哮,來繼續(xù)說我們的SAAS產(chǎn)品袋毙。
現(xiàn)在為了說明清楚,而又不泄露一些公司的隱私冗尤。我們假設(shè)我們做的產(chǎn)品是一個類似于微盟或者有贊這樣的一個產(chǎn)品听盖,它可以給一些中小商家提供搭建電商店鋪的能力。我們可以暫時給它起一個名字裂七,就叫做微贊 皆看。好了,現(xiàn)在我們繼續(xù)來分析我們的微贊背零。
微贊有一個admin portal腰吟,它用來管理商戶。還有一個manager portal徙瓶, 它是賣家的平臺毛雇,方便賣家上下架商品,做一些促銷活動侦镇,查看最新的銷售數(shù)據(jù)等等灵疮。當(dāng)然,微贊還有一個member portal壳繁,它是消費者終端震捣,可能是小程序,也可能是微信網(wǎng)頁闹炉,還可能是APP蒿赢,最終都是要讓消費者消費的入口。
然而渣触,如果微贊細分開來羡棵,又可以分成多個不同的模塊。比如優(yōu)惠券模塊昵观,又比如百億補貼模塊晾腔,這個時候,我們當(dāng)然希望我們地微贊更穩(wěn)定啊犬,這里的穩(wěn)定從以下幾個方面來談:
各個功能模塊灼擂,可以單獨部署,這樣每一個新的功能開發(fā)完成觉至,都不會等待其他的模塊剔应,而可以直接上線。
各個功能模塊之間應(yīng)該相互獨立语御,這樣能更好地支撐第一點峻贮。項目也能足夠簡潔。
所以应闯,這個時候纤控,我們發(fā)現(xiàn)針對第一個問題,我們需要引入微服務(wù)的概念碉纺,這個時候船万,對于后端服務(wù)來說,每個服務(wù)就能夠單獨部署骨田,上線耿导。相對應(yīng)的,前端要做好支持态贤,也需要引入微前端的概念,這樣的話悠汽,才好箱吕。
code spliting 又多種方式,在webpack的官方文檔中姻采,提到了兩種比較推薦的方式巴刻。第一種方式柠座,是我們以前就用到的webpack打包方式淮野,其原理說白了洞难,就是把那些external的資源拿出去萝勤,把那些common的資源也都拿出去瘪吏,單獨打包,對于這個入口來說,還是只有一個chunk拟淮。頁面在初始化的時候干茉,就已經(jīng)把所有的資源全部加載上了,之后惩歉,你就用就好了。第二種方式俏蛮,就是我們現(xiàn)在用的這種方式了撑蚌。
我做的工作厲害嗎?并不厲害搏屑,事實上争涌,這個工作只需要按照文檔按部就班就可以完成。
但是接下來辣恋,還是有一些不一樣的東西的亮垫。
混合應(yīng)用
前面說了,我們是想將我們的項目伟骨,進行微前端化處理的
這個時候饮潦,不光用到了動態(tài)加載,也在恰當(dāng)?shù)臅r機携狭,用到了loadRemote , 這是我們自己寫的一個加載遠程模塊的機制继蜡,通過它,我們可以實現(xiàn)類似node imort逛腿, require那樣的效果稀并。
之所以這樣做的目的,是有一下幾點单默。
第一碘举,前面說了,我們會有多端產(chǎn)品搁廓,而這多端產(chǎn)品中引颈,又有大量的業(yè)務(wù)組件是重復(fù)的,比如一個表單組件境蜕,這個表單組件并不單單是一個UI組件线欲,也是我們自己定制好的一個業(yè)務(wù)組件,跟業(yè)務(wù)綁定的非常緊汽摹,隨著開發(fā)和迭代李丰,這個表單組件,可能每周都會有代碼的提交逼泣,這個時候趴泌,我們希望對這個表單組件進行一個有效的管理舟舒。但是受限于基礎(chǔ)設(shè)施,我們當(dāng)時還并沒有一個私有的npm庫來完成這樣一個工作嗜憔,所以我當(dāng)時就做了一個工作秃励,通過loadRemote的方式,來把這個組件單獨build出來吉捶,這樣的話夺鲜,這個組件也就能夠被另外一端的產(chǎn)品訪問了。不過值得一提的是呐舔,這個方案乍看起來還很不錯币励,但是遇到了一個經(jīng)典的問題,那就是跨域珊拼。這里可以詳細說一說食呻,比如我在manager 端對這個組件進行build,最后生成的域名是manager.test.com 而我想要在member 端引用這個組件澎现,那么就會引起跨域的問題仅胞。解決這個問題,也很意外剑辫,非常湊巧的是干旧,我們的后端在使用K8S的時候,就將兩端的域做了整合妹蔽。這樣的話莱革,如果訪問member.test.com/mgr-static/abc ,它實際上會往manager.test.com/static/abc這個地址去解析讹开。也就完美解決了跨域的問題盅视。
第二,我們也發(fā)現(xiàn)旦万,雖然用到了動態(tài)加載闹击,但是由于有一些npm模塊寫得并不符合規(guī)范,導(dǎo)致出現(xiàn)了在多個chunk中某個npm包多次被打包進去的情況成艘,這個時候赏半,如果我們想要對打包后的chunk文件進行優(yōu)化,一個方法就是將那些寫得并不規(guī)范的npm包通過loadRemote的方式淆两,單獨打包出去断箫,這樣的話,它在最終打包的文件中秋冰,只會有一份結(jié)果仲义,而不會像剛才我們所說的那樣,在多個chunk中都有它的身影了。
事實上埃撵,關(guān)于這里提到的第一點赵颅,隨著私有npm庫的搭建,也許更加優(yōu)雅的方式已經(jīng)出現(xiàn)暂刘。關(guān)于這里提到的第二點饺谬,我也一直在找尋更加優(yōu)雅的解決辦法。
完稿時間: 20200917
2020.06.27
前提
我是喜歡做一些前端優(yōu)化相關(guān)的工作的谣拣,最近又做了一些募寨,也踩了一些坑。于是就分享記錄一下森缠。
之前遇到的問題
之前遇到的顯著問題是由于歷史債拔鹰,或者說為了省事,在做一些webpack相關(guān)的流程的時候辅鲸,采用了在入口處將所有資源都打出去的做法格郁。然后將一些體積比較大的npm包腹殿,或者用處比較多的npm包独悴,通過webpack的external方式來分離出去,通過這樣的操作锣尉,讓主入口的index.js文件盡可能地小刻炒。
這樣的做法有什么優(yōu)缺點呢?
優(yōu)點:
只需要一個index.js文件自沧,其他的資源都可以通過external的方式獲取坟奥。
用戶從著陸頁跳轉(zhuǎn)到其他的頁面的時候,只要是在SPA之下拇厢,就無需再請求webpack打包后的其他資源爱谁,這樣地話,打開這些頁面會很快孝偎,因為資源早就預(yù)先加載過了访敌。
缺點:
由于將整個項目中用到的所有資源都打包到了入口中(除了external的資源),致使有一些頁面衣盾,盡管并不會被用戶訪問寺旺,也已經(jīng)直接在打包的文件中了。那必然導(dǎo)致势决,這個index.js 體積很大阻塑,那么如何解決這個問題呢?
舉一個形象的例子,當(dāng)時的做法就是費了很大的力氣果复,我用卡車拉了一車的水果到你家門口陈莽,西瓜,蘋果,大鴨梨传透,應(yīng)有盡有耘沼。你想要什么水果,我能夠立刻就把你要的水果給到你朱盐。但是群嗤,我可能只是想要兩個蘋果,你卻要為此浪費那么多汽油兵琳。
我的方案狂秘,其實是一個通用的方案,也就是React 官方文檔推薦的code-splitting 的方式躯肌,用到了Suspense
以及Lazy
這兩個方法來實現(xiàn)者春。
其他的,也就是Webpack 4中配置dynamic-imports 的方法了清女。
這里需要解釋的是钱烟,其實我早在上家公司的時候,就已經(jīng)使用這樣的方式來進行code spliting嫡丙。 之所以這次又做了這方面的工作拴袭,也是因為當(dāng)前公司項目的一些技術(shù)債。
一個項目曙博,多個項目
我來這家公司之前拥刻,對微前端只停留在認知層面,并沒有太多了解父泳。后來般哼,來到這家公司,慢慢地發(fā)現(xiàn)原來還有我們這樣的項目惠窄。
產(chǎn)品究竟是什么
產(chǎn)品是SAAS的蒸眠,面向企業(yè)的軟件。它的最終目的是希望能夠幫助企業(yè)在遇到危機或者突發(fā)事件的時候杆融,合理地調(diào)配楞卡,處理一些事情。比如颶風(fēng)來襲之前擒贸,向颶風(fēng)所在地的員工發(fā)送短信臀晃,郵件提醒,管理員需要能夠快速執(zhí)行一個預(yù)案介劫,這個預(yù)案也可以說是一個任務(wù)列表徽惋,逐個任務(wù)去完成,直到所有任務(wù)完成座韵,它的工作才算完成险绘,這所有的一切都是這個軟件提供的踢京。
然而雖然大體上說是一個軟件,但是更具體地來說宦棺,應(yīng)該是多端的服務(wù)瓣距。
首先是需要一個管理終端,這個終端能夠去為所有SAAS用戶設(shè)置相應(yīng)的權(quán)限代咸,依據(jù)它們所購買的產(chǎn)品蹈丸。這個管理終端,我們可以跟它叫做admin portal.
另外呐芥,還需要一個SAAS用戶的管理終端逻杖,這個終端可以依據(jù)你購買的產(chǎn)品,提供相應(yīng)的服務(wù)思瘟。這些服務(wù)荸百,包括發(fā)送消息,包括發(fā)布任務(wù)等等滨攻。這個SAAS用戶的管理終端够话,我們可以跟它叫做manager portal.
其次,還需要一個普通用戶終端光绕,這個終端接受來自manager portal的指令女嘲,例如下達的任務(wù)等。我們可以跟它叫做member portal.
我們現(xiàn)在搞清楚了奇钞,這樣一個大的SAAS產(chǎn)品澡为,需要多端來進行支持漂坏。
如果你還不明白景埃,也可以有個更加通俗易懂的解釋。我們普通用戶逛的淘寶顶别,其實是淘寶買家版谷徙,淘寶的賣家也需要一個終端來管理和維護商品,這就是淘寶賣家版驯绎。除此之外完慧,還有一個淘寶的員工才能用的終端,通過它可以看到所有的賣家數(shù)據(jù)剩失,可以在這個終端上面屈尼,設(shè)置一些全場優(yōu)惠券。所以拴孤,我們可以看到脾歧,一個大的產(chǎn)品,下面相應(yīng)地會有多端產(chǎn)品演熟。
而即便是一個淘寶買家版鞭执,也會根據(jù)用戶使用設(shè)備不同而分成不同版本司顿,比如PC網(wǎng)頁版,手機網(wǎng)頁版兄纺,安卓手機APP版大溜,蘋果手機APP版,Ipad版本等等估脆,所以一個產(chǎn)品需要維護的內(nèi)容實際上是相當(dāng)多的钦奋。
好了,我們現(xiàn)在不談淘寶了疙赠,來繼續(xù)說我們的SAAS產(chǎn)品锨苏。
現(xiàn)在為了說明清楚,而又不泄露一些公司的隱私棺聊。我們假設(shè)我們做的產(chǎn)品是一個類似于微盟或者有贊這樣的一個產(chǎn)品伞租,它可以給一些中小商家提供搭建電商店鋪的能力。我們可以暫時給它起一個名字限佩,就叫做微贊 葵诈。好了,現(xiàn)在我們繼續(xù)來分析我們的微贊祟同。
微贊有一個admin portal作喘,它用來管理商戶。還有一個manager portal晕城, 它是賣家的平臺泞坦,方便賣家上下架商品,做一些促銷活動砖顷,查看最新的銷售數(shù)據(jù)等等贰锁。當(dāng)然,微贊還有一個member portal滤蝠,它是消費者終端豌熄,可能是小程序,也可能是微信網(wǎng)頁物咳,還可能是APP锣险,最終都是要讓消費者消費的入口。
然而览闰,如果微贊細分開來芯肤,又可以分成多個不同的模塊。比如優(yōu)惠券模塊压鉴,又比如百億補貼模塊崖咨,這個時候,我們當(dāng)然希望我們地微贊更穩(wěn)定晴弃,這里的穩(wěn)定從以下幾個方面來談:
各個功能模塊掩幢,可以單獨部署逊拍,這樣每一個新的功能開發(fā)完成,都不會等待其他的模塊际邻,而可以直接上線芯丧。
各個功能模塊之間應(yīng)該相互獨立,這樣能更好地支撐第一點世曾。項目也能足夠簡潔缨恒。
所以,這個時候轮听,我們發(fā)現(xiàn)針對第一個問題骗露,我們需要引入微服務(wù)的概念,這個時候血巍,對于后端服務(wù)來說萧锉,每個服務(wù)就能夠單獨部署,上線述寡。相對應(yīng)的柿隙,前端要做好支持,也需要引入微前端的概念鲫凶,這樣的話禀崖,才好。
code spliting 又多種方式螟炫,在webpack的官方文檔中波附,提到了兩種比較推薦的方式告私。第一種方式溜哮,是我們以前就用到的webpack打包方式,其原理說白了墩衙,就是把那些external的資源拿出去换吧,把那些common的資源也都拿出去折晦,單獨打包钥星,對于這個入口來說沾瓦,還是只有一個chunk。頁面在初始化的時候谦炒,就已經(jīng)把所有的資源全部加載上了贯莺,之后,你就用就好了宁改。第二種方式缕探,就是我們現(xiàn)在用的這種方式了。
我做的工作厲害嗎还蹲?并不厲害爹耗,事實上耙考,這個工作只需要按照文檔按部就班就可以完成。
但是接下來潭兽,還是有一些不一樣的東西的倦始。
混合應(yīng)用
前面說了,我們是想將我們的項目山卦,進行微前端化處理的
這個時候鞋邑,不光用到了動態(tài)加載,也在恰當(dāng)?shù)臅r機账蓉,用到了loadRemote , 這是我們自己寫的一個加載遠程模塊的機制枚碗,通過它,我們可以實現(xiàn)類似node imort铸本, require那樣的效果肮雨。
之所以這樣做的目的,是有一下幾點箱玷。
第一酷含,前面說了,我們會有多端產(chǎn)品汪茧,而這多端產(chǎn)品中椅亚,又有大量的業(yè)務(wù)組件是重復(fù)的,比如一個表單組件舱污,這個表單組件并不單單是一個UI組件呀舔,也是我們自己定制好的一個業(yè)務(wù)組件,跟業(yè)務(wù)綁定的非常緊扩灯,隨著開發(fā)和迭代媚赖,這個表單組件,可能每周都會有代碼的提交珠插,這個時候惧磺,我們希望對這個表單組件進行一個有效的管理。但是受限于基礎(chǔ)設(shè)施捻撑,我們當(dāng)時還并沒有一個私有的npm庫來完成這樣一個工作磨隘,所以我當(dāng)時就做了一個工作,通過loadRemote的方式顾患,來把這個組件單獨build出來番捂,這樣的話,這個組件也就能夠被另外一端的產(chǎn)品訪問了江解。不過值得一提的是设预,這個方案乍看起來還很不錯,但是遇到了一個經(jīng)典的問題犁河,那就是跨域鳖枕。這里可以詳細說一說魄梯,比如我在manager 端對這個組件進行build,最后生成的域名是manager.test.com 而我想要在member 端引用這個組件宾符,那么就會引起跨域的問題画恰。解決這個問題,也很意外吸奴,非常湊巧的是允扇,我們的后端在使用K8S的時候,就將兩端的域做了整合则奥。這樣的話考润,如果訪問member.test.com/mgr-static/abc ,它實際上會往manager.test.com/static/abc這個地址去解析读处。也就完美解決了跨域的問題糊治。
第二,我們也發(fā)現(xiàn)罚舱,雖然用到了動態(tài)加載井辜,但是由于有一些npm模塊寫得并不符合規(guī)范,導(dǎo)致出現(xiàn)了在多個chunk中某個npm包多次被打包進去的情況管闷,這個時候粥脚,如果我們想要對打包后的chunk文件進行優(yōu)化,一個方法就是將那些寫得并不規(guī)范的npm包通過loadRemote的方式包个,單獨打包出去刷允,這樣的話,它在最終打包的文件中碧囊,只會有一份結(jié)果树灶,而不會像剛才我們所說的那樣,在多個chunk中都有它的身影了糯而。
事實上天通,關(guān)于這里提到的第一點,隨著私有npm庫的搭建熄驼,也許更加優(yōu)雅的方式已經(jīng)出現(xiàn)像寒。關(guān)于這里提到的第二點,我也一直在找尋更加優(yōu)雅的解決辦法谜洽。
完稿時間: 20200917