微信小程序包体积优化:2MB 到 400KB 的实操记录

微信小程序包体积优化:2MB 到 400KB 的实操记录

小程序开发有个绕不开的坎:主包体积限制 2MB。

平时开发到一半没感觉,等真机预览、提审的时候突然冒出来"包体积超限",然后开始一轮手忙脚乱的删东西------删图片、删组件、删字体,删到最后功能都不全了。

这篇记录一次真实的瘦身过程,不是理论清单,是每一步改了什么、省了多少、踩了什么坑。

一、先搞清楚:2MB 到底限制的是什么

这是最容易搞错的点。

限制的是「主包 + 分包总和」以外的层级,具体来说:

  • 主包限制 2MB
  • 整个小程序包(含所有分包)限制 20MB
  • 单个分包限制 2MB

所以严格说,不是"整个包不能超 2MB",而是主包里的东西不能超 2MB。

这个区别很关键,因为很多人一看到"超了"就把所有东西塞进分包,结果分包也超。

先明确目标:主包只放"启动即需要"的东西。

二、第一刀:干掉主包里的静态资源

先说结论,这一步通常能省 300KB - 800KB,是性价比最高的。

检查 iconfont 有多臃肿

小程序的 iconfont 是最容易被忽略的体积杀手。

一个正常项目里,iconfont 文件可能包含几百个图标------但实际用到的可能只有二三十个。

排查方式 :找到项目里的 .ttf / .woff 文件,直接看文件大小。如果超过 100KB,基本就是图标全量打包了。

解法 :用 iconfont 的 Unicode 引用方式,生成的是字体文件 + CSS,字体文件只包含你订阅的图标。

或者更直接:用图片图标或者 SVG。如果你项目里图标数量不多(20 个以内),直接换成 SVG 内联反而更省,而且不受字体加载延迟影响。

检查图片有没有在主包里

项目里肯定有一堆图片,散落在各个目录里。只要被某个主包页面 import 或者写在样式里,它就进主包。

解法:所有图片资源都放 CDN 或者用云存储,主包里不存图片。

判断标准很简单:打开构建产物目录,看 assets 里有什么。这个目录里的东西就是主包资源。

我们项目当时的 assets 里有:

内容 体积 处理
iconfont 字体 210KB 改成 SVG 内联,删字体
占位图 45KB 移到 CDN
启动图 38KB 移到 CDN
未使用的 tabBar 图标 12KB 删掉两个变体

合计省掉 305KB。

tabBar 图标的坑

tabBar 必须用本地图片(不能用网络图片),且所有 tab 页的图标都会进主包。

我们之前有 5 个 tab,每个 tab 两套图标(选中/未选中),一共 10 张图。有 2 个 tab 的图标其实长得一样,根本不需要两套。

解法:合并视觉上相同的图标,能用一张就不做两套。

如果 tab 超过 5 个,考虑改成"自定义 tabBar",可以把图标放到分包里。

三、第二刀:分包策略

处理完静态资源,如果还是超,就该分包了。

怎么划分分包

原则:按业务模块划分,不要按页面数量硬切。

我们当时的划分:

css 复制代码
主包:首页、登录、我的、以及所有 tab 页
├── 分包 A:订单模块(订单列表、详情、评价)
├── 分包 B:商品模块(商品详情、规格选择、下单)
└── 分包 C:我的扩展(设置、地址簿、消息)

判断标准很简单:这个页面的功能,主流程会用吗?

  • 会的(比如首页)→ 主包
  • 不会的(比如订单历史)→ 分包

用户第一屏根本不会点到的页面,全在主包里就是浪费启动速度。

分包的两个硬限制

1. 分包不能引用主包外的资源

这个经常踩坑。分包页面里 import 主包里的组件是不允许的。

js 复制代码
// ❌ 分包页面引用了主包外的组件
import { CustomButton } from '../../components/button'

// ✅ 正确做法:把公共组件放主包,或者放到每个分包里

我们的做法是:高频公共组件(Button、Empty、Loading)放主包,低频业务组件放对应分包。

判断依据:这个组件有几个页面在用?只有 2-3 个页面用又都在同一个分包内,就放分包里。

2. 分包首次进入有加载延迟

分包不是免费的------用户第一次点进那个 tab,会等几百毫秒加载分包。

所以分包不要切太细。我们试过切 6 个包,结果每个包都很小,切换时的等待反而更明显。

最终定在 3 个分包,体验和体积平衡得比较好。

异步分包

