分包加載
某些情况下,開發者需要將小程序劃分成不同的子包,在構建時打包成不同的分包,用戶在使用時按需進行加載。
在構建小程序分包項目時,構建會輸出一個或多個分包每個使用分包小程序必定含有一個主包所謂的主包,即放置默認啟動頁面/TabBar頁面,以及一些所有分包都需用到公共資源/JS腳本; 而分包則是根據開發者的配置進行劃分。
在小程序啟動時,默認會下載主包並啟動主包內頁面,當用戶用戶進入分包內某個頁面時,用戶端會把對應分包下載下來,下載完成後再進行展示。
現時小程序分包大小有以下限制:
- 整個小程序所有分包大小不超過24M。
- 單個分包/主包大小不能超過2M。
1.使用分包
1.1配置方法
假設支持分包的小程序目錄結構如下:
├── app.js
├── app.json
├── app.wxss
├── packageA
│ └── pages
│ ├── cat
│ └── dog
├── packageB
│ └── pages
│ ├── apple
│ └── banana
├── pages
│ ├── index
│ └── logs
└── utils開發者通過在app.json subpackages欄位聲明項目分包結構:
TIP
寫成subPackages也支持。
{
"pages":[
"pages/index",
"pages/logs"
],
"subpackages": [
{
"root": "packageA",
"pages": [
"pages/cat",
"pages/dog"
]
}, {
"root": "packageB",
"name": "pack2",
"pages": [
"pages/apple",
"pages/banana"
]
}
]
}subpackages中,每個分包的配置有以下幾項:
| 欄位 | 類型 | 說明 |
|---|---|---|
| root | String | 分包根目錄 |
| name | String | 分包別名,分包預下載 時可以使用 |
| pages | StringArray | 分包頁面路徑,相對於分包根目錄 |
| independent | Boolean | 分包是否是 獨立分包 |
1.2打包原則
- 聲明subpackages後,將按subpackages配置路徑進行打包,subpackages配置路徑外的目錄將被打包到主包中。
- 主包也可以有自己的pages,即最外層的pages欄位。
- subpackage的根目錄不能是另外一個subpackage內的子目錄。
- tabBar頁面必須在主包內。
1.3引用原則
- packageA無法require packageB JS文件,但可以require主包、packageA內的JS文件; 使用 分包非同步化 時不受此條限制。
- packageA無法import packageB的template,但可以require主包、packageA內的template。
- packageA無法使用packageB的資源,但可以使用主包、packageA內的資源。
2.獨立分包
獨立分包是小程序中一種特殊類型的分包,可以獨立於主包和其他分包運行從獨立分包中頁面進入小程序時,不需要下載主包當用戶進入普通分包或主包內頁面時,主包才會被下載。
開發者可以按需將某些具有一定功能獨立性的頁面配置到獨立分包中當小程序從普通的分包頁面啟動時,需要首先下載主包; 而獨立分包不依賴主包即可運行,可以很大程度上提升分包頁面的啟動速度。
一個小程序中可以有多個獨立分包。
2.1配置方法
假設小程序目錄結構如下:
├── app.js
├── app.json
├── app.wxss
├── moduleA
│ └── pages
│ ├── rabbit
│ └── squirrel
├── moduleB
│ └── pages
│ ├── pear
│ └── pineapple
├── pages
│ ├── index
│ └── logs
└── utils開發者通過在app.json的subpackages欄位中對應的分包配置項中定義independent欄位聲明對應分包為獨立分包。
{
"pages": [
"pages/index",
"pages/logs"
],
"subpackages": [
{
"root": "moduleA",
"pages": [
"pages/rabbit",
"pages/squirrel"
]
}, {
"root": "moduleB",
"pages": [
"pages/pear",
"pages/pineapple"
],
"independent": true
}
]
}2.2 限制
獨立分包屬於分包的一種普通分包的所有限制都對獨立分包有效獨立分包中自定義組件的處理管道同普通分包。
此外,使用獨立分包時要注意:
- 獨立分包中不能依賴主包和其他分包中的內容,包括js文件、 template、wxss、 自定義組件等(使用 分包非同步化時js文件、自定義組件不受此條限制);
- 主包中的app.wxss對獨立分包無效,應避免在獨立分包頁面中使用app.wxss中的樣式;
- App只能在主包內定義,獨立分包中不能定義App,會造成無法預期的行為;
2.3 注意事項
2.3.1 關於getApp()
與普通分包不同,獨立分包運行時,App並不一定被注册,囙此getApp()也不一定可以獲得App對象:
- 當用戶從獨立分包頁面啟動小程序時,主包不存在,App也不存在,此時調用getApp()獲取到的是undefined當用戶進入普通分包或主包內頁面時,主包才會被下載,App才會被注册。
- 當用戶是從普通分包或主包內頁面跳轉到獨立分包頁面時,主包已經存在,此時調用getApp()可以獲取到真正的App。
為了在獨立分包中滿足這一需求,getApp支持[allowDefault]參數,在App未定義時返回一個默認實現當主包加載,App被註冊時,默認實現中定義的内容會被覆蓋合併到真正的App中。
示例代碼:
- 獨立分包中
const app = getApp({ allowDefault: true }); // {}
app.data = 456;
app.global = {};- app.js中
App({
data: 123,
other: "hello",
});
console.log(getApp()); // {global: {}, data: 456, other: 'hello'}2.3.2 關於App生命週期
當從獨立分包啟動小程序時,主包中App的onLaunch和首次onShow會在從獨立分包頁面首次進入主包或其他普通分包頁面時調用。
由於獨立分包中無法定義App,小程序生命週期的監聽可以使用 wx.onAppShow, wx.onAppHide完成App上的其他事件可以使用 wx.onError, wx.onPageNotFound 監聽。
3. 分包預下載
開發者可以通過配置,在進入小程序某個頁面時,由框架自動預下載可能需要的分包,提升進入後續分包頁面時的啟動速度對於 獨立分包, ,也可以預下載主包
分包預下載現時只支持通過配置管道使用,暫不支持通過調用API完成。
TIP
vConsole裏有preloadSubpackages開頭的日誌資訊,可以用來驗證預下載的情况
3.1 配置方法
預下載分包行為在進入某個頁面時觸發,通過在app.json新增preloadRule配置來控制。
{
"pages": ["pages/index"],
"subpackages": [
{
"root": "important",
"pages": ["index"],
},
{
"root": "sub1",
"pages": ["index"],
},
{
"name": "hello",
"root": "path/to",
"pages": ["index"]
},
{
"root": "sub3",
"pages": ["index"]
},
{
"root": "indep",
"pages": ["index"],
"independent": true
}
],
"preloadRule": {
"pages/index": {
"network": "all",
"packages": ["important"]
},
"sub1/index": {
"packages": ["hello", "sub3"]
},
"sub3/index": {
"packages": ["path/to"]
},
"indep/index": {
"packages": ["__APP__"]
}
}
}preloadRule中,key是頁面路徑,value是進入此頁面的預下載配置,每個配置有以下幾項:
| 欄位 | 類型 | 必填 | 預設值 | 說明 |
|---|---|---|---|---|
| packages | StringArray | 是 | 無 | 進入頁面後預下載分包的root或name,__ APP__表示主包 |
| network | String | 否 | wifi | 在指定網絡下預下載,可選值為: 1.all: 不限網絡 2.wifi: 僅wifi下預下載 |
3.2 限制
同一個分包中的頁面享有共同的預下載大小限額2M,限額會在工具中打包時校驗。
如,頁面A和B都在同一個分包中,A中預下載總大小0.5M的分包,B中最多只能預下載總大小1.5M的分包。
4. 分包非同步化
在小程序中,不同的分包對應不同的下載單元; 囙此,除了非獨立分包可以依賴主包外,分包之間不能互相使用自定義組件或進行require「分包非同步化」特性將允許通過一些配置和新的接口,使部分跨分包的內容可以等待下載後非同步使用,從而一定程度上解决這個限制。
4.1 跨分包自定義組件引用
一個分包使用其他分包的自定義組件時,由於其他分包還未下載或注入,其他分包的組件處於不可用的狀態通過為其他分包的自定義組件設定 占位組件, ,我們可以先渲染占位組件作為替代,在分包下載完成後再進行替換例如:
// subPackageA/pages/index.json
{
"usingComponents": {
"button": "../../commonPackage/components/button",
"list": "../../subPackageB/components/full-list",
"simple-list": "../components/simple-list",
"plugin-comp": "plugin://pluginInSubPackageB/comp"
},
"componentPlaceholder": {
"button": "view",
"list": "simple-list",
"plugin-comp": "view"
}
}在這個配置中,button和list兩個自定義組件是跨分包引用組件,其中button在渲染時會使用內寘組件view作為替代,list會使用當前分包內的自定義組件simple-list作為替代進行渲染; 在這兩個分包下載完成後,占位組件就會被替換為對應的跨分包組件。
4.2 跨分包JS代碼引用
一個分包中的代碼引用其它分包的代碼時,為了不讓下載阻塞代碼運行,我們需要非同步獲取引用的結果如:
// subPackageA/index.js
// Use a callback function style call
require('../subPackageB/utils.js', utils => {
console.log(utils.whoami) // Wechat MiniProgram
}, ({mod, errMsg}) => {
console.error(`path: ${mod}, ${errMsg}`)
})
// Or use a Promise-style call
require.async('../commonPackage/index.js').then(pkg => {
pkg.getPackageName() // 'common'
}).catch(({mod, errMsg}) => {
console.error(`path: ${mod}, ${errMsg}`)
})詳情可參攷 模組化- require章節, ,我們可以先渲染占位組件作為替代,在分包下載完成後再進行替換例如: