微信小程序分包进阶:独立分包、预下载与分包异步化实战

微信小程序分包进阶:独立分包、预下载与分包异步化实战

admin
2026-06-01 / 0 评论 / 246 阅读

微信小程序分包进阶:独立分包、预下载与分包异步化的正确打开方式

主包 2M、总包 30M 的限制人人皆知,但分包能玩出的花样远不止"把页面挪出去"。独立分包解决冷启动速度、分包预下载消除切换白屏、分包异步化打破"主包不能引用分包代码"的铁律——这三个特性组合起来,才是分包体系的完全体。这篇逐个拆解。

一、普通分包:只是起点

// app.json
{
  "pages": [
    "pages/index/index",
    "pages/login/login"
  ],
  "subpackages": [
    {
      "root": "packageOrder",
      "pages": [
        "pages/list/list",
        "pages/detail/detail"
      ]
    },
    {
      "root": "packageActivity",
      "name": "activity",
      "pages": ["pages/coupon/coupon"]
    }
  ]
}

容易忽略的规则

  1. 分包页面可以引用主包的公共资源,反之不行(普通分包模式下)
  2. tabBar 页面必须在主包
  3. 分包使用 root 做 import 路径前缀:require('../../packageOrder/utils/format.js') 从主包引用是不行的(分包异步化出现前)
  4. 一个页面的图片资源如果被多个分包引用,放主包还是复制多份,要用体积权衡

二、独立分包:把启动速度砍一半

2.1 原理

普通分包启动时,无论用户进入哪个页面,主包都会先下载。独立分包的意义:从它进入小程序时,不下载主包,直接跑独立分包。

适用场景非常明确:

  • 营销活动页(扫码直达,秒开要求高)
  • 分享有礼落地页
  • 面向新用户的裂变页面
{
  "subpackages": [
    {
      "root": "packageActivity",
      "pages": ["pages/coupon/coupon"],
      "independent": true   // 关键配置
    }
  ]
}

2.2 独立分包的三条军规

军规一:不能依赖主包任何内容。主包的 app.wxss、utils、公共组件全部不可用,独立分包必须是自包含的。

军规二:getApp() 可能拿不到。主包未加载时 app 实例不存在:

// packageActivity/pages/coupon/coupon.js
const app = getApp({ allowDefault: true })  // 允许拿到默认空壳

// 或更稳妥的防御式写法
let app
try {
  app = getApp()
} catch (e) {
  app = { globalData: {} }
}

军规三:App 生命周期不触发。从独立分包冷启动时,app.jsonLaunch/onShow 都不会执行。全局初始化逻辑(如统计 SDK 初始化)要在独立分包页面里自己做一份。

2.3 独立分包跳主包

用户从活动页点"进店逛逛"跳主包页面时,主包才开始下载:

wx.navigateTo({
  url: '/pages/index/index',
  fail() {
    // 主包下载中,用户可能看到 loading
    wx.showLoading({ title: '加载中' })
  }
})

跳转前可以预热:

// 独立分包页面 onReady 后预下载主包
wx.preDownloadSubpackage({
  packageType: 'main',
  complete() { /* 主包就绪 */ }
})

三、分包预下载:消灭切换白屏

用户从首页点进订单列表,普通分包要现场下载 → 白屏/loading 一段。preloadRule 让分包提前就位:

{
  "preloadRule": {
    "pages/index/index": {          // 触发页面
      "network": "all",             // wifi / all
      "packages": ["packageOrder"]  // 预下载的分包 root 或 name
    },
    "pages/order/list/list": {
      "network": "wifi",
      "packages": ["packageActivity"]
    }
  }
}

设计策略:按用户动线配置——首页预下载高频分包(全网络),二级页在 wifi 下预下载低频分包。同一个分包的预下载体积和页面数量成正比,别一口气全预下载,白瞎了流量策略。

进阶玩法是结合数据做个性化预下载:服务端返回用户画像,首页 onLoad 时动态调用 wx.preDownloadSubpackage

// 首页
async onLoad() {
  const profile = await api.getUserProfile()
  if (profile.isVip) {
    wx.preDownloadSubpackage({
      packageType: 'sub', root: 'packageVip',
      complete() {}
    })
  } else {
    wx.preDownloadSubpackage({
      packageType: 'sub', root: 'packageActivity',
      complete() {}
    })
  }
}

四、分包异步化:主包引用分包代码

这是 2022 年后分包体系的最大进化。此前"主包不能 require 分包代码",公共组件库要么塞主包(挤占 2M),要么各分包复制一份。分包异步化允许:

4.1 跨分包 JS 引用

// 主包页面里,引用分包的模块
const { formatPrice } = require.async('../../packageOrder/utils/format.js')

Page({
  async onLoad() {
    const { formatPrice } = await require.async('../../packageOrder/utils/format.js')
    this.setData({ price: formatPrice(9900) })
  }
})

4.2 跨分包组件引用

// 页面 json
{
  "usingComponents": {
    "order-card": "../../packageOrder/components/order-card/index"
  }
}
<!-- WXML:像普通组件一样用,首次渲染时自动异步加载 -->
<order-card wx:if="{{loaded}}" item="{{item}}" />

注意搭配 wx:if 或占位组件,处理组件异步加载完成前的渲染状态,避免布局跳动。

4.3 分包异步化的收益场景

场景传统方案异步化方案
大型富文本编辑器(500KB)塞主包,挤占限额编辑器分包,用到再加载
多个分包共用图标库每包复制一份图标库分包,异步引用
低频但主包入口需要的工具塞主包工具分包化

五、体积分析实战

上线前用代码依赖分析(开发者工具 → 详情 → 基本信息 → 代码包体积,或 ci.quickCompile 分析)找出大头:

常见的体积黑洞

  1. echarts 全量引入(~900KB)→ 按需构建 + 放分包异步化
  2. moment.js 带全量 locale(~300KB)→ dayjs(7KB)替换
  3. 图片资源→ CDN 化,包内只留 tabBar 图标等必须本地化的
  4. 组件库全量引入 → 按需引入 + lazyCodeLoading: requiredComponents
// app.json:按需注入,所有项目都该开
{
  "lazyCodeLoading": "requiredComponents"
}

六、架构决策速查

主包(≤2M)
├── tabBar 页面(必须主包)
├── 登录/首页骨架
└── 首屏强依赖的公共代码

普通分包(按业务域拆)
├── packageOrder    —— 预下载(network: all)
├── packageVip      —— 按用户画像动态预下载
└── packageEditor   —— 分包异步化,主包按需引用

独立分包(自包含,零主包依赖)
└── packageActivity —— 营销页/裂变页,秒开

七、避坑清单

现象解法
独立分包 getApp() 报错主包未加载getApp({allowDefault:true}) 防御
独立分包样式错乱引用了 app.wxss样式自包含,别依赖全局样式
preloadRule 不生效触发页面是 tabBar 页面之外的类型触发页面必须是普通页面
require.async 偶发失败分包未下载try-catch + 降级 UI
跨分包组件首帧跳动异步加载无占位wx:if + 骨架占位
真机白屏但工具正常分包路径大小写严格保持目录名大小写一致

写在最后

分包体系的三板斧各有分工:普通分包管体积、独立分包管启动、预下载和异步化管体验。做架构时先画用户动线图,再决定哪个页面进哪个包、预下载怎么排布。最后记住一个朴素原则:主包里只放"每个用户每次打开都会用到"的东西,其他一切皆可分包。

0

评论 (0)

取消
0:00