第5章 5.2 小程序分包加载
🎯 上一章我们搞定了微信小程序的原生能力,像是获取用户信息、地理位置这些"手机自带的功能"。但你有没有遇到过这种情况——小程序功能越加越多,安装包越来越大,用户点开转圈转半天,最后直接跑了?
这就是这一章要解决的问题:小程序分包加载。
说白了,就是让小程序"化整为零",该用的功能才加载,不用先不加载。用户点进来秒开,体验直接拉满。
🎯 开场 3 分钟:为什么要学这个?
场景带入
你做了一个"校园二手交易"小程序,功能模块有:
- 首页商品列表
- 发布商品
- 消息聊天
- 个人中心
- 管理员后台
结果安装包 5MB,用户打开要等 8 秒,点击"我的"直接卡住...
痛点来了:
1. 小程序主包超过 2MB 直接审核被拒
2. 功能全塞主包,加载慢到哭
3. 用户只用到 1 个功能,却要等所有功能都加载完
学完本文能解决
- ✅ 主包超 2MB 被拒的问题(拆成多个分包)
- ✅ 首屏加载慢的问题(按需加载)
- ✅ 用户只用到部分功能却\n\n
\n\n
\n\n要全部下载的问题
🧱 基础 25 分钟:核心概念
5.2.1 什么是分包?
生活类比:
想象你去住酒店。酒店主包(主楼)只提供前台、走廊这些基础服务。你的房间在副楼(分包),健身房在另一栋楼(另一个分包)。你入住的时候不需要等所有设施都准备好,只用拿到你的房间钥匙就行。
小程序的分包就是这样:
- 主包:小程序的"骨架",包含启动画面、首页、所有页面都需要的公共资源
- 分包:各个功能模块,按需加载
5.2.2 为什么要用分包?
3 个必须用分包的场景:
| 场景 | 不用分包 | 用分包 |
|---|---|---|
| 安装包 3MB+ | 直接被微信拒绝上架 | 拆成 3 个 1MB 分包,秒过审 |
| 功能模块独立 | 全量下载,加载 8 秒 | 按需加载,2 秒进首页 |
| 多人协作开发 | 合并代码冲突到崩溃 | 每人负责一个分包,互不干扰 |
5.2.3 怎么用分包?(uniapp 配置)
uniapp 配置分包只需要修改 manifest.json 和页面路径结构。
项目结构:
项目根目录/
├── pages/ # 主包页面
│ ├── index/
│ │ └── index.vue
│ └── manifest/
│ └── manifest.vue
├── pages-subpack/ # 👈 分包目录(注意这个目录名)
│ ├── goods/ # 👈 商品分包
│ │ └── list.vue
│ └── chat/ # 👈 聊天分包
│ └── index.vue
└── manifest.json
步骤 1:在 manifest.json 配置分包
{
"mp-weixin": {
"optimization": {
"subPackages": true
}
}
}
这行配置告诉 uniapp:"我要用分包功能,给我打开开关。"
步骤 2:在 pages.json 配置分包路径
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
}
],
"subPackages": [
{
"root": "pages-subpack/goods",
"pages": [
{
"path": "list",
"style": {
"navigationBarTitleText": "商品列表"
}
}
]
},
{
"root": "pages-subpack/chat",
"pages": [
{
"path": "index",
"style": {
"navigationBarTitleText": "消息"
}
}
]
}
]
}
代码解释:
- subPackages:分包的配置数组
- root:分包的根目录路径(相对于项目根目录)
- pages:该分包下的页面列表
5.2.4 分包的加载规则
生活类比:
你去医院看病,主楼(主包)有挂号和分诊台。你跟护士说"我要看眼科",护士指给你"眼科在东院区 3 楼"——这时候才会去眼科(分包)。
小程序的加载规则:
1. 用户打开小程序,先加载主包
2. 主包加载完成后,按需加载用户访问的页面所在分包
3. 已加载的分包会被微信缓存,下次访问直接用
5.2.5 独立分包(高级配置)
什么是独立分包?
普通分包依赖主包,但独立分包可以独立运行!
生活类比:
普通分包像是酒店的房间——你得先经过大堂(主包)才能进房间。
独立分包像是民宿——你有钥匙就能直接进,不用经过酒店前台。
使用场景:
- 广告页、启动页(用户强点广告直接进,不用等主包)
- 分享裂变页(扫码直接进指定页面)
配置独立分包:
{
"subPackages": [
{
"root": "pages-subpack/ad",
"pages": [
{
"path": "splash",
"style": {
"navigationBarTitleText": "广告页"
}
}
],
"independent": true // 👈 加这个配置
}
]
}
关键就在 independent: true 这一行。
5.2.6 分包预下载
什么是分包预下载?
用户在浏览首页时,偷偷提前把可能用到的分包下载好。
生活类比:
你去超市之前,老婆已经在手机上看好要买什么、放在哪个货架。到了超市你直接拿,不用满超市找。
配置预下载:
在 pages.json 的 preloadRule 节点配置:
{
"preloadRule": {
"pages/index/index": { // 触发预下载的页面
"network": "all", // 在什么网络下预下载:all=所有网络,wifi=仅WiFi
"packages": ["pages-subpack/goods"] // 预下载哪个分包
}
}
}
代码解释:
- pages/index/index:当用户访问首页时
- packages:自动下载这个分包
🔥 实战 35 分钟:3 个递进的小项目
项目 1:基础分包配置(5 分钟)
目标: 把一个商品列表页面拆成分包,理解最基础的分包结构。
完整代码:
项目结构:
├── pages/
│ └── index/
│ └── index.vue
├── pages-subpack/
│ └── product/
│ └── list.vue
├── manifest.json
└── pages.json
manifest.json:
{
"mp-weixin": {
"optimization": {
"subPackages": true
}
}
}
pages.json:
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
}
],
"subPackages": [
{
"root": "pages-subpack/product",
"pages": [
{
"path": "list",
"style": {
"navigationBarTitleText": "商品列表"
}
}
]
}
]
}
pages/index/index.vue:
<template>
<view class="container">
<text class="title">校园二手市场</text>
<button type="primary" @tap="goToProductList">浏览商品</button>
</view>
</template>
<script>
export default {
methods: {
goToProductList() {
uni.navigateTo({
url: '/pages-subpack/product/list'
});
}
}
}
</script>
<style>
.container {
padding: 20px;
}
.title {
font-size: 24px;
display: block;
margin-bottom: 20px;
}
</style>
pages-subpack/product/list.vue:
<template>
<view class="container">
<text class="title">商品列表(分包页面)</text>
<view v-for="item in products" :key="item.id" class="product-item">
<text>{{ item.name }} - ¥{{ item.price }}</text>
</view>
</view>
</template>
<script>
export default {
data() {
return {
products: [
{ id: 1, name: '二手自行车', price: 200 },
{ id: 2, name: '教科书', price: 30 },
{ id: 3, name: '台灯', price: 50 }
]
}
}
}
</script>
<style>
.container {
padding: 20px;
}
.title {
font-size: 18px;
display: block;
margin-bottom: 15px;
}
.product-item {
padding: 10px;
border-bottom: 1px solid #eee;
}
</style>
预期输出:
点击"浏览商品"按钮 → 跳转到商品列表页(显示 3 个商品)
一句话解释: uni.navigateTo 跳转到分包页面时,微信会自动先加载该分包。
项目 2:带预下载的商品列表(15 分钟)
目标: 从本地 JSON 文件读取商品数据,并配置分包预下载。
需求:
1. 商品数据放在 static/data/products.json
2. 首页访问时预加载商品分包
3. 点击按钮展示商品列表
static/data/products.json:
[
{ "id": 1, "name": "二手自行车", "price": 200, "seller": "小明" },
{ "id": 2, "name": "高等数学教科书", "price": 30, "seller": "小红" },
{ "id": 3, name": "小米台灯", "price": 50, "seller": "小刚" },
{ "id": 4, "name": "AirPods Pro", "price": 600, "seller": "阿华" },
{ "id": 5, "name": "机械键盘", "price": 250, "seller": "阿杰" }
]
pages.json(加入预下载配置):
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
}
],
"subPackages": [
{
"root": "pages-subpack/product",
"pages": [
{
"path": "list",
"style": {
"navigationBarTitleText": "商品列表"
}
}
]
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["pages-subpack/product"]
}
}
}
pages-subpack/product/list.vue(读取 JSON 数据):
<template>
<view class="container">
<text class="title">商品列表(从JSON加载)</text>
<view v-for="item in products" :key="item.id" class="product-item">
<text class="product-name">{{ item.name }}</text>
<text class="product-price">¥{{ item.price }}</text>
<text class="product-seller">卖家:{{ item.seller }}</text>
</view>
</view>
</template>
<script>
export default {
data() {
return {
products: []
}
},
onLoad() {
this.loadProducts();
},
methods: {
loadProducts() {
// 读取静态 JSON 文件
uni.request({
url: '/static/data/products.json',
success: (res) => {
this.products = res.data;
},
fail: () => {
console.error('加载商品数据失败');
}
});
}
}
}
</script>
<style>
.container {
padding: 20px;
}
.title {
font-size: 18px;
display: block;
margin-bottom: 15px;
}
.product-item {
padding: 15px;
border-bottom: 1px solid #eee;
display: flex;
flex-direction: column;
}
.product-name {
font-size: 16px;
font-weight: bold;
}
.product-price {
color: #ff6000;
margin-top: 5px;
}
.product-seller {
color: #888;
font-size: 12px;
margin-top: 5px;
}
</style>
预期输出:
进入商品列表页后,页面展示 5 个商品,每个显示名称、价格、卖家。
一句话解释: uni.request 从本地 static 目录读取 JSON 数据,加载到页面渲染。
项目 3:分类浏览 + 预下载(15 分钟)
目标: 实现一个分类浏览工具,用户点击不同分类只加载该分类的商品。
需求:
1. 首页显示"数码产品""图书""生活用品"3 个分类按钮
2. 每个分类是一个独立分包
3. 点击分类时预下载对应分包
新增 pages-subpack/digital/list.vue:
<template>
<view class="container">
<text class="title">数码产品</text>
<view v-for="item in products" :key="item.id" class="product-item">
<text>{{ item.name }} - ¥{{ item.price }}</text>
</view>
<button @tap="goBack">返回首页</button>
</view>
</template>
<script>
export default {
data() {
return {
products: [
{ id: 1, name: 'AirPods Pro', price: 600 },
{ id: 2, name: '机械键盘', price: 250 },
{ id: 3, name: '小米手环', price: 150 }
]
}
},
methods: {
goBack() {
uni.navigateBack();
}
}
}
</script>
<style>
.container { padding: 20px; }
.title { font-size: 18px; display: block; margin-bottom: 15px; }
.product-item { padding: 10px; border-bottom: 1px solid #eee; }
</style>
pages/index/index.vue(分类选择):
<template>
<view class="container">
<text class="title">校园二手市场</text>
<text class="subtitle">选择分类浏览</text>
<button @tap="goCategory('digital')">📱 数码产品</button>
<button @tap="goCategory('book')">📚 图书</button>
<button @tap="goCategory('life')">🏠 生活用品</button>
</view>
</template>
<script>
export default {
methods: {
goCategory(category) {
if (category === 'digital') {
uni.navigateTo({ url: '/pages-subpack/digital/list' });
} else if (category === 'book') {
uni.navigateTo({ url: '/pages-subpack/book/list' });
} else if (category === 'life') {
uni.navigateTo({ url: '/pages-subpack/life/list' });
}
}
}
}
</script>
<style>
.container { padding: 20px; text-align: center; }
.title { font-size: 24px; display: block; margin-bottom: 10px; }
.subtitle { font-size: 14px; color: #888; display: block; margin-bottom: 30px; }
button { margin: 10px 0; }
</style>
pages.json(配置多个分包 + 预下载):
{
"pages": [
{
"path": "pages/index/index",
"style": { "navigationBarTitleText": "首页" }
}
],
"subPackages": [
{
"root": "pages-subpack/digital",
"pages": [{ "path": "list", "style": { "navigationBarTitleText": "数码产品" } }]
},
{
"root": "pages-subpack/book",
"pages": [{ "path": "list", "style": { "navigationBarTitleText": "图书" } }]
},
{
"root": "pages-subpack/life",
"pages": [{ "path": "list", "style": { "navigationBarTitleText": "生活用品" } }]
}
],
"preloadRule": {
"pages/index/index": {
"network": "wifi",
"packages": ["pages-subpack/digital", "pages-subpack/book", "pages-subpack/life"]
}
}
}
预期输出:
首页点击"📱 数码产品" → 跳转到数码列表页,显示 AirPods Pro、机械键盘、小米手环。
一句话解释: 多个分包可以并行预下载,用户 WiFi 环境下打开首页时,后台静默下载所有分类分包。
💪 进阶 20 分钟:常见坑 + 性能小贴士
❌ 坑 1:路径写错了,页面打不开
错误示例:
{
"root": "pages-subpack/goods", // 注意不是 pages-subpack-goods
"path": "list" // 实际文件是 list.vue,这里只写文件名不加后缀
}
正确示例:
{
"root": "pages-subpack/goods",
"pages": [
{ "path": "list" }
]
}
注意! root 路径最后不要加 /,path 只写文件名不含 .vue。
❌ 坑 2:主包页面引用分包资源
错误示例(主包直接 import 分包里的文件):
// ❌ 主包的 pages/index/index.vue
import goodsList from '@/pages-subpack/goods/list.vue' // 不允许!
正确做法: 主包和分包之间不能直接引用,只能用 uni.navigateTo 跳转页面。
❌ 坑 3:独立分包用了主包的公共资源
错误示例:
独立分包里用了 common/style.css(主包的公共样式),独立分包加载时会找不到。
正确做法: 独立分包如果要样式,把样式文件放独立分包自己的目录里。
❌ 坑 4:预下载分包数量超限
微信限制一次预下载不能超过 3 个分包。
错误示例:
"packages": ["分包A", "分包B", "分包C", "分包D"] // ❌ 超过3个
正确做法: 只预下载用户最可能访问的 2-3 个分包。
❌ 坑 5:分包页面用 getApp() 获取全局状态
错误示例:
// 分包页面里
const app = getApp();
app.globalData.userInfo // ❌ 独立分包里可能拿不到
正确做法: 分包页面用 uni.getStorageSync('userInfo') 或在 onLoad 里通过参数传递。
✅ 性能小优化:分包懒加载
默认分包是懒加载(用到才下载),但可以显式配置:
"preloadRule": {
"pages/index/index": {
"network": "wifi",
"packages": ["pages-subpack/goods"] // 实际上这行已经足够了
}
}
如果想更激进地优化,用 uni.preloadSubPackage API 在特定时机预加载:
// 当用户停留在首页超过 3 秒时,偷偷预加载
setTimeout(() => {
uni.preloadSubPackage({
name: 'goods',
success: () => console.log('商品分包预加载成功')
});
}, 3000);
🔍 调试技巧:查看分包加载信息
在微信开发者工具里,打开「详情」→「项目配置」→「调试器」:
输入以下命令查看分包信息:
wx.getSubpackageInfo() // 查看已加载的分包
或者在控制台查看 Network 面板,找 __WEGAME_SUBPACKAGE__ 开头的请求,就是分包加载的请求。
✏️ 练习题 + 作业题
练习题(10 分钟)
练习 1(2 分钟):修改分包路径
- 输入:把 pages-subpack/goods/list 改成 pages-subpack/product/list
- 预期输出:pages.json 配置正确,路径能正常跳转
- 提示:修改 root 字段和实际文件夹名称
练习 2(2 分钟):添加一个新分类
- 输入:在项目 3 基础上新增"服装"分类分包
- 预期输出:首页点击"👕 服装"能跳转到服装列表
- 提示:需要新增文件夹、配置 pages.json、新增按钮
练习 3(2 分钟):修改预下载网络条件
- 输入:把预下载从 wifi 改成 all
- 预期输出:手机流量环境下也能预下载
- 提示:只改 preloadRule 里的 network 字段
练习 4(2 分钟):给独立分包加配置
- 输入:把练习 2 的服装分包改成独立分包
- 预期输出:配置里多了 "independent": true
- 提示:在该分包的配置对象里加一个 independent 字段
练习 5(2 分钟):找错
- 输入:以下配置哪里有问题?
{
"root": "pages-subpack/goods",
"pages": [
{ "path": "list.vue" }
]
}
- 预期输出:指出 path 不应该加
.vue后缀 - 提示:path 只写文件名
作业题(30 分钟-2 小时)
作业:做一个「校园服务小程序分包版」
- 需求描述:做一个校园服务合集小程序,包含多个互不相关的功能
- 功能点:
1. 主包:首页,显示功能入口
2. 分包 A:快递查询(输入单号查询物流)
3. 分包 B:课表查询(显示周一到周五的课程)
4. 分包 C:校园公告(列表 + 点击查看详情) - 加分项:
1. 配置快递分包的预下载
2. 公告列表页用v-for循环渲染 - 验收标准:
- 三个分包都能正常跳转
- 每个分包有真实数据渲染(非空列表)
- 代码有适当注释说明分包结构
- 提交方式:评论区贴关键配置或 GitHub 链接
📚 总结 + 资源
本文学到的 3 个核心点:
1. 分包就是把小程序拆成"主包 + 多个功能包",按需加载
2. pages.json 的 subPackages 配置是分包的入口
3. preloadRule 可以让用户还没点之前就偷偷下载分包
延伸学习资源:
- uniapp 分包文档 - 官方配置参考
- 微信小程序分包加载指南 - 微信官方说明
- uniapp 性能优化实战 - 进阶优化技巧
互动钩子:
你在项目里用过分包吗?有没有遇到过审核被拒的情况?评论区聊聊,老粉优先回复!
📌 下章预告:学会了分包加载,下一章我们要解决"怎么让更多人用到你的小程序"——第5章 5.3 小程序发布流程,从开发到上架,一步步教你把作品发布到微信!

评论(0)