滴滴出行小程序體積優化實踐

概述

2019年下半年,爲了將微信錢包/支付寶九宮格入口的滴滴出行遷移爲小程序,團隊對小程序進行了大量的功能升級與補全。在整個過程當中也遇到並克服了一系列問題和挑戰,其中包體積問題尤其突出。接下來全面介紹一下滴滴出行小程序在體積控制方面作的努力與沉澱。前端

背景

微信對小程序包體積的要求是整體積不得超過12M,主包及單個分包體積不得超過2M。支付寶對於小程序包體積的計算方式雖和微信略有區別,不過總體也大同小異。node

18年至19年初時,滴滴出行小程序裏承載的業務只有網約車,且業務需求較少,在主包內都可以搞定。而在下半年時,爲了將微信錢包/支付寶九宮格入口遷移至小程序,小程序開始新增諸如公交/代駕/車服/單車/順風車等衆多業務線,同時網約車的業務需求也要作全面的補齊,業務量和代碼量一塊兒爆炸式增加。webpack

滴滴出行包含了豐富多樣的出行業務,包含了快車/專車/出租車/豪華車/拼車/單車/代駕/順風車/公交/車生活等衆多業務線。整個滴滴出行小程序的最重要,使用最高頻的頁面是首頁與訂單詳情頁,首頁中承載了各個業務線的需求表達,各個業務線的訂單詳情頁則承載了具體的出行訂單展現邏輯。此外還有各類功能頁面好比我的中心,營銷頁面,設置,歷史行程。git

按照滴滴出行的產品邏輯,全部業務線的需求表達邏輯都在首頁承載,爲了良好的切換體驗,在首頁採用了單頁頂導的方案進行業務線展現。即每一個業務線在首頁中提供一個需求表達組件,當用戶切換頂導業務線後,切換出對應的業務線組件。github

在這種設計下,全部的業務線的需求表達邏輯都集中在首頁這個單一頁面中,致使在業務迭代過程當中,承載首頁的主包體積迅速增加,很快觸碰了小程序平臺的單包2M上限,對後續的業務迭代與發展帶來巨大阻礙。所以,對於包體積的控制是咱們在小程序開發過程當中面臨的一大難題。web

體積控制

下面咱們將介紹滴滴出行小程序開發迭代過程當中,咱們對於小程序包體積進行的一系列優化控制實踐。npm

基礎優化手段

對於小程序來講,基礎的包體積優化手段包括:資源壓縮/去除代碼冗餘/資源CDN化/異步加載json

