3、包体积优化(下):分包加载策略(主包/分包)、独立分包与预加载、分包体积监控

好,咱们接着聊包体积优化。上一节我把代码层面的压缩、图片优化、无用代码清理都讲了一遍。这一节,咱们要啃的是一块硬骨头——分包加载

说实话,我早期做小程序的时候,最头疼的就是那个2MB的主包限制。那时候功能一多,动不动就超限,每次提审都提心吊胆。后来我学乖了——分包才是根治包体积问题的终极方案。

主包与分包:核心逻辑

先搞清楚一个概念:小程序启动时,只会下载主包。主包里放什么?放那些必须第一时间展示的页面和公共资源。比如首页、登录页、核心的tabBar页面,还有全局通用的组件、工具库。

那分包呢?分包就是那些用户不一定马上用到的功能模块。比如商品详情页、订单列表、个人设置页。这些页面可以拆到不同的分包里,用户访问时才下载。

我个人的习惯是:主包控制在1.2MB以内,留出余量给后续迭代。分包每个控制在500KB左右,别太大,否则加载体验会变差。

来看一个典型的分包配置:

// app.json
{
  "pages": [
    "pages/index/index",
    "pages/login/login",
    "pages/mine/mine"
  ],
  "subPackages": [
    {
      "root": "packageA",
      "pages": [
        "pages/goods-detail/goods-detail",
        "pages/order/order"
      ]
    },
    {
      "root": "packageB",
      "pages": [
        "pages/setting/setting",
        "pages/feedback/feedback"
      ]
    }
  ]
}

这里要注意:pages数组里的页面属于主包,subPackages里的页面属于分包。分包之间不能互相引用代码,但分包可以引用主包里的公共模块。

⚠️ 我曾经踩过的坑: 分包里的页面如果引用了另一个分包的组件,编译不会报错,但运行时直接白屏。所以分包之间一定要解耦,公共逻辑全部抽到主包里。

独立分包:让某些页面秒开

分包虽然好,但有个问题:用户访问分包页面时,还是需要先下载主包。如果主包比较大,用户等得就久。

这时候独立分包就派上用场了。独立分包可以不依赖主包,单独下载、单独运行。你想想看,像活动页、广告落地页这种场景,用户从外部链接直接跳进来,如果还要先下载主包,体验就很差。

配置独立分包很简单,加一个 "independent": true 就行:

{
  "root": "packageC",
  "pages": [
    "pages/activity/activity"
  ],
  "independent": true
}

嗯,这里有个细节:独立分包不能引用主包的任何代码。所以如果你的独立分包页面需要用到公共组件,要么把组件复制一份到分包里,要么用纯原生写法。我个人建议尽量保持独立分包轻量,只放一个页面和它独有的资源。

💡 我的经验: 独立分包最适合做「活动页」、「邀请页」、「广告页」。这些页面生命周期短,用户看一眼就走,没必要把整个主包拖下来。

预加载:让用户感觉不到加载

分包解决了体积问题,但带来了新的问题——加载延迟。用户点击某个按钮,才去下载分包,中间会有几百毫秒甚至几秒的等待。怎么优化?

答案是预加载。说白了,就是在用户可能访问某个分包之前,提前把分包下载下来。

配置方式是在 app.json 里加 preloadRule

{
  "preloadRule": {
    "pages/index/index": {
      "network": "wifi",
      "packages": ["packageA"]
    }
  }
}

这段配置的意思是:当用户进入首页时,如果当前网络是WiFi,就提前下载 packageA 分包。这样用户点击商品详情时,分包已经下载好了,直接打开,几乎没有延迟。

我一般会在首页tabBar页面做预加载。因为这些页面用户停留时间长,有足够的时间去下载后续分包。而且我习惯加上 "network": "wifi" 限制,避免在移动网络下浪费用户流量。

📊 预加载策略建议:
  • 首页 → 预加载商品列表分包(用户大概率会点)
  • 商品列表页 → 预加载商品详情分包(用户大概率会看)
  • 登录页 → 预加载个人中心分包(登录后大概率会去)

分包体积监控:别让体积悄悄涨回去

分包做完了,是不是就万事大吉了?不是。我见过太多团队,优化完包体积,过两个月又涨回去了。为什么?因为新需求不断加,代码不断堆,没人盯着体积。

所以,分包体积监控必须落地。我推荐两种方式:

1. 本地构建时监控

project.config.json 里可以配置分包体积上限:

{
  "setting": {
    "preloadLimit": "2MB",
    "subPackageSizeCheck": true
  }
}

开启 subPackageSizeCheck 后,如果某个分包超过限制,构建时会直接报错。这能拦住大部分无意识的体积膨胀。

2. CI/CD 流水线监控

我在公司的CI流水线里加了一个脚本,每次构建后自动解析 subPackages 的体积,如果某个分包比上一次构建大了10%以上,就发告警通知。这样团队里每个人都能看到体积变化。

来看一个简单的体积监控脚本思路:

# 伪代码,实际用Node.js写
1. 构建完成后读取 dist 目录
2. 遍历每个分包文件夹,计算总大小
3. 与上一次构建的基线数据对比
4. 如果增长超过阈值,输出警告
⚠️ 注意: 分包体积监控不能只看总大小,还要关注单个分包的大小。我曾经遇到一个项目,主包只有1MB,但某个分包偷偷涨到了1.5MB,用户访问那个分包时加载特别慢。所以每个分包都要设上限。

总结一下

分包加载这件事,说白了就是把大包拆小,按需加载。主包放核心,分包放次要,独立分包放独立场景,预加载让用户感觉不到等待。最后用监控守住成果。

我个人觉得,分包策略做得好不好,直接决定了小程序启动速度和页面跳转体验。你想想看,用户打开小程序,1秒内看到首页,和3秒才看到首页,体验差距有多大?

下一节我会讲代码层面的极致优化,包括如何减少setTimeout、如何优化长列表渲染。咱们一步步来,把性能优化吃透。

💡 最后一个小技巧: 如果你不确定哪些页面该拆到分包里,可以打开微信开发者工具的「性能面板」,看看每个页面的加载耗时。那些加载慢、但又不是首屏的页面,优先拆出去。