微信小程序分包不能嵌套分包——一个让编译器报 should not contain 的隐藏禁令
某个微信小程序的单包体积逼近 2MB 限制,想把其中一个大分包里的几个子目录拆出去,减轻这个包的体积压力。配置写好提交,微信开发者工具刷出一条让人摸不着头脑的报错,折腾半小时才搞清楚这是平台层的一条硬性禁令——而不是自己哪里写错了。
现象
在 app.json 的 subpackages 数组里,已存在一个分包:
{ "root": "packagePerson", "pages": [...] }想把其中七个子目录拆成独立分包,于是新增:
{ "root": "packagePerson/pages/qixi", "pages": [...] }保存后编译器立即报错:
app.json: ["subpackages"][22]["root"] should not contain ["subpackages"][15]["root"]
根因
微信小程序的分包加载规则有一条严格约束:subpackages 数组内,任意两个分包的 root 路径不允许存在前缀包含关系。
换言之,packagePerson/pages/qixi 以 packagePerson 为前缀,框架判定这是"分包嵌套分包",直接拒绝。
很多人参照过这种写法:
{ "root": "pages/preview", "pages": [...] }这是从主包的 pages/ 目录下拆出来的,之所以合法,是因为主包没有 root 字段,它由顶层 pages 数组定义,不参与 subpackages 前缀嵌套检测。
一旦你把 packagePerson 也放入了 subpackages,再往 packagePerson/ 下挂任何子分包,就会触发这条禁令——哪怕物理目录结构完全正确。
正解
面对"大分包超体积想拆"的诉求,有三条可行路径,按代价从低到高排列:
方案一(最轻):注销已下线页面
如果该分包里有若干历史遗留页面不再需要,直接从 app.json 里删除注册(保留物理文件不动),体积立刻下降,不需要改任何跳转路径。
方案二(中等):新增独立顶级分包
把要拆出去的子目录整体移动到一个全新的顶级分包,root 使用从未出现过的名字,例如 packageActivity:
{ "root": "packageActivity", "pages": ["pages/qixi/index"] }代价是需要 codemod 所有 navigateTo 路径,同时更新后端配置里硬编码的页面路径(如消息推送 bannerLink、活动跳转 URL 等)。
方案三(重型):解散原大分包
把原来的大分包完全解散,将每个子目录分别升级为顶级独立分包。好处是颗粒度最细,坏处是主包的共享资源(utils/、components/、miniprogram_npm/)会被各分包重复引用,反而可能撑大总包体积。
目标目录结构不影响 app.json 配置写法。物理上可以是 packagePerson/pages/qixi/,但 app.json 里的 root 必须是独立顶级路径,例如 packageActivity,绝不能是 packagePerson/pages/qixi。
一句话外卖
微信小程序只有「主包 → 分包」一级拆分,分包永远是叶节点,想再拆只能另起一个顶级分包,没有嵌套分包这条路。