分包要解决什么:主包为什么会越来越大

小程序有一道硬门槛:主包体积超过一定上限就传不上去,而且主包越大,冷启动越慢——用户要等整包下载完才能看到第一个页面。很多团队做着做着就发现,首页其实只用到两三个模块,却把整个商城、个人中心、设置页全塞进了主包。分包,就是把不该跟着首屏一起下载的部分,拆出去按需加载。

分包的思路一句话:把页面按访问路径切开,主包只留启动和 Tab 必需的部分,其余页面放进各自的分包,用到哪个分包才下载哪个。用户从首页点进二级页时,对应的分包才开始下载,首屏因此快了一大截。

分包不是优化技巧,而是小程序工程的默认结构。
本文核心知识点
  • 分包结构用 subPackages 把页面按目录拆成多个包。
  • 独立分包不依赖主包就能单独启动,适合活动页。
  • 分包预下载在合适时机提前下载下一跳的分包。
  • 主包瘦身把资源和代码挪出主包,给冷启动减负。
小程序分包加载示意:蓝调渐变背景上一个居中主模块向外拆分出多个子包模块的扁平科技插画
把一个大包子拆成多个小包子:主包负责启动,分包负责按需加载。

分包的基本结构:app.json 里怎么配

分包在 app.json 里用 subPackages 字段声明。每个分包给一个 root 目录和这个目录下的页面列表。主包里放 Tab 页和启动页,其余按业务模块切分。

// app.json
{
  "pages": [
    "pages/home/home",
    "pages/mine/mine"
  ],
  "subPackages": [
    {
      "root": "pkg-order",
      "pages": ["list/list", "detail/detail"]
    },
    {
      "root": "pkg-user",
      "pages": ["profile/profile", "setting/setting"]
    }
  ]
}

分包划分的几个原则:

做法说明
按业务模块切订单一个包、用户中心一个包,互不串门
主包留 TabTabBar 页面必须在主包
公共资源抽离多个分包都用的组件放到主包或单独分包

独立分包:从哪里都能进

普通分包依赖主包,必须先下载主包才能进。但有些页面——比如一个活动页、一个分享落地页——用户可能直接从分享卡片打开,根本没进过首页。这时候用独立分包,让它不依赖主包,单独启动。

// app.json:独立分包标记 independent
{
  "root": "pkg-activity",
  "pages": ["promo/promo"],
  "independent": true
}

独立分包特别适合那种「只靠分享卡片进来」的场景:一个限时活动,用户从朋友转发的卡片直接点开,不需要先加载你的首页。它省掉了主包这一步,打开速度明显更快。

独立分包的代价是:它不能用主包里的公共组件和工具函数。所以独立分包要尽量自包含,把依赖的东西自己带齐。它特别适合一次性的活动页。

分包预下载:在该用之前先下好

分包第一次被点进去时才下载,用户会愣一下。分包预下载就是在用户还停留在上一页时,后台悄悄把下一跳的分包下好,点进去时已经就绪。

// app.json:进入首页时预下载订单分包
{
  "preloadRule": {
    "pages/home/home": {
      "network": "wifi",
      "packages": ["pkg-order"]
    }
  }
}

预下载的分寸:

  • 只预下载「下一步大概率去」的分包,别全下。
  • network 设成 wifi,弱网下别偷偷耗用户流量。
  • 预下载是体验优化,不要依赖它做必须的数据准备。

主包瘦身:把代码和资源挪出去

拆完分包还要回头给主包减重。主包里塞着的图片、字体、第三方库,是冷启动的隐形负担。

  • 大图上 CDN,包内只留极小的占位图。
  • 只在二级页用的组件,挪到对应分包里。
  • 工具函数按需引入,别整库 import。
// 按需引入,避免整库打包进主包
import debounce from "lodash/debounce";
// 而不是:import _ from "lodash";

主包每瘦一 KB,冷启动就快一点,这是最实在的收益。

另外,分包之间不要互相引用对方的页面或组件,否则微信会把被引用的包又算回主包,分包就白拆了。跨分包共享的东西,要么放在主包,要么单独抽成一个公共分包,让大家都依赖它而不是互相依赖。