大型小程序体积治理:滴滴出行的分包、依赖与架构取舍
复盘滴滴出行小程序包体积优化,从资源压缩、依赖分析、分包治理到封面页方案,整理大型小程序可复用的体积治理方法论。
2019 年下半年,滴滴出行需要把微信钱包、支付宝九宫格入口中的 WebApp 迁移为小程序。这个迁移不是简单换壳,而是要把网约车、公交、代驾、车服、单车、顺风车等业务线都接入一个统一的小程序入口。
业务补齐带来的第一个工程问题,就是包体积。
小程序平台对包体积有明确限制,主包和单个分包都有上限。滴滴出行小程序的首页又承载了大量高频业务:用户要在首页选择业务线、填写起终点、切换车型、保持状态、进入订单。业务越集中,首页相关代码越容易被打进主包,主包很快就会逼近平台限制。
English version: Package Size Governance for Large Mini Programs
这篇文章不只记录当时做了哪些优化,更想复盘一套可复用的方法:当一个小程序从单业务扩展到多业务、多团队、多依赖时,如何把“包体积优化”从临时救火变成长期治理。
先定义问题:不是所有体积都一样
包体积超标时,第一反应通常是“删代码”“压图片”“开压缩”。这些动作有用,但它们解决的是表层问题。
大型小程序的体积问题至少分三类:
- 资源体积:图片、视频、字体、JSON、静态配置等资源进入包内。
- 依赖体积:公共库、polyfill、协议描述文件、组件库、跨业务基础包重复进入主包。
- 架构体积:产品信息架构让大量业务都必须挂在首页,导致代码即使按需也无法拆出去。
前两类可以靠工程工具优化,第三类需要产品、架构和构建系统一起调整。如果没有先分清是哪一类,很容易做大量局部优化,却始终救不回主包空间。
第一步:建立体积可视化
优化体积前,必须回答三个问题:
- 主包里到底有什么?
- 哪些模块最大?
- 哪些依赖被重复打包或被放错了位置?
滴滴出行小程序基于 Mpx 开发,Mpx 的构建体系基于 webpack,因此可以借助 webpack-bundle-analyzer 一类工具分析构建产物。
一个典型体积分析图会展示第三方库、公共模块和业务代码的占比:

这一步的价值不只是找“大文件”,更重要的是建立团队沟通语言。体积问题如果只能靠感觉讨论,很难推动多业务线配合;一旦分析图展示出某个依赖被重复打包,或者某个只在分包使用的模块进入了主包,沟通成本会低很多。
可复用的方法是:每次体积治理都先产出可视化报告,再基于报告做决策。
第二步:做基础优化,但不要停在基础优化
基础优化包括:
- 压缩 JS、CSS、模板和 JSON。
- 删除无用代码和无用资源。
- 图片、视频等静态资源尽量走 CDN。
- 使用 tree shaking、模块去重、按需引入。
- 控制 polyfill 和公共基础库体积。
- 避免同一依赖因为版本不一致被打成多份。
Mpx 基于 webpack 构建,天然能复用很多 Web 生态里的优化能力。同时,Mpx 也针对小程序做了额外处理:按页面和组件依赖收集、运行时压缩、公共样式复用、分包公共模块抽取等。
这些优化是必要的,但它们通常只能让包体积“变瘦”。如果业务架构决定了所有业务都要进主包,再怎么瘦身也会越来越接近上限。
所以基础优化的目标不是一次性解决所有问题,而是先把明显浪费清掉,为后续架构拆分争取空间。
第三步:用分包把低频页面移出主包
小程序分包的思路很直接:启动时不需要的页面,不应该占用主包空间。用户进入对应页面时,再下载对应分包。
在滴滴出行小程序里,早期比较适合拆出去的是行程页、起终点选择、个人中心等非首页页面。这些页面不是启动第一屏必须展示的内容,放到分包里对首包压力更小。
初期分包完成后,主包释放了几百 KB 空间。这个收益看似不夸张,但它证明了一件事:项目结构只要能配合分包规则,主包体积就可以被持续管理。
分包治理的关键不是“能拆就拆”,而是按访问路径拆:
- 启动必需内容留在主包。
- 首屏后才能访问的页面进入分包。
- 业务线独立页面进入业务分包。
- 公共能力只在确实公共时进入主包。
- 只被某个分包使用的模块应该跟随分包输出。
第四步:治理 npm 依赖进入主包的问题
分包的难点在于,真实项目里很多代码不是按页面目录写的,而是通过 npm 包接入。
早期分包规则往往依赖文件路径:分包目录下的资源进分包,其他资源进主包。这个规则对页面代码有效,但对 node_modules 里的业务包不友好。
例如,一个行程页分包只在行程页里用到某个 socket 库,但这个库来自 npm,路径在 node_modules 下。如果构建系统只按路径判断,它就可能被收进主包。
这会造成一个很反直觉的问题:业务代码已经拆到分包了,但业务依赖仍然留在主包。
Mpx 后来做了更细的依赖归属分析:
- 构建时记录每个模块被哪些分包引用。
- 只被一个分包引用的模块输出到对应分包。
- 被多个分包复用但不被主包使用的资源,不强行进入主包。
- 为分包生成独立 cache group,把同一分包内复用的模块抽到分包公共 bundle。
这类能力的核心思想是:模块归属不应该只看文件在哪,还要看它被谁使用。
对大型小程序来说,这一步非常关键。多团队协作时,业务常常通过 npm 包独立交付。如果构建系统不能识别 npm 依赖的真实使用范围,主包会不断吸收本不该属于它的依赖。
第五步:识别纯技术优化的边界
当业务继续增长后,滴滴出行小程序又遇到了更大的问题:所有业务线都要在首页表达需求。
这和很多电商或内容类小程序不同。电商首页可以只是入口,商品详情、订单、搜索、个人中心都能拆成相对独立页面。出行首页则要同时承载业务选择、起终点、车型、地图、价格、状态、推荐等内容,用户还需要在多个业务之间流畅切换。
这意味着,各业务线都要提供首页组件。只要组件必须出现在首页,它就很难被拆进普通分包。
当时主包里的体积大致可以分成两块:
- 公共基础库:框架运行时、组件库、polyfill、通信库、业务公共依赖。
- 首页业务代码:各业务线在首页的需求表达组件和状态逻辑。
这时继续做“删几 KB 代码”的收益已经不够了。真正的问题变成:产品架构要求所有业务都进入首页,而平台限制要求主包不能太大。
这就是纯技术优化的边界。体积治理做到这里,必须开始讨论架构和产品形态。
第六步:用封面页方案改变主包职责
最终的解决方案,是把启动页变成一个很轻的封面页。
封面页只承担启动、品牌展示和跳转职责。真正承载复杂业务的首页,被放到一个分包里。用户打开小程序后,先进入主包里的封面页,再跳转到业务首页分包。

