京東快遞小程序分包優(yōu)化實踐
點擊上方 前端Q,關注公眾號
回復加群,加入前端Q技術交流群
前言—
隨著項目規(guī)模增大,小程序分包優(yōu)化是必須要面對的問題。分包不合理,不僅影響項目迭代和上線計劃,還關乎用戶體驗,甚至因此導致 C 端用戶流失。本文主要介紹京東快遞小程序分包過程中踩過的坑,以及小程序分包優(yōu)化的一些建議。
小程序簡介
小程序是一種不需要下載安裝即可在各類宿主環(huán)境(手機 APP、車載系統(tǒng)、IOT 設備等)中使用的應用程序。
小程序使用了雙線程模型,包括邏輯層和渲染層:邏輯層 JSCore 負責運行 JavaScript 腳本,進行數據處理;渲染層使用 WebView 進行渲染,負責頁面展示、處理用戶交互。小程序通信模型如圖 1 所示。

小程序分包機制
小程序的優(yōu)勢之一就是無需下載安裝即可運行。在用戶打開小程序時,如果是首次使用,或者小程序版本有更新,宿主環(huán)境會下載最新代碼包,我們稱這個包為小程序的“主包”。為優(yōu)化小程序首次啟動下載時間,各小程序平臺對主包大小有一定限制,如微信限制主包大小不能超過 2M。
為了防止主包超限,以及更好地多人協作,開發(fā)人員可以對小程序進行分包,如將一組獨立的功能頁面作為分包打包,當用戶進入分包頁面時,宿主環(huán)境會動態(tài)下載對應分包,極大提高用戶體驗。小程序平臺對分包大小限制為 20M。小程序包加載流程圖如圖 2 所示。

分包前準備—
本節(jié)主要介紹分包前的一些準備工作。
項目架構梳理
在分包優(yōu)化前,首先對項目框架有個清晰地梳理,才能更好地明確優(yōu)化方向。京東快遞小程序基于 Taro 多端開發(fā)框架,適配了微信、百度、京東等多個 APP 渠道。
基礎架構圖如圖 3 所示。

代碼依賴分析
依賴分析能幫我們確定項目代碼依賴關系,根據依賴關系可以確定分包優(yōu)化的代碼、資源文件等。依賴分析主要有以下兩種方式:
通過小程序開發(fā)者工具的“代碼依賴分析”插件,可以查看到各代碼包的依賴情況。
在 Taro2.0 以上版本中,使用了 Webpack 進行編譯構建。可以通過添加 webpack-bundle-analyzer 插件,實現依賴分析的可視化展示。主要步驟如下:
a. 首先安裝 webpack-bundle-analyzer 依賴:
npm install webpack-bundle-analyzer -D
b. 然后在 mini.webpackChain 中添加如下配置:
const config = {
...
mini: {
webpackChain (chain, webpack) {
chain.plugin('analyzer')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [])
}
}
}
c. 然后通過運行編譯命令,即可查看代碼文件依賴關系及體積。
小程序打包面臨問題—
隨著需求迭代,京東快遞小程序主包早已接近閾值 2M,稍有不慎就會超包,影響上線計劃。
京東快遞小程序打包面臨問題如下:
圖片資源過大,影響主包體積; 第三方包引入不規(guī)范,導致打包后引入冗余代碼; console、debugger 等測試代碼未做優(yōu)化,需要上線前手動刪除; 采用運行時而不是構建時進行多端小程序代碼兼容; 分包難度大,主包涉及寄件、查件等黃金流程頁面,分包成本大; 分包路徑問題,有些頁面路徑已經給到外部,分包后涉及外部系統(tǒng)改造上線;
小程序分包優(yōu)化實踐—
本節(jié)主要介紹京東快遞小程序分包優(yōu)化實踐。
圖片資源問題
小程序主包的體積空間是“寸土寸金”的,建議將圖片資源上傳到 CDN,優(yōu)先使用 CDN 圖片。如有 tabbar 等必須用本地圖片的情況,建議將本地圖片壓縮后再進行引入。圖片資源壓縮前后對比如圖 4 所示:


可以看到,圖片壓縮后主包代碼減少了 17KB,折算成代碼行數收益是非常大的。分包優(yōu)化時建議優(yōu)先處理圖片資源,圖片壓縮可以請 UI 同學協助處理。
第三方包引入問題
項目開發(fā)中難免會引入第三方工具包,包引入不當會導致打包后體積過大。拿 lodash 舉例,原來的引入方式如下
import { get } from 'lodash'
上述引入打包結果如圖 5 所示:

可以看到,lodash 包大小為 117KB。
我們優(yōu)化后的引入方式如下:
import get from 'lodash/get'
import isEmpty from 'lodash/isEmpty'
打包結果如圖 6 所示:

