微信小程序在提交审核和日常迭代中,代码包体积直接影响用户首次打开速度和下载成功率。当项目不断叠加功能,很容易在源码目录里残留不再使用的页面、组件和图片,这些文件被打包进主包后毫无用处却占用额度。理解代码包的构成并定期清理,是维持小程序轻量化的关键手段。

小程序代码包结构与大小限制原理
微信小程序分为主包和分包,平台规定主包体积不得超过两兆,单个分包不得超过两兆,总包大小上限为二十兆。在开发者工具编译时,所有在app.json中被声明的页面和组件,以及它们静态引用的图片、脚本,都会被算入对应包体。如果某张图片仅被一个已下线的活动页使用,而该页面未从app.json的pages数组移除,这张图就会一直留在包里。
从底层看,小程序打包器会依据入口文件做依赖收集,但静态资源如images目录下的文件往往采用 glob 方式整体拷贝,并不会做 tree-shaking。这意味着即便代码里没require某个模块,只要它落在被拷贝的目录规则内,依然进包。因此单纯靠摇树优化不够,必须结合引用关系做文件级清理。
另一个容易被忽视的点是node_modules中某些库会携带示例代码或文档,若直接被小程序构建流程误包含,也会膨胀包体。清楚这些机制后,我们才能有针对性地写脚本,而不是盲目删除。
利用开发者工具与命令分析包内大文件
微信开发者工具提供了“代码依赖分析”面板,可以可视化的看到每个文件在包中的大小占比。打开方式是在工具栏选择“详情”再进入“代码依赖分析”标签,工具会列出主包和分包的拓扑图。但图形界面不适合纳入持续集成,我们更推荐用命令行解包分析。
编译后的包在dist目录或工具缓存中以__APP__.wxapkg形式存在,可用开源工具wxapkg-unpack解压。解压后能得到完整的文件树,此时配合du -sh *类指令即可排序找出体积最高的目录。通常images与pages是重灾区。下面是一段 Node 脚本,用来打印指定目录下各文件大小并降序输出:
const fs = require('fs');
const path = require('path');
function scan(dir) {
let result = [];
const list = fs.readdirSync(dir);
for (const name of list) {
const full = path.join(dir, name);
const stat = fs.statSync(full);
if (stat.isDirectory()) {
result = result.concat(scan(full));
} else {
result.push({ path: full, size: stat.size });
}
}
return result;
}
const files = scan('./dist');
files.sort((a, b) => b.size - a.size);
files.slice(0, 20).forEach(f => {
console.log((f.size / 1024).toFixed(2) + 'KB ' + f.path);
});
这段脚本递归收集文件信息,按字节数倒序打印前二十个最大文件,帮助我们快速定位该删谁。需要注意的是,分析时应基于构建后的产物而非源码,因为源码里的ts文件在构建后变成js,路径和体积都有变化。
编写自动清理无用文件的 Node 脚本
清理的核心思路是:以app.json及分包配置为基准,提取所有被注册的页面路径和usingComponents,再扫描项目资源目录,标记那些既不在页面引用链也不在组件引用链中的文件。为避免误删,脚本应先做“模拟删除”打印清单,确认后再物理删除。
下面示例脚本读取app.json,收集pages与subpackages里的页面,并简单匹配pages目录下是否存在未被声明的.wxml与.js。实际项目可进一步解析每个页面的json中usingComponents来追踪组件,再追踪组件用到的图片。此处给出基础框架:
const fs = require('fs');
const path = require('path');
const appJson = JSON.parse(fs.readFileSync('./app.json', 'utf8'));
const usedPages = new Set(appJson.pages);
if (appJson.subpackages) {
appJson.subpackages.forEach(sub => {
sub.pages.forEach(p => usedPages.add(sub.root + '/' + p));
});
}
const pageDir = './src/pages';
const allPageFiles = fs.readdirSync(pageDir);
const unused = [];
allPageFiles.forEach(folder => {
const pagePath = 'pages/' + folder + '/' + folder;
if (!usedPages.has(pagePath)) {
unused.push(path.join(pageDir, folder));
}
});
console.log('待清理页面目录:');
unused.forEach(u => console.log(u));
// 确认无误后取消下一行注释执行删除
// unused.forEach(u => fs.rmSync(u, { recursive: true, force: true }));
该脚本只处理了页面级冗余,图片清理可类似实现:提取所有.wxml与.js里的src和require路径,建立白名单,其余images文件即视为无用。将这类逻辑组合进npm run clean指令,每次发版前自动跑一遍,可长期保持包体健康。
在执行自动清理时,务必把脚本加入.gitignore保护或仅在本地构建机运行,防止误删正在被动态路径引用的资源。例如某些图片地址是接口下发的,并不写死在前端,这类资源不应被脚本清除,需要维护一份例外清单。通过人工配置例外项加自动扫描,才能既安全又高效地瘦身。