在web開發中,webpack提供了大量的代碼優化能力,包括依賴分析、模塊去重、代碼壓縮、tree shaking、side effects等,這些能力能夠方便地完成資源壓縮和去除代碼冗餘的工做。滴滴出行小程序基於滴滴開源的小程序框架Mpx( https://github.com/didi/mpx )進行開發,Mpx框架的編譯構建徹底基於webpack,兼容webpack內部生態,自然可使用上述能力對包體積進行優化。小程序

小程序中支持部分靜態資源(如圖像視頻等)使用CDN地址加載,咱們會盡量將相關的資源壓縮後放到CDN上,避免這部分資源對包體積的佔用。緩存

小程序場景下沒法像web當中經過script標籤便捷地進行異步加載,可是小程序平臺後期紛紛支持了分包加載的方案來實現該能力,因爲分包加載是小程序特有的技術規範,webpack沒法直接支持,所以Mpx框架專門針對該技術規範進行了良好的適配支持,關於該能力的應用咱們會在後文詳細闡述。

除此以外,Mpx框架還針對小程序場景進行了許多包體積優化的適配工做,如儘量減小框架運行時包體積佔用(壓縮後佔用56Kb),對引用到的頁面/組件按需進行打包構建,聲明公共樣式進行樣式複用,分包內公共模塊抽取等。

在Mpx框架的這些能力的支持下,基本不須要額外配置就能構建出一個通過初步優化的小程序包。

微信開發者工具選項裏也有相似的"上傳代碼時自動壓縮混淆"可勾選,但在開發者工具中上傳代碼時計算體積是直接計算的當前項目代碼的體積,並不會依據壓縮後的體積。所以,若是你使用原生小程序進行開發,你的source代碼極有可能進行進一步的壓縮以節省空間。

分析體積

雖然框架已經提供了不少在體積控制方面的優化,可是隨着業務迭代咱們發現主包體積依然偏大。

在遇到主包體積偏大後,咱們須要弄明白,主包裏有哪些東西?它們爲何這麼大?

使用原生小程序或者其餘非基於webpack的框架進行開發的同窗遇到這個問題後,可能只能去看硬盤上的文件大小。這樣一來,各個模塊的大小佔比可能並不直觀。而咱們則能夠藉助 webpack-bundle-analyzer 這樣一個webpack插件去作輔助分析。

好比這是一個使用Mpx框架編寫的demo,經過 npm run build --report 就能夠看到這樣一個界面:

體積分析圖

能夠看到這個demo工程由 moment / lodash / socket-weapp / core-js 等第三方庫組成。各個庫的大小,相互依賴關係也能清晰地看出。

對於滴滴出行小程序也是能看到相似的圖,能看到整個項目究竟是由哪些代碼組成。

另外,滴滴出行前端開發一直是採用「源碼編譯」的,可讓整個項目裏公共的依賴能夠實現僅有一份,一塊兒共用。簡而言之,也有助於減小項目代碼體積。相關資料:https://github.com/DDFE/DDFE-blog/issues/23

要完美髮揮源碼編譯的效果,須要上下游一塊兒創建整套源碼編譯生態,好比主項目的依賴方在聲明公用依賴時,就應該用peerDep或者devDep來聲明一些公有依賴,這些共有依賴應該在主項目中統一聲明,避免因版本不一樣裝出兩份公共依賴,那樣反而會增大致積。因爲滴滴出行小程序涉及業務線及團隊衆多,部分團隊可能並不知道這個事情,所以代碼裏實際是可能出現上述劣化場景。而依照分析圖,能夠容易地發現這種問題,並推進相關團隊清除這些重複依賴。

同時,咱們依照體積分析圖,對其中體積較大的文件重點分析,進行了一輪業務代碼梳理和精簡,刪除了一些無用代碼,精簡了websocket的消息體描述文件等。

配置分包

分包是小程序給出的相似web異步引入的一個方案,把一些初始進入時不須要的頁面能夠放進分包裏,跳轉到對應頁面時纔去下載分包,將這些頁面及其附屬資源放到分包裏能夠有效減小主包體積。

Mpx框架早期對分包規範進行了初步支持,資源訪問規則保持和微信一致,主要根據資源存放的目錄判斷應該輸出到主包仍是分包。有這個能力後,咱們把行程頁抽到了分包,大概抽出了200多K左右的空間。

有了行程頁的成功拆分後,咱們開始對全部的非首頁代碼進行分包操做,好比起終點選擇和我的中心。以及部分業務線的接入是經過npm的方式接入,咱們也儘量將這些業務線的全部非首頁的代碼放到了分包。

這裏還有個題外話,得益於mpx早期設計了packages形式的業務組合方案,能夠很方便地讓業務獨立開發,又能及其方便地整合。然後發現微信的分包的json配置設計和packages很像,就在這個基礎上支持了微信的分包,用戶側僅需在原來的packages基礎上加一個query標記這個分包的名字便可。

拆除各個分包後,整個項目結構大概如圖:

分包一期結構圖

初階的分包工做進行完畢後,總計從主包裏拆了差很少400K的空間到分包裏。

分包資源精細化管理

上面提到,Mpx框架初期的分包處理規則是徹底按照微信的方式,把在分包路徑下的資源收集到分包裏。而npm管理的資源由於都在node_modules目錄下,不屬於任何分包路徑,則會被所有收集進主包。

好比以前咱們有行程頁分包,行程頁自有的狀態管理store整個都在行程頁分包的路徑下,就會被收集到行程頁分包中。而行程頁還用到了封裝好的didi-socket庫,這個庫是公共的npm包,即便它只在行程頁分包裏被使用,但因爲它自己路徑是在node_modules下的,那麼就會將其收集進主包裏。

由於早期的一些設計,行程頁的資源和首頁是分割開的,都比較獨立地存在於各自的路徑下,一期的分包處理的大頭也主要是行程頁,它恰好契合了Mpx初期對分包處理上的特色,所以能較好地收集進行程頁分包裏。

隨着業務迭代,後續大量業務線的接入都是經過npm進行的,就會有大量npm包資源,他們都在node_modules目錄下,所以所有會被收集進主包。

因此Mpx框架進行了一系列改造:

  1. 在構建的依賴收集過程當中,咱們會對收集到的依賴打上標記,記錄它是被哪些分包引入的。一旦它只有一個分包引入,它就會被輸出到這個分包中。
  2. 咱們會根據用戶定義的分包配置,自動在 SplitChunksPlugin 中生成各個分包的 cacheGroups ,把分包中的複用模塊抽取到分包下的bundle中。
  3. 對於組件和靜態資源,若是他們被多個分包所引用且未在主包中引用,爲了確保主包體積最優,這些資源將產生多份副本分別輸出到對應分包中,而不會佔用主包體積。

這樣一來,無論分包中引用的資源本來在什麼位置,最終輸出時都會盡量將其輸出到dist的分包目錄下,避免佔用主包空間

這個改動完成後項目結構看似和以前同樣,但得益於Mpx處理分包資源能力的升級,咱們得以將業務線分包中引用的npm資源成功輸出到其所在的分包目錄下。

封面方案

再後來滴滴出行小程序須要替換微信/支付寶裏原有的WebApp入口,小程序接入的業務線迅速增長,包體積迅速增加。

這個部分體積增加的主要緣由前面提到過,全部的業務線都要接入到主頁來展現。這也是因爲業務特色決定的,滴滴出行提供了豐富的出行產品線,包括快車/專車/出租車/豪華車/拼車/單車/代駕/順風行車等產品,用戶是可能須要反覆切換挑選的。這個過程還要保留起終點車型之類的信息,必須是一個頁面內切換組件加一整套很是複雜的大型狀態管理才能比較流暢順滑地實現。而不能像一些電商/信息平臺,將不一樣的功能拆分到不一樣頁面,讓用戶經過首頁的菜單進入子頁面再進行操做,首頁只承載入口,只有較少的業務邏輯,分包處理起來就會容易不少。

所以各個業務線都要提供首頁組件進行接入。這個組件會在首頁被用到,因此不管如何也拆不到分包裏。最終,整個首頁主包部分的體積能夠分紅兩個部分:基礎庫和業務代碼。二者的體積佔比大概是公共依賴基礎庫佔1M左右,業務代碼佔1M左右。

這麼龐大的基礎庫體積主要是因爲滴滴出行的業務線及業務團隊衆多,各方均有一些本身的基礎依賴。好比網約車依賴的長連接通訊pb數據描述文件,地圖會依的大數計算庫,順風車依賴的CML框架運行時、代駕依賴的通訊網關庫,以及公用的組件庫和polyfill等。

因此滴滴出行小程序面對的問題在當時已經沒法用純技術方案在短時間內快速解決問題了,因而咱們作了一個工程架構調整,能夠叫封面頁方案,解決了主包問題。

封面方案簡單講,就是作一個帶滴滴出行Logo的封面做爲啓動頁面,而頁面一旦加載,馬上跳轉另外一個頁面,這個頁面真正承載業務,且它被放在分包裏。

這個操做的意義在於,主包裏就只剩下了全部方都要依賴的基礎框架/庫等,而業務全被抽離到了分包裏。

封面方案結構圖

這是封面方案完成後項目的結構圖,以前很大塊的首頁業務邏輯被抽出到首頁分包中了。

這樣一個挪移的操做的結果是咱們能夠有2M的主包空間來乘放基礎的公共的庫,有一個2M左右的分包來乘放前面提到的滴滴出行的集成了各類業務的「大主頁」。而當時拆下來差很少有1.2M的主包,800K+的業務主分包。

這個改造最優秀的一點在於,後續的業務迭代產生的體積增加幾乎全是在業務主分包裏,剩下的1.1M+空間留給業務迭代仍是比較充裕的。而主包的體積在理想條件下是能夠長久保持不變的,就不會由於業務需求的不斷開發反覆致使主包體積臨近超標,再也不須要爲主包體積感到焦慮。

固然,能夠看到,這個方案自己是沒有消減任何體積的,只是把位置變換了一下。除此以外,這個封面頁方案其實也存在一些缺陷,好比首屏業務的展現會變慢,由於要加載的內容會變多,不太小程序自己有較好的緩存資源的能力,所以還算能夠接受。

相比於因體積問題卡住需求迭代以及產品線的接入,目前這個方案至少能解決有無問題。咱們開發團隊後續也會持續跟進關注體積問題,看是否會有產品方案變動或者小程序自己給出一些解決方案來進一步優化這個部分。

總結

Mpx框架在包體積控制上作了大量工做,對於npm場景下的小程序分包進行了很是完善的支持。

滴滴出行小程序團隊在框架支持的基礎上,經過梳理業務依賴,充分利用分包,調整交互方案等一系列手段,在不阻礙業務發展的前提下,將龐大複雜的滴滴出行小程序包體積控制在平臺限制範圍內。

但願本文能給在包體積上遇到問題的小程序開發者們帶來一些啓發,歡迎留言交流。

相關文章
相關標籤/搜索