某些情况下,开发者需要将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。
在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包小程序必定含有一个主包。
所谓的主包,即放置默认启动页面/TabBar页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。
在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。
目前小程序分包大小有以下限制:
整个小程序所有分包大小不超过 20M
单个分包/主包大小不能超过 2M
对小程序进行分包,可以优化小程序首次启动的下载时间,以及在多团队共同开发时可以更好的解耦协作。

(1)声明分包
在app.json的subpackages字段声明项目分包结构:
{
"pages":[ 主包
"pages/index",
"pages/logs"
],
"subpackages": [ 分包
{
"root": "packageA",
"pages": [
"pages/cat", 相对于root分包的路径
"pages/dog"
]
}, {
"root": "packageB",
"name": "pack2",
"pages": [
"pages/apple",
"pages/banana"
]
},
{
root:分包根目录
name:分包别名,分包预下载时可以使用
pages:分包页面路径数组,相对与分包根目录
independent:true|false分包是否是独立分包
}
]
}
其中:
声明subpackages后,将按subpackages配置路径进行打包,subpackages配置路径外的目录将被打包到主包中
subpackage的根目录不能是另外一个subpackage内的子目录
tabBar页面必须在主包内
引用原则:
对于js、template、资源
packageA无法require packageB的,但可以require app、自己package内的(对于js文件:使用分包异步化时不受此条限制)
(2)独立分包
独立分包是小程序中一种特殊类型的分包,可以独立于主包和其他分包运行。
从独立分包中页面进入小程序时,不需要下载主包。当用户进入普通分包或主包内页面时,主包才会被下载。
{
"pages": [
"pages/index",
"pages/logs"
],
"subpackages": [ {
"root": "moduleB",
"pages": [
"pages/pear",
"pages/pineapple"
],
"independent": true
}
]
}
其中:
.普通分包的所有限制都对独立分包有效
.独立分包中不能依赖主包和其他分包中的内容,包括js文件、template、wxss、自定义组件、插件等(使用分包异步化时js文件、自定义组件、插件不受此条限制)
.主包中的app.wxss对独立分包无效,应避免在独立分包页面中使用app.wxss中的样式;
.App只能在主包内定义,独立分包中不能定义App,会造成无法预期的行为;
.独立分包中暂时不支持使用插件。
1、独立分包中全局变量共享
与普通分包不同,独立分包运行时,App并不一定被注册,因此getApp()也不一定可以获得App对象
当用户从独立分包页面启动小程序时,主包不存在,App也不存在,此时调用getApp()获取到的是undefined。
当用户进入普通分包或主包内页面时,主包才会被下载,App才会被注册。
当用户是从普通分包或主包内页面跳转到独立分包页面时,主包已经存在,此时调用getApp()可以获取到真正的App。
独立分包中
const app = getApp({allowDefault: true})
app.data = 456
app.global = {}
app.js中
App({
data: 123,
other: 'hello'
})
console.log(getApp()) 可以获得独立分包中设置的全局数据,会覆盖掉当前文件中设置的相同变量
2、独立分包的生命周期
当从独立分包启动小程序时,主包中App的onLaunch和首次onShow会在从独立分包页面首次进入主包或其他普通分包页面时调用。
由于独立分包中无法定义App,小程序生命周期的监听可以使用wx.onAppShow,wx.onAppHide完成。
App上的其他事件可以使用wx.onError,wx.onPageNotFound监听
(3)分包预下载
在进入小程序某个页面时,由框架自动预下载可能需要的分包,对于独立分包,也可以预下载主包。
{
"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", all不限网络、wifi:仅wifi下预下载
"packages": ["important"] 可以是分包的root或name
},
"sub1/index": {
"packages": ["hello", "sub3"]
},
"sub3/index": {
"packages": ["path/to"]
},
"indep/index": {
"packages": ["__APP__"] __APP__ 表示主包。
}
}
}
其中:
同一个分包中的页面享有共同的预下载大小限额2M,限额会在工具中打包时校验。
页面A和B都在同一个分包中,A中预下载总大小0.5M的分包,B中最多只能预下载总大小1.5M的分包。
(4)分包异步化
在小程序中,不同的分包对应不同的下载单元;因此,除了非独立分包可以依赖主包外,分包之间不能互相使用自定义组件或进行require。
「分包异步化」特性将允许通过一些配置和新的接口,使部分跨分包的内容可以等待下载后异步使用,从而一定程度上解决这个限制。
1、组件共享
一个分包使用其他分包的自定义组件时,由于其他分包还未下载或注入,其他分包的组件处于不可用的状态。
通过为其他分包的自定义组件设置占位组件,我们可以先渲染占位组件作为替代,在分包下载完成后再进行替换。
subPackageA/pages/index.json
{
"usingComponents": {
"button": "../../commonPackage/components/button", 跨分包引用组件
"list": "../../subPackageB/components/full-list", 跨分包引用组件
"simple-list": "../components/simple-list" 自身包组件
},
"componentPlaceholder": {
"button": "view", 占位组件
"list": "simple-list" 占位组件,在分包下载完成后,占位组件就会被替换为对应的跨分包组件。
}
}
2、js共享
require('../subPackageB/utils.js', utils => {
console.log(utils.whoami) // Wechat MiniProgram
})
或者使用 Promise 风格的调用
require.async('../commonPackage/index.js').then(pkg => {
pkg.getPackageName() // 'common'
})
其他分包的插件中暴露的接口
requirePlugin('live-player-plugin', livePlayer => {
console.log(livePlayer.getPluginVersion())
})
或者使用 Promise 风格的调用
requirePlugin.async('live-player-plugin').then(livePlayer => {
console.log(livePlayer.getPluginVersion())
})