ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

微信小程序分包超限排查与主包体积优化实战

微信小程序分包超限排查与主包体积优化实战 最近接了个商城的活儿HBuilderx 里跑得好好的小程序我改了几行跳转逻辑上传的时候微信直接甩了个“分包大小超过限制”的报错。关键是我压根没动分包配置新增的页面也都塞进子包了它凭什么超排查了一下午发现这个报错背后藏着的东西还挺深。今天就把完整的排查链路和解决思路整理出来遇到同样问题的朋友可以直接照着抄。先把话说清楚微信小程序的主包限制是 2MB总包限制是 20MB某些类目可能有差异HBuilderx 只是编译器真正的体积审核是微信开发者工具那边做的。所以你在 HBuilderx 里看着没问题一上传就报错本质是uni-app 编译出来的 dist 目录里主包体积已经越过红线。至于为什么“改了几行代码”就爆后面细讲。1. 先搞清楚微信那边的真实规则再谈怎么排查很多人一看到“分包大小超过限制”就急着拆代码其实第一步应该搞明白微信到底在限制什么它统计的不是你 HBuilderx 项目里源码的 size而是mp-weixin编译产物中主包主包 没有写在 subPackages 里的页面 公共资源的体积。1.1 主包、分包、独立分包的边界这里有一个最容易误解的地方你以为把新页面放进了pages/activity/目录它就自动进分包了错了。在 uni-app 里一个页面属于主包还是分包只取决于 pages.json 里的配置跟物理目录没关系。出现在pages数组里的页面 → 统统算主包。出现在subPackages数组里的页面 → 才算分包。tabBar里的页面必须是主包这是微信硬性规定。所以“改了几行代码”后报超限大概率是这几种情况要么你新加的页面不小心挂在了主包 pages 下要么虽然页面进了分包但公共组件、公共JS、公共图片仍然被打进了主包要么你的主包本来就在 1.9MB 边缘疯狂试探随便加点东西就爆了。1.2 微信开发者工具里的真实数字怎么看HBuilderx 里你看到的是源码微信开发者工具看到的是编译结果。最靠谱的做法是在 HBuilderx 里点击“运行到小程序模拟器”然后打开微信开发者工具。点击右上角“详情” → “基本信息”里面会列出主包大小、分包总大小。更精确的方法是点“代码依赖分析”按钮在工具栏上路径可能随版本变化它会按目录列出每个文件占的体积。我那次的情况就是这样主包已经占到了 1.97MB而我只往主包页面里加了一个onLoad里的二维码生成逻辑引入了一个挺大的 qrcode 库直接超了 0.5MB。所以“几行代码”是表象真正的问题是那些代码背后拖进来的依赖。2. 别急着删代码先用构建报告定位超限元凶我见过很多人一报错就把components里的公共组件往外挪挪半天发现还是超。正确顺序是先看体积构成再动手砍。2.1 用代码依赖分析看主包大头在微信开发者工具里打开“代码依赖分析”重点看common/vendor.jsuni-app 会把第三方依赖都砸进这里和主包pages下的各页面 js。如果vendor.js已经从 600KB 涨到了 1.2MB那就说明你最近引入的某个 npm 包是元凶。我那次排查时注意到vendor.js里有html2canvas的完整代码。这个库在 uni-app 小程序里基本用不上小程序不是浏览器环境但我在一个公共 JS 文件里import了它即便页面没实际调用编译时也会被打进 vendor.js。这类情况属于**“连带打包”**是特别坑的一点。2.2 公共图片和 base64 是隐形杀手很多从 Vue 项目转过来的朋友习惯把图片放在src/assets里然后在template里直接require(/assets/xxx.png)。在 H5 端这样没事但在小程序端小图片一般小于 10KB会被转成 base64 串写进 js 或 wxml图片本身不占体积但 base64 膨胀了约 33%如果图片数量多比如 20 张 8KB 的小图标光这几张就能吃掉 200KB。大图片的话uni-app 编译时会输出为独立文件放在主包 static 目录下同样占用主包空间。2.3 手动检查 dist 目录如果开发者工具里的数据不够直观可以直接去项目下的dist/dev/mp-weixin或dist/build/mp-weixin看。用终端命令按体积排序du -sh dist/build/mp-weixin/* | sort -rh | head -30如果你能看到多个pkg-xxx开头目录那是分包没有前缀的pages、static、common、components目录就是主包。哪个体积不对劲直接进去找最大的文件通常就是它了。我在实际排查中还发现有些项目会在static目录里躺着一堆没人引用的切图比如设计稿里调过色后来不用了但文件还在。这些废资源不会被自动清除一直占着主包空间。3. 建立分包体系不是把页面塞进 subPackages 就行找到元凶之后如果你还没做分包或者分包策略不合理下一步就是搭一套正确的分包体系。这里有个前提switchTab 的页面不能被分出去所以玩法一般是这样核心 tab 页 公共依赖放主包其他二级页、工具页、活动页统统进分包。3.1 pages.json 分包配置的正确姿势以 uni-app 的 pages.json 为例分包是这样声明的{ pages: [ { path: pages/index/index, style: {} }, { path: pages/mine/mine, style: {} } ], subPackages: [ { root: pages/order, pages: [ { path: list, style: {} }, { path: detail, style: {} } ] }, { root: pages/activity, pages: [ { path: coupon, style: {} } ] } ] }这里有几个容易犯的错root必须以/开头不不能以/开头直接写相对路径。root目录下的文件路径不能和主包 pages 里的路径重复。分包里的页面路径在uni.navigateTo时要写完整比如/pages/order/list?orderIdxxx。子包的pages数组里path是相对于root的不要加root前缀。3.2 一个常见坑分包页面引用的公共组件仍会进主包我这次遇到的就是这个。我在分包页面里用到某个自定义弹窗组件这个组件放在src/components/common-popup/下。你以为它跟着分包走不分包只会把 “分包页面自身 分包内独有的组件” 打包进分包。如果这个组件同时被主包页面用到了它就会被提升到主包common里。所以假使你主包本来就快满了哪怕只是往分包页面加了一个按钮只要这个按钮引用了新的公共组件也可能导致主包体积上升。3.3 分包预加载规则还有一个优化点是preloadRule。微信允许在进入某个分包前预下载另一个分包对于用户在首页就要跳转到活动页的场景很有用preloadRule: { pages/index/index: { network: all, packages: [pages/activity] } }不过注意预下载的分包大小也有 DHCP 限制具体是限制 2MB 还是 4MB 取决于微信当前规则。不要为了体验把一堆分包全预载否则还是会被体积卡住。4. 主包瘦身那些真正有效的压缩手段如果你已经配置了分包主包却依然超限就要对主包做精确瘦身了。下面这些手段是我实际跑过一遍后确认有效的。4.1 图片能上 CDN 就别本地存放小程序主包和分包对图片的容忍度很低一张 1.5MB 的 banner 直接顶掉大半个主包。我的原则是所有运营位图片、商品图、活动头图全部上传到 CDN代码里只保存 URL。但这里要留意如果你把图片路径写在 CSS 的background-image: url(../../static/banner.png)里编译时它会被当成静态资源处理不管你是不是线上 URL都会被打包。用 CDN URL 时最好直接写完整https://链接不要写相对路径。4.2 大图片转 base64 看起来变小了实际更糟这个点有些人容易想反。确实一张 3KB 的小图标转 base64 后虽然占的体积变成约 4KB 字符串但它避免了 HTTP 请求在小程序里能减少网络往返偶尔用用可以。可一旦中转 base64 的图片到了几十张生成后的vendor.js或者 wxml 里会有大段乱码直接撑爆主包。所以我的经验是主包里 base64 图片总量控制在 30KB 以内超过全部换 CDN。特别是页面顶部大图绝对不要用 base64。4.3 按需引入第三方库uni-app 项目里第三方库极易膨胀。常见套路是某业务需要用了dayjs然后又装了lodash再配一个js-cookie加上自己写的utils/http.js里引了axios。这些库如果不做按需引入全都进common/vendor.js。解决思路// 错误示范全量引入 import _ from lodash // 正确示范只引入用到的函数 import debounce from lodash/debounce对于无法按需引入的大型库比如富文本解析mp-html、海报生成painter建议不要放在主包公共引用而是把它考进对应分包页面内部只在那个分包里引入这样体积就落在分包里主包就安全了。4.4 App.vue 里的全局样式和全局 JS 要克制uni-app 的App.vue里如果import了一个较大的全局 CSS比如完整版的uview-plus主题样式或者内联了一段很长的工具函数它们都会被算进主包的app.js和app.wxss。我接手的一个项目App.vue里的onLaunch里写了个LoginManager.init()这个 init 方法里 import 了完整的weapp-qrcode二维码库但实际上只有一个页面用到了二维码。结果主包把weapp-qrcode整个吞了。解决办法是把二维码生成函数单独抽成utils/qrcode.js放进入口按钮对应页面的分包里需要时再import绝不在 App.vue 中全局引用。4.5 注意 easycom 配置uni-app 的 easycom 自动引入是双刃剑。当你template里写了uni-popup编译器会自动去找uni_modules/uni-popup组件。如果你在 HBuilderx 的安装插件里装了很多常用组件但项目里没用到它们不会打包这点还好。但如果你在主包页面用了一个又同时希望它在分包页面里也能用那这个组件必然被提取到主包。所以对于体积大户不要图方便用 easycom 自动引用直接在分包里的页面 json 手动usingComponents引用仅对分包生效能有效避免组件进入主包。5. 一次完整的超限排查复盘从报错到上传成功前面讲了不少理论现在完整复盘一遍我处理这类报错的流水线包含我刚才提到的那次经历前后大概花了一个半小时。5.1 现象与初步判断项目之前可以正常上传最近加了两个页面一个订单列表、一个优惠券领券中心。我把它们写在了pages/order/和pages/coupon/下并在 pages.json 里配置了 subPackages。改动前上传正常这次改完“分发”报错分包大小超过限制。云平台报错信息也指向主包偏大。打开微信开发者工具的“代码依赖分析”显示主包 2.15MB已经超了。我第一反应是难道新增的页面没进分包打开 pages.json 仔细检查发现pages数组里确实也有一个pages/order/list的旧路径新页面则写在了subPackages里。历史原因老代码同时存在两套 order 页面旧页面不仅没删还一直挂着导致主包平白多了一整套页面。删除pages数组里的旧 order 路径后主包降到了 1.62MB。5.2 继续追查公共组件被提升原以为搞定了再一看主包还是超因为项目要求主包必须低于 2MB1.62MB 虽然不超但离 1.97MB 的试运行环境如果微信对体验版有额外限制还差一点。继续看依赖分析发现common/vendor.js已经干到 800KB。点进去看具体模块有个wangeditor的痕迹——这是一个富文本编辑器按理说小程序里用不上。往代码里一搜payResult.vue里import wangeditor用于 H5 端展示结果没有做条件编译就一并打包进小程序了。改成条件编译后// #ifdef H5 import wangeditor from wangeditor // #endifvendor.js从 800KB 缩小到了 420KB主包总大小降到 1.78MB。5.3 最后的冲刺图片资源外移虽然这时已经不超了但我想趁机多挤出一点安全空间免得下次改需求又立刻超限。继续在代码依赖分析里看到主包static目录下有一个poster-bg.png3.2MB是某个海报生成功能的背景图只在“生成分享海报”页面用到而这个页面恰恰在分包里。图片却埋在公共 static 下所以被算进了主包。把这张图移到对应分包的static或者直接换成 CDN URL 后主包降到 1.52MB整个上传顺利通过。5.4 复盘结论“改几行代码导致超限”的真正根因往往是主包处于高位运行状态而任何新依赖、新页面、新图片都可能成为压垮它的最后一根稻草。所以每次改动前如果发现主包接近 1.85MB就要警惕不要等到上传报错再处理。6. 预防措施把超限问题扼杀在提交之前经历这一轮之后我给自己定了个机制每次上传前都会主动检查几项这篇文章的最后部分分享给你。6.1 用 HBuilderx 发行配置做体积预检HBuilderx 的“发行”面板里选“小程序-微信”点开后有“压缩资源”和“Tree Shaking”之类选项具体名称取决于 HBuilderx 版本。开启后能在编译阶段压缩 JS 和 WXML有一定体积缩减效果。但记得这是构建期优化不代表主包一定不超还是以微信开发者工具的信息为准。6.2 建立依赖体积审计习惯我现在的习惯是每两周左右打开一次微信开发者工具的“代码依赖分析”看看主包前三大的文件分别是谁。如果发现某个第三方库占比较大但实际使用频率很低就考虑替换或按需引入。比如一个只需日期格式化的小功能完全用不着引一个moment.js用原生Date或者剪裁版的dayjs就够了。类似的常见案例还有lodash只为了一个deepClone就全量引入非常亏。6.3 对静态资源的统一约束我在团队里定了个规矩图片资源超过 50KB 一律走 CDN低于 50KB 的图标类按需内联。实际执行下来主包体积一直控制得比较健康。另外提醒一点从 CDN 加载图片时若用到oss私有读referer防盗链可能会拦截记得在小程序后台配置合法域名白名单同时确认 CDN 能处理小程序请求头。6.4 善用分包异步化如果你的项目里有需要独立运行的功能模块比如 WebView 容器页、客服会话页可以使用独立分包配置{ subPackages: [ { root: pages/independent, pages: [ { path: webview, style: {} } ], independent: true } ] }独立分包不会打包进主包也允许自己独立下载。不过它有限制不能依赖主包的任何 JS 和组件也不能使用 App.js 里的通用方法适合那种功能隔离度比较高的页面。6.5 用 CI 脚本检查构建产物如果你有自动化构建流程可以在上传前用脚本检查一下dist/build/mp-weixin的主包体积一旦超过阈值就直接 fail。比如#!/bin/bash SIZE$(du -sm dist/build/mp-weixin/ | cut -f1) if [ $SIZE -gt 2 ]; then echo 主包体积超过2MB exit 1 fi注意这里的du统计的是整个 dist 目录包括子包不一定准。更精确的方式是指定主包路径或者用find累加主包文件大小。7. 一个容易被忽视的细节开发者账号和工具版本的影响排查超限问题时我也遇到过一些跟体积无关但报错相似的状况。比如上传时提示“登录用户不是该小程序的开发者”这时候再怎么看体积都没用因为压根传不上去。需要检查微信公众平台里有没有把你微信号加入项目成员开发者权限要勾选。还有如果 HBuilderx 版本和微信开发者工具版本有较大差异某些编译配置会不生效也容易出现莫名其妙的报错所以建议两边都保持在较新的稳定版本。再补充一个场景如果你的项目里用了uni_modules插件尤其是一些比较大的 UI 组件库一定要留意它们是放在uni_modules目录还是src/uni_modules目录。HBuilderx 对uni_modules的编译逻辑和普通 npm 包不太一样部分插件即使只在一个页面用到也可能被 easycom 全局注册进主包。遇到这类问题去uni_modules插件目录里找它的package.json看看有没有easycom相关规则必要时手动排除。实战中我还发现像mescroll这种列表加载组件如果你只在一个列表页面用了但它做了全局easycom注册主包体积可能增加几百 KB。解决办法是把组件的引入方式改成在页面内显式import绕开 easycom。以上这些就是我解决“分包大小超过限制”问题的整套思考路径。核心就一句话超限是结果体积分配才是原因只有精确掌握主包的每一份体积才能根治这个报错。如果你也遇到了类似问题先别急着大改结构按文中的步骤从构建报告查起大概率能在半小时内定位到那个“几行代码”背后的真正元凶。
返回列表