如果你有某个特别大的业务模块(比如直播、视频),可以用异步分包:

js 复制代码
// 只在真正用到时才加载
const live = defineAsyncComponent(() => import('./live/index'))

配合分包配置里的 "lazyCodeLoading": "requiredComponents",能让启动更快。

但注意:异步分包用到的组件,不能在主包里被同步引用,否则会被打进主包,异步就白做了。

四、第三刀:干掉那些"顺手加的"东西

这一步没有技术含量,但效果出奇地好。

未使用的依赖

bash 复制代码
# 看依赖树,找出体积大的
npm ls --all --depth=10

我们当时发现一个没用到的日期处理库,带了一整套时区数据,78KB。

解法:定期检查依赖,别看到顺手就 npm install。项目跑了一年,依赖树里全是历史沉淀。

用 bundle-analyzer 类工具扫一下,找出没被引用的包。

polyfill

小程序端不需要那么多 polyfill。如果你的项目用了 core-js,检查下是不是全量引入的。

解法:按需引入,别全量打包。

sourcemap 和调试文件

这些应该只在本地保留,不要进构建产物。

json 复制代码
// project.config.json
{
  "setting": {
    "packNpmManually": false,
    "minifyWXSS": true,    // 开启压缩
    "minifyJS": true,      // 开启压缩
    "disableUseStrict": true
  }
}

五、优化后的实际数据

贴一下这次的完整对照:

阶段 主包体积 主要动作
优化前 1.87MB ---
清静态资源后 1.56MB iconfont 转 SVG、图片移 CDN
分包后 890KB 划分 3 个分包,公共组件重新分配
清理依赖后 745KB 删无用依赖、开启压缩
微调后 412KB tabBar 图标合并、异步分包

从超限到 412KB,主包降到原来的 22%。

六、几个容易忽略的细节

1. 主包里的图片会被 base64 内联

小体积图片(< 8KB)在构建时会被转成 base64 塞进 CSS/CSSJS 里。

这意味着一个 5KB 的图标,实际可能让 CSS 涨了 7KB(base64 体积比原图大 33%)。

如果你的 CSS 莫名其妙很大,先去 dist 里搜一下有没有 data:image。

2. 自定义组件的分包归属

uni-app / Taro 这类框架,自定义组件在哪个分包,取决于它被谁引用。

如果主包引用了某个组件,那个组件就永远在主包,哪怕它只服务分包页面。

这一点很反直觉,但很关键------想彻底瘦身,要从主包的依赖链开始砍。

3. 别为了体积牺牲可维护性

我们删掉过一些"暂时没用但预留了"的代码,后来又要加回来,来回折腾。

建议:只删确定不用的,标了 TODO 或注释的先留着。几百 KB 换来的维护成本不划算。

七、写在最后

包体积优化的核心思路其实就一句:主包只放启动必需的东西。

围绕这个原则,具体做法可以很多------移资源、删依赖、合并图标、分包、按需加载。

但更重要的是:改完要真的量一遍。

微信开发者工具里有"代码质量分析"或者上传时会给体积报告,每次提交前看一眼,别等提审被拒了才回头找原因。

最后提一句,我们做完这次优化还有个附带好处:启动速度明显变快了。因为主包小了,首屏加载的资源少了。这个是意外收获------本来只是想解决超限,结果顺手优化了体验。

如果你的项目也卡在 2MB 上,可以按这个顺序试试:先查静态资源 → 再查依赖 → 最后才考虑分包。大部分项目前两步就能解决大半。

相关推荐
掘金挖土1 小时前
前端手摸手跑路之 AI 应用开发(十一)
前端·后端
创了么OPC1 小时前
小程序能收款了,对公户还没开?独立开发者的交付闭环踩坑②
前端·微信小程序
IT_陈寒1 小时前
Vue动态组件缓存的坑你踩过了吗?
前端·人工智能·后端
寂寞狼牙冷1 小时前
封装fetch替换axios
前端
用户461169657281 小时前
网站 HTTPS 不稳定?证书排查指南
前端
n87652 小时前
Playwright Java WEB UI 自动化实现框架与逻辑
java·前端·ui
keyipatience2 小时前
TypeScript学习(1)
前端·javascript·学习·typescript·html·css3
xifangge20252 小时前
基于 JavaScript 实现 CNC 数控切削参数与螺纹公差纯前端核算引擎
开发语言·前端·javascript
wangruofeng3 小时前
2026 Web 技术选型指南,AI 时代如何选择适合项目的技术栈
前端·aigc·ai编程