这个方案没有减少总代码量,它改变的是代码位置:
- 主包只保留启动必需能力和公共基础能力。
- 复杂首页业务进入首页分包。
- 后续业务增长主要消耗首页分包空间,而不是继续挤压主包。
当时这个改造把一大块首页业务逻辑从主包移到了分包里,主包压力立刻缓解。更重要的是,后续业务迭代的增长位置变得可控:主包不再随着每个业务需求反复逼近上限。
这个方案也有代价:首屏业务展示会变慢,因为启动后还要加载业务分包。但相比“主包超限导致无法继续上线”,这是可以接受的取舍。小程序平台本身也有分包缓存能力,实际体验可以通过加载策略继续优化。
可复用的方法论
复盘这类体积治理,大型小程序可以按下面的顺序处理类似问题。
1. 先建立预算,而不是等超限
不要等主包接近平台限制才开始治理。项目一开始就应该定义体积预算:
- 主包预算。
- 单个分包预算。
- 公共基础库预算。
- 单业务接入预算。
- 图片、JSON、协议文件等资源预算。
预算不是为了限制业务,而是为了让每个团队知道自己的代码会消耗公共空间。
2. 每次构建都能看到体积变化
体积问题适合自动化监控。至少应该能看到:
- 主包和各分包大小。
- 本次提交相比上次变化了多少。
- 新增了哪些大依赖。
- 是否出现重复依赖。
- 是否有只在分包使用的依赖进入主包。
没有数据,体积治理很容易变成临时运动。
3. 把分包当架构设计,不只是配置项
分包不只是 app.json 或构建配置里的一个字段。它会反过来影响业务模块边界、目录结构、npm 包设计和页面路径。
大型项目里,业务团队接入时就应该回答:
- 哪些代码必须首屏可用?
- 哪些页面可以延迟下载?
- 业务依赖是否会污染主包?
- 公共组件是否真的公共?
- 分包之间是否存在不合理耦合?
4. 依赖归属要按使用关系判断
真实项目里,文件路径并不等于模块归属。尤其是 npm 包、共享组件和公共工具函数,必须结合依赖图判断它们应该输出到哪里。
一个模块如果只被某个分包使用,它就不应该因为位于 node_modules 而进入主包。
5. 技术优化解决不了产品结构问题
当首页必须承载所有业务时,主包天然会膨胀。这个问题不能只靠压缩和 tree shaking 解决。
这时需要重新定义主包职责:主包是否真的要承载完整首页?能不能只做启动壳?业务首页是否可以作为分包加载?用户体验损失是否可接受?
大型项目的性能优化,很多时候最后都会变成架构取舍。
总结
滴滴出行小程序的包体积优化,不是一组孤立技巧,而是一条逐步升级的治理路径:
- 先用可视化工具看清体积组成。
- 再做压缩、去重、CDN 化、无用代码清理。
- 然后通过分包拆出低频页面。
- 接着治理 npm 依赖和分包归属。
- 最后在技术优化触顶后,用封面页方案调整主包职责。
这套经验最值得复用的地方,不是某个具体配置,而是判断顺序:先定位,再治理;先清理浪费,再调整结构;先优化技术边界内的问题,再推动产品和架构取舍。
大型小程序的包体积不会自动变好。它需要预算、工具、构建系统、业务边界和持续监控一起发挥作用。