# 小程序分包
某些情况下,开发者需要将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。
在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包小程序必定含有一个主包。所谓的主包,即放置默认启动页面/*TabBar* 页面,以及一些所有分包都需用到公共资源/*JS* 脚本;而分包则是根据开发者的配置进行划分。
在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。
目前小程序分包大小有以下限制:
- 整个小程序所有分包大小不超过 *20M*
- 单个分包/主包大小不能超过 *2M*
对小程序进行分包,可以优化小程序首次启动的下载时间,以及在多团队共同开发时可以更好的解耦协作。
官方所提供的文档分为如下 *3* 个内容:
- 使用分包
- 独立分包
- 分包预加载
所以这里不再照搬官网做介绍,详细了可以参阅官方文档:*https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages.html*
本文我们主要来看一下分包的实际操作。
这里以【*applet-subcontracting*】项目为例。
根据官网的介绍,分包主要是将小程序的页面进行分门别类,例如:
```js
├── app.js
├── app.json
├── app.wxss
├── packageA
│ └── pages
│ ├── cat
│ └── dog
├── packageB
│ └── pages
│ ├── apple
│ └── banana
├── pages
│ ├── index
│ └── logs
└── utils
```
然后在 *app.json* 文件中使用 *subpackages* 字段来声明项目分包结构:
```js
{
"pages":[
"pages/index",
"pages/logs"
],
"subpackages": [
{
"root": "packageA",
"pages": [
"pages/cat",
"pages/dog"
]
}, {
"root": "packageB",
"name": "pack2",
"pages": [
"pages/apple",
"pages/banana"
]
}
]
}
```
*subpackages* 字段对应的值为一个数组,数组里面记录了分几个包,每个包对应一个对象,对象可以设置如下的属性值。如下:

来看【*applet-subcontracting*】项目实际的操作示例。
首先是我们的项目目录,以前我们所有的页面,都是放在 *pages* 目录下面的。现在要进行分包的话,虽然也都是放在 *pages* 目录下,但是 *pages* 目录下面又分为了 *package1、package2* 和 *package3*。
这里我们其实就是分成了 *3* 个包,每个包有自己的目录,展开后如下图所示:
接下来我们就需要在 *app.json* 里面进行配置了。配置代码片段如下:
```js
{
"pages":[
"pages/package1/pages/index/index",
"pages/package1/pages/cat/cat",
"pages/package1/pages/dog/dog",
"pages/package1/pages/apple/apple",
"pages/package1/pages/banana/banana"
],
"subpackages": [
{
"root": "pages/package2",
"name": "pack2",
"pages": [
"pages/cat/cat",
"pages/dog/dog"
]
}, {
"root": "pages/package3",
"name": "pack3",
"pages": [
"pages/apple/apple",
"pages/banana/banana"
]
}
],
// ...
}
```
可以看到,*pages* 里面配置第一次要加载的页面,这里我们加载的是 *package1* 里面的所有页面。
而 *package2* 和 *package3* 则采取的是分包的形式,被写入到了 *subpackages* 里面。
在开发工具的详情中,可以看到当前的分包情况,如下图所示:
### 独立分包
独立分包就是这个包是独立的,不依赖于主包就能用,当设置为独立分包时,我们从独立分包进入不会加载主包,只有进入主包页面或者非独立分包页面是才加载主包。
使用的方法也很简单,只需要在配置包的时候,把 *independent* 设置为 *true* 就会成为独立分包。
例如:
```js
{
// ...
"subpackages": [{
"root": "pages/package2",
"name": "pack2",
"pages": [
"pages/cat/cat",
"pages/dog/dog"
],
"independent": true
}, {
"root": "pages/package3",
"name": "pack3",
"pages": [
"pages/apple/apple",
"pages/banana/banana"
]
}],
// ...
}
```
在上面的代码中,我们将 *pack2* 设置为了独立分包。
独立分包注意事项:
- 从独立分包进入的时候,由于没有加载主包,因此通过 *getApp* 方法拿到的是 *undefined*。只有在加载主包回来这个页面以后才能通过 *getApp* 拿到全局参数。
- 独立分包不能共享其他包样式,包括 *app.wxss* 样式。
- 独立分包不支持使用插件
- 在低于 *6.7.2* 的微信版本的小程序独立分包当成普通分包对待,不具备独立分包的能力。
为了兼容独立分包进入无法全局管理变量的能力,官方在基础版本库 *2.4.4* 以后做了兼容,使用 *getApp({allowDefault: true})* 可以预先写入变量,当主包加载的时候会同步到 *app* 里面。
```js
const app = getApp({allowDefault: true});
app.aa = 1; // 等主包加载的时候会同步进去
```
### 分包预加载
所谓分包预加载,就是在进入小程序某个页面时,由框架自动预下载可能需要的分包,提升进入后续分包页面时的启动速度。
例如:
```js
{
// ...
"preloadRule": {
"pages/package1/pages/cat/cat": {
"network": "all",
"packages": ["pack2"]
},
"pages/package1/pages/apple/apple": {
"network": "all",
"packages": ["pack3"]
}
},
// ...
}
```
在上面的配置中,表明进入 *cat* 页面时,就加载 *pack2* 这个包,进入 *apple* 这个页面时,就加载 *pack3* 这个包。
而 *network* 对应的 *all* 代表在指定网络下预下载,可选值有 *all*(不限网络)和 *wifi*(仅 *wifi* 下预下载)。
## 分包异步化
在小程序中,不同的分包**对应不同的下载单元**。
不同的包之间无法相互使用自定义组件或者 require。
```js
subpackA
item 自定义组件
subpackB
```
**跨分包自定义组件引用(占位渲染)**
有点类似于骨架屏,先用内置组件或者本包中的组件进行一个占位渲染,之后在其他包加载之后再渲染为对应的组件。
要使用此特性,直接在当前包对应的 json 文件中进行配置即可:
```js
{
"componentPlaceholder": {
"button": "view",
"list": "simple-list"
}
}
```
**跨分包 JS 代码引用**
在当前包如果要使用其他包的代码,首先通过 require 来引入,然后注意这个过程是异步的。
-*EOF*-