可以看到,優(yōu)化引入方式后 lodash 包大小只有 46KB,使主包體積減少了 60%。
除了上述優(yōu)化方法,還可以將 lodash 替換為“l(fā)odash-es”,“l(fā)odash-es”基于 ESM 打包方式,這樣就能利用 tree-shaking 移除不必要的代碼,同時還能保留了按需引入的寫法。
關于 console、debugger 的打包優(yōu)化
在原生開發(fā)中,項目中的 console、debugger 等調試代碼占據了一定主包空間,往往需要上線前手動移除。京東快遞小程序基于 Taro 框架開發(fā),在編譯構建時提供了代碼壓縮插件的支持,可以做如下優(yōu)化配置:
module.exports = {
env: {
NODE_ENV: '"production"'
},
plugins: {
uglify: {
enable: true,
config: {
// 配置項同 https://github.com/mishoo/UglifyJS2#minify-options
compress: {
drop_console: true,
drop_debugger: true
}
}
},
}
}
上述是生產環(huán)境打包配置文件,在 plugins 新增 uglify 選項,在 config 下新增 compress 配置項,將“drop_console”和“drop_debugger”設置為 true,即可在生產環(huán)境打包階段移除代碼中的 console 和 debugger,減少包代碼體積。
采用構建時進行多端小程序代碼兼容
京東快遞小程序除了微信端,還適配百度和京東小程序。對于某些只在特定平臺才有的功能,采用運行時的適配方法如下:
const isJD = process.env.TARO_ENV === 'jd'
function test() {
if (isJD) {
console.log('京東小程序特定功能')
}
}
首先定義了一個全局變量,在運行時判斷如果是京東小程序平臺,執(zhí)行京東小程序相關代碼。上述代碼構建后的結果如下:
// 京東小程序
const isJD = true
function test() {
if (isJD) {
console.log('京東小程序特定功能')
}
}
// 非京東小程序
const isJD = false
function test() {
if (isJD) {
console.log('京東小程序特定功能')
}
}
可以看到,在京東和非京東小程序,只是頂級作用域中 isJD 的值不一樣,test 函數中代碼是沒有變化的。優(yōu)化后的代碼如下
function test() {
if (process.env.TARO_ENV === 'jd') {
console.log('京東小程序特定功能')
}
}
構建后的結果
// 京東小程序
function test() {
console.log('京東小程序特定功能')
}
// 非京東小程序
function test() {}
可以看到,通過動態(tài)判斷 process.env.TARO_ENV,構建后小程序只包含了自己平臺相關的代碼,大大減少了包體積(請注意區(qū)分 process.env.TARO_ENV 和 Taro.getEnv(),前者是編譯構建時的變量,后者是運行時的變量)。
主包黃金流程頁面分包、分包路徑跳轉問題
如果要對主包某個頁面進行分包,但頁面路徑已提供給外部,分包改變路徑后可能涉及其他系統(tǒng)改造上線。這種情況可以保留主包頁面,代碼做如下處理
export default class PageA extends Taro.Component<Props, State> {
componentDidMount() {
try {
const params = get(this.$router, 'params') || {}
const paramArr: Array<string> = []
Object.keys(params).forEach(key => {
params[key] && paramArr.push(`${key}=${params[key]}`)
})
let url = '/packageSub/test/test'
if (paramArr.length > 0) {
url = `${url}?${paramArr.join('&')}`
}
Taro.redirectTo({ url })
} catch (e) {}
}
render(): JSX.Element {
return <View></View>
}
}
可以看到,主包 PageA 頁面只保留了 componentDidMount 的代碼,首先從路由參數中獲取 params,參數轉換之后通過 redirectTo 路由到分包頁面,這樣對跳轉方是無感知的,同時將 PageA 主體移入了分包頁面,減小了主包體積。
總結—
小程序運行在各類宿主環(huán)境中,無需安裝即可運行。因此保證小程序主包大小,對小程序進行分包優(yōu)化能極大提升用戶體驗。
對小程序分包優(yōu)化時,要具體情況具體分析。要注意以下幾點:
分包優(yōu)化前,要做好項目框架梳理工作,明確分包方向;然后利用代碼依賴分析工具進行包依賴分析,確定要分包的代碼、資源文件等;
優(yōu)先處理圖片資源加載、第三方包引入問題,然后進行正確打包配置,合理利用 process.env.TARO_ENV 進行平臺差異處理,最后再考慮黃金流程頁面分包;
分包優(yōu)化是個持續(xù)的過程,要培養(yǎng)分包的意識,日常工作按照最佳實踐進行開發(fā),才能保證系統(tǒng)穩(wěn)定。

往期推薦



最后
歡迎加我微信,拉你進技術群,長期交流學習...
歡迎關注「前端Q」,認真學前端,做個專業(yè)的技術人...


