分包加载
WeChat 小程序的分包机制在 weapp-vite 中得到完整支持。本页帮助你快速理解「普通分包 vs 独立分包」的差异,以及框架在构建阶段做了哪些工作。若需要原理级配置(weapp.subPackages、weapp.chunks 等),请继续阅读 配置文档 · 分包与 Worker 策略。
- 想知道如何开启分包?直接沿用官方
app.json写法即可。 - 想共用工具、样式?普通分包可以与主包共享上下文,独立分包则需要借助
styles等配置。 - 想优化构建产物位置?留意
weapp.chunks.sharedStrategy。
官方说明可参考:分包加载 - 微信官方文档。以下内容聚焦于 weapp-vite 的行为和调优手段。
分包配置入口
通过 weapp.subPackages 可以为每个 root 单独开启独立编译、裁剪 dependencies 或注入 inlineConfig。当需要强制开启独立分包、给特定分包设置额外的 define、或为某些分包关闭自动组件导入时,优先在 vite.config.ts 中调整该项。
NOTE
文档多次提到的 Rolldown 是 weapp-vite 内置的打包器,语法与 Vite/Rollup 插件体系兼容,但针对小程序做了额外的产物分发优化。你可以把它理解成「为小程序量身定制的 Rollup」,同一个 Rolldown 上下文意味着编译出的模块、样式和资源可以直接互相复用。
普通分包
普通分包被视为和整个 app 是一个整体,所以它们是在同一个 Rolldown 上下文里面进行打包的。
根据引用规则:
packageA无法requirepackageBJS文件,但可以require主包、packageA内的JS文件;使用分包异步化时不受此条限制packageA无法importpackageB的template,但可以require主包、packageA内的templatepackageA无法使用packageB的资源,但可以使用主包、packageA内的资源
代码产物的位置
所以假如有可以复用的 js 代码,它们产物的位置,取决于它们被引入使用的文件位置,这里我们以工具类 utils 为例,展示处理策略上的区别
- 假如
utils只被packageA中的文件使用,那么utils的产物只会出现在dist产物的packageA中。 - 假如
utils在packageA和packageB中使用,那么utils会被复制到各自分包的__shared__/common.js中,而不再提炼到主包。 - 假如
utils在packageA和主包中使用,那么utils的产物会被提炼到主包中,保证主包可以直接使用。
另外,node_modules 中的第三方依赖与 Vite 注入的 commonjsHelpers.js 也会参与相同的统计:在默认的 duplicate 策略下,它们会和业务模块一起根据引用方被复制到各自分包;只有在 sharedStrategy: 'hoist' 时,相关模块才会统一落到主包的 common.js,供所有分包共享。
详细示例
下面以 test/fixtures/subpackage-dayjs 为例,展示一次真实的分包拆分过程。项目结构与配置精简如下:
src/
app.ts
utils/shared.ts # 主包与 packageA、packageB 同时引用
packageA/
pages/foo.ts # 引入 utils/shared.ts,并使用第三方 dayjs
packageB/
pages/bar.ts # 引入 utils/shared.ts,并使用第三方 dayjs
workers/index.ts # (可选)worker 入口
// vite.config.ts
export default defineConfig({
weapp: {
subPackages: [
{ root: 'packageA' },
{ root: 'packageB' },
],
chunks: {
sharedStrategy: 'duplicate',
},
},
})构建完成后,测试夹具会分别生成 dist-duplicate/ 与 dist-hoist/ 两个目录,核心产物与模块来源对应关系如下:
| 产物位置 | 说明 |
|---|---|
dist-duplicate/__weapp_shared__/packageA_packageB/common.js | packageA 与 packageB 共同引用的模块(如 utils/shared.ts),被标记为虚拟共享块。 |
dist-duplicate/packageA/__shared__/common.js | 复制自虚拟共享块,供 packageA 使用。 |
dist-duplicate/packageB/__shared__/common.js | 复制自虚拟共享块,供 packageB 使用。 |
dist-duplicate/packageA/pages/foo.js | 入口被自动改写为 require('../__shared__/common.js')。 |
dist-duplicate/packageB/pages/bar.js | 入口被自动改写为 require('../__shared__/common.js')。 |
dist-duplicate/packageA/__shared__/common.js / dist-duplicate/packageB/__shared__/common.js | 内含 dayjs 等来自 node_modules 的依赖代码,因为它们仅被两个分包使用。 |
dist-hoist/common.js | 切换为 hoist 策略后,跨分包共享模块统一落在主包。 |
dist-hoist/packageA/pages/foo.js / dist-hoist/packageB/pages/bar.js | 入口被改写为引用 ../common.js。 |
dist-hoist/app.js | 主包独享的逻辑,仍留在主包目录。 |
若某个共享模块或 node_modules 依赖同样被主包引用,则它会被提炼到主包下的 common.js。将 sharedStrategy 切换为 hoist 时,上述跨分包共享模块(包括 dayjs 等第三方依赖)会集中在主包的 common.js,供所有分包按需引用。
提示:主仓库的演示项目
apps/vite-native也在packageA与packageC中引入了dayjs,可以结合dist产物直观观察默认策略与hoist策略的差异。
默认的复制策略可以显著降低跨分包访问主包代码时的冷启动成本,当然你也可以通过 weapp.chunks.sharedStrategy = 'hoist' 恢复旧行为,或结合 advanced-chunks 功能进行更精细的拆分。
import { defineConfig } from 'weapp-vite/config'
export default defineConfig({
weapp: {
chunks: {
// 若项目体积更敏感,也可以显式切回旧策略
sharedStrategy: 'hoist',
},
},
})独立分包
独立分包和整个 app 是隔离的,所以它们是在不同的 Rolldown 上下文里面进行打包的,它们是不会去共享复用的 js 代码的
- 独立分包中不能依赖主包和其他分包中的内容,包括
js文件、template、wxss、自定义组件、插件等(使用分包异步化时 js 文件、自定义组件、插件不受此条限制) - 主包中的
app.wxss对独立分包无效,应避免在独立分包页面中使用app.wxss中的样式;App只能在主包内定义,独立分包中不能定义App,会造成无法预期的行为; - 独立分包中暂时不支持使用插件。
独立分包的共享样式
虽然构建上下文是隔离的,但仍可以使用 weapp.subPackages[].styles 注入共享主题、基础样式。weapp-vite 会在独立上下文内重新编译这些样式,并自动在页面或组件的样式文件头部插入 @import。
TIP
如果分包根目录内直接存在 index.* / pages.* / components.*,框架会自动推测注入范围,零配置即可共享基础样式。
调试建议
- 确认
app.json中的independent: true是否与vite.config.ts中的weapp.subPackages保持一致。 - 利用
weapp.debug.watchFiles查看产物位置,确认独立分包是否生成独立的miniprogram_npm。 - 如果分包引用到了主包路径,构建会报错提示,请及时调整引用方式或拆分公共模块。
常见问题
- 本地运行时报路径错误? 检查页面是否引用了其他分包的资源,或在
weapp.chunks中启用了与你项目不符的策略。 - 产物体积过大? 使用
weapp.subPackages[].dependencies精确声明每个独立分包需要的 npm 依赖,剩余依赖保持在主包。 - 想在分包中调试 Worker? 记得同时在
weapp.worker中声明入口,并确保 Worker 文件位于对应分包目录。