上一篇文章《小程序性能优化全景指南》已经系统覆盖了性能优化的通用手段,本文聚焦分包加载与启动性能这条主线:当主包逼近 2MB 红线、冷启动明显变慢时,如何通过分包拆分、预下载、按需注入等技术把「首包体积」和「首屏耗时」降下来。内容包含分包原理、拆分策略、独立分包/异步分包、按需注入、资源优化与启动耗时分析工具,是对性能优化主题的纵深进阶。
一、分包原理与主包限制
1.1 体积红线
微信小程序对包体积有硬性限制:
| 限制项 | 数值 | 说明 |
|---|---|---|
| 单个主包/普通分包 | ≤ 2MB | 超出将无法上传 |
| 整个小程序 | ≤ 30MB | 主包 + 所有分包总和 |
| tabBar 页面 | 必须在主包 | 底部导航页不能分包 |
超过 2MB 主包的项目,唯一出路就是把非首屏页面拆进分包,让用户「先见主包、用到再下载分包」。
1.2 分包目录结构
// app.json
{
"pages": [
"pages/index/index",
"pages/cart/cart"
],
"subpackages": [
{
"root": "package-order",
"pages": [
"pages/list/list",
"pages/detail/detail",
"pages/refund/refund"
],
"name": "订单分包"
},
{
"root": "package-live",
"pages": [
"pages/room/room"
],
"independent": true,
"name": "直播独立分包"
}
]
}
项目根目录/
├── app.js / app.json / app.wxss
├── pages/ # 主包页面
├── package-order/ # 普通分包
│ └── pages/...
└── package-live/ # 独立分包
└── pages/...
一句话:主包只保留「首页可达路径」必需的页面与公共代码,其余按业务拆包,是分包优化的第一原则。
二、分包拆分策略
2.1 三种拆分视角
| 策略 | 做法 | 适用 |
|---|---|---|
| 按业务域 | 订单、商城、直播各一个分包 | 业务边界清晰 |
| 按访问频次 | 低频页面(规则、协议)拆独立包 | 低频长尾页面 |
| 按团队边界 | 团队 A/B 各维护一个分包 | 多团队协作 |
2.2 公共代码处理
- 公共组件/工具放主包:被多个分包共享的代码留在主包,避免重复。
- 分包内共享用分包内公共目录:分包内的公共代码放分包
root下自定义目录,不进主包。 - 避免主包引用分包资源:主包不能
require分包内的 JS(普通分包),需要时走「分包异步化」。
2.3 分包异步化
基础库 2.14.0+ 支持跨分包引用 JS 与组件,主包可以按需加载分包的代码:
// 主包页面中异步加载分包模块
wx.loadSubpackage({
name: 'package-order',
success() {
// 分包已加载完成,可安全跳转或调用
wx.navigateTo({ url: '/package-order/pages/detail/detail?id=1' });
},
fail(err) {
wx.showToast({ title: '模块加载失败', icon: 'none' });
}
});
三、分包预下载:preloadRule
3.1 配置预下载
preloadRule 用于在用户停留在某页面时,提前后台下载指定分包:
{
"pages": ["pages/index/index"],
"subpackages": [
{ "root": "package-order", "pages": ["pages/list/list"] },
{ "root": "package-community", "pages": ["pages/feed/feed"] }
],
"preloadRule": {
"pages/index/index": {
"network": "wifi", // all / wifi
"packages": ["package-order"] // 主包用 main,分包用 root 名
},
"pages/cart/cart": {
"network": "all",
"packages": ["package-order", "package-community"]
}
}
}
3.2 预下载策略要点
| 配置值 | 含义 | 建议 |
|---|---|---|
network: "wifi" | 仅 WiFi 下预下载 | 体积大的分包,省流量 |
network: "all" | 任意网络都预下载 | 用户很可能访问的分包 |
packages: ["main"] | 预下载主包 | 依赖主包的场景 |
预下载的本质是「用流量换速度」:从「点击才下载」变成「浏览时悄悄下载」,跳转命中时零等待。注意预下载只在配置的触发页面进入时执行,且同一时间预下载分包数有限制。
一句话:
preloadRule是体验与流量的权衡——把「用户下一步大概率进入的分包」在 WiFi 下预热,命中率决定收益。
四、独立分包与异步分包
4.1 独立分包
independent: true 的分包不依赖主包,可单独加载、直接成为入口(如扫码进入):
- 优势:进入独立分包页面时无需下载主包,启动更快。
- 代价:独立分包不能使用主包的页面、组件与 JS(除
app.js全局逻辑外),需要自带依赖。
{
"subpackages": [
{
"root": "package-live",
"pages": ["pages/room/room"],
"independent": true
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["package-live"]
}
}
}
4.2 异步分包与按需注入
「按需注入」通过 lazyCodeLoading 让自定义组件、页面 JS 在真正使用时才注入:
// app.json
{
"lazyCodeLoading": "requiredComponents"
}
开启后,启动阶段不再执行所有组件的 JS,只注入当前页面使用到的组件代码,显著缩短冷启动「代码注入」阶段耗时。配合「组件按需引用」,可将启动脚本执行量削减 30%-50%。
// 按需注册组件:仅当前页面用到才声明
// pages/index/index.json
{
"usingComponents": {
"product-card": "/components/product-card/index",
"heavy-chart": "/components/heavy-chart/index"
}
}
一句话:
lazyCodeLoading: "requiredComponents"是成本最低、收益最稳定的启动优化开关,任何项目都建议开启。
五、图片与字体优化
5.1 图片瘦身
- CDN 外置:所有业务图走云存储/自建 CDN,包内只留图标与占位图。
- 格式与尺寸:照片用 WebP/渐进式 JPEG,图标用压缩 PNG 或 SVG;按渲染尺寸的 2 倍输出,避免大图。
- 懒加载:
<image>组件lazy-load="{{true}}"。
<image
src="{{item.cover}}"
mode="aspectFill"
lazy-load="{{true}}"
bindload="onImageLoad"
/>
5.2 字体按需
中文自定义字体动辄数 MB,禁止直接打包:
- 系统字体栈优先:
-apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif。 - 特殊字体用
wx.loadFontFace从 CDN 异步加载,配合font-display效果避免阻塞渲染。 - 字符子集化:仅保留实际使用的汉字,可压缩到几十 KB。
wx.loadFontFace({
family: 'CustomFont',
source: 'url("https://cdn.example.com/fonts/regular.woff2")',
scopes: ['webview'],
success: () => console.log('字体加载成功')
});
六、渲染层性能进阶
6.1 setData 深度调优
- 合并多次
setData为一次;用路径式更新this.setData({ 'list[3].name': v })而非整表替换。 - 大列表配合虚拟列表(仅渲染可视区)与
wxs计算减少逻辑层往返。 - 纯数据字段用
options.pureDataPattern声明,避免触发无谓的渲染。
Component({
options: { pureDataPattern: /^_/ },
data: { list: [], _page: 1 }, // _page 不参与渲染
methods: {
onLoadMore() {
this.setData({ '_page': this.data._page + 1 });
}
}
});
6.2 骨架屏
首屏用骨架屏占位,内容到达后替换,降低「白屏焦虑」:
<view wx:if="{{loading}}" class="skeleton">
<view class="sk-banner"></view>
<view class="sk-line" wx:for="{{4}}"></view>
</view>
<view wx:else>...</view>
.sk-banner {
height: 320rpx;
border-radius: 16rpx;
background: linear-gradient(90deg, #f2f2f2 25%, #e8e8e8 50%, #f2f2f2 75%);
background-size: 200% 100%;
animation: shine 1.4s infinite;
}
@keyframes shine {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
一句话:渲染优化的两个杠杆是「减少 setData 数据量/频次」与「让用户在数据到来前看到占位」,前者治本、后者治感知。
七、启动耗时分析工具
7.1 开发者工具性能面板
微信开发者工具「调试器 → Performance / 性能」面板可记录:
- 启动耗时:小程序启动到首个页面
onReady的耗时。 - 脚本注入耗时:JS 代码解析与执行的时长(受分包与
lazyCodeLoading影响最大)。 - setData 耗时:每次数据更新的传输与渲染成本。
7.2 真机与线上指标
真机环境与工具差异明显,需要采集线上指标:
// utils/perf.js —— 上报关键指标
function reportLaunch() {
const perf = wx.getPerformance();
const nav = perf.getEntriesByType('navigation')[0];
wx.request({
url: 'https://analytics.example.com/perf',
method: 'POST',
data: {
launchDuration: nav?.duration ?? null, // 启动总耗时
codeExecTime: nav?.scriptExecutionDuration ?? null,
ttfb: nav?.responseStart ?? null,
networkType: wx.getNetworkTypeSync()?.networkType
}
});
}
App({
onLaunch() {
// 首帧渲染完成后上报
const page = getCurrentPages()[0];
page?.onReady ? setTimeout(reportLaunch, 0) : wx.nextTick(reportLaunch);
}
});
7.3 微信公众平台「性能」看板
已发布的小程序可在「微信公众平台 → 统计 → 性能分析」查看线上启动耗时分布,按机型/地区/网络类型切片,定位真实用户的性能瓶颈。
| 指标 | 工具 | 优化关联 |
|---|---|---|
| 首包体积 | 开发者工具「代码依赖分析」 | 分包拆分、资源外置 |
| 冷启动耗时 | Performance 面板 | 按需注入、预下载 |
| 脚本执行耗时 | Performance 面板 | lazyCodeLoading、代码精简 |
| 真机启动分布 | 公众平台性能看板 | 线上回归验证 |
八、常见问题
- 上传报主包超限:先看「代码依赖分析」找出大文件,图片、字体、地图 SDK 是头号嫌疑。
- 分包页面找不到:确认页面路径写在对应分包的
pages中,且root路径拼写一致。 - 独立分包调用主包组件报错:独立分包不能依赖主包资源,需把依赖下沉到独立分包内。
- 预下载不生效:
preloadRule必须在app.json,触发页面路径必须是真实存在的页面。 loadSubpackage重复加载:success中先判断wx.getSubpackageList是否已加载再触发。
九、总结
| 环节 | 方案 | 核心收益 |
|---|---|---|
| 体积红线 | 主包 ≤2MB / 总 ≤30MB | 明确拆分目标 |
| 拆分策略 | 按业务/频次/团队拆包 | 主包瘦身 |
| 预下载 | preloadRule | 跳转零等待 |
| 独立分包 | independent: true | 入口直达、免主包 |
| 按需注入 | lazyCodeLoading | 启动代码量骤降 |
| 资源优化 | CDN 图片 / 子集字体 | 包体积与内存双降 |
| 渲染调优 | setData 路径更新 + 骨架屏 | 首屏体验 |
| 性能分析 | 工具面板 + 线上看板 | 数据驱动优化 |
分包加载与启动性能优化,本质是「首包最小化 + 用时再加载」的工程哲学。以 2MB 主包红线为约束、以 preloadRule 预下载为加速器、以 lazyCodeLoading 按需注入为减负开关,配合资源外置与渲染调优,再用工具面板与线上看板量化验证,就能把冷启动时间持续压向体验红线以内。更完整的性能维度可回顾性能优化全景指南。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。