2、包体积优化(上):代码压缩与混淆、图片资源压缩(WebP/AVIF)、无用代码与资源清理

包体积优化,说白了就是给小程序「减重」。我见过太多团队,功能做了一大堆,结果包体积飙到 2MB、3MB,用户加载慢得想摔手机。其实很多体积都是「虚胖」——代码里藏着大量注释、冗余变量,图片还是几年前的 PNG 格式。今天咱们就从上手最快的三个方向开刀:代码压缩与混淆、图片格式升级、以及清理那些「僵尸代码」。

2.1 代码压缩与混淆:把「废话」去掉

代码压缩,就是把变量名缩短、去掉空格和注释。混淆则更进一步,把函数名、变量名改成 a、b、c 这种短名。两者配合,体积能直接砍掉 30%-50%。

我习惯在构建阶段用工具自动处理。微信开发者工具自带「上传时压缩代码」选项,但说实话,它只做了基础压缩。想要更狠的效果,得自己配 Webpack 或 Gulp。

核心思路:压缩后的代码,人类读不懂,机器跑得欢。这就够了。

2.1.1 使用 TerserPlugin 做深度压缩

Webpack 项目里,我最常用 TerserPlugin。它能把代码体积压到极限。配置起来也不复杂:

// webpack.config.js
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true,   // 干掉所有 console.log
            drop_debugger: true,  // 去掉 debugger 语句
            pure_funcs: ['console.log'] // 彻底移除
          },
          mangle: true,           // 混淆变量名
          output: {
            comments: false       // 去掉注释
          }
        }
      })
    ]
  }
};

这里有个坑:drop_console: true 会干掉所有 console 语句。我在项目中遇到过,上线后线上问题排查不了,因为所有日志都没了。后来我改成只保留 console.error

compress: {
  pure_funcs: ['console.log', 'console.info', 'console.warn']
}

注意:混淆后的代码,报错堆栈会变成 a、b、c。记得上传 sourcemap 到监控平台,否则线上报错你根本看不懂。

2.1.2 微信小程序原生压缩配置

如果你用原生开发,可以在 project.config.json 里开启:

{
  "setting": {
    "uglifyFileName": true,   // 压缩文件名
    "minified": true,         // 压缩代码
    "es6": true,              // ES6 转 ES5
    "postcss": true           // 自动补全 CSS 前缀
  }
}

嗯,这里要注意:es6: true 会转译语法,但也会增加一些 polyfill 代码。如果你的基础库版本够新(2.15.0+),可以关掉它,直接用原生 ES6 支持,反而能省点体积。

2.2 图片资源压缩:WebP 和 AVIF 是王道

图片往往是包体积的「大头」。我见过一个小程序,光图片就占了 1.2MB,其中大部分是 PNG 和 JPEG。你想想看,现在手机屏幕都是视网膜屏,一张 200KB 的 PNG 在 1x 图上根本看不出区别。

我个人习惯,能转 WebP 就转 WebP。如果条件允许,AVIF 更香。来看对比:

格式 压缩率(相对 PNG) 浏览器支持 适用场景
PNG 基准 全部 需要透明背景的图标
JPEG 约 60% 全部 照片、渐变图
WebP 约 30% 微信 7.0+、Chrome 大部分场景,推荐
AVIF 约 20% 微信 8.0+、Chrome 85+ 高压缩需求,注意兼容

2.2.1 批量转换 WebP

我一般用 cwebp 命令行工具,配合脚本批量处理:

# 安装工具
brew install webp

# 批量转换所有 PNG 和 JPG
for file in images/*.{png,jpg,jpeg}; do
  cwebp -q 80 "$file" -o "${file%.*}.webp"
done

-q 80 是质量参数。我测试过,80 的视觉损失几乎不可察觉,但体积能降 70%。如果你对图片质量要求极高,可以调到 90。

小技巧:微信小程序里,<image> 标签直接支持 WebP。你只需要把图片后缀改成 .webp,路径写对就行。不需要额外配置。

2.2.2 AVIF 的「坑」与「甜」

AVIF 压缩率确实牛,但我在项目中遇到过兼容问题。微信 8.0 以下版本不支持,部分 Android 机型也会闪退。我的做法是「降级方案」:

// 判断是否支持 AVIF
function supportsAvif() {
  const canvas = document.createElement('canvas');
  return canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0;
}

// 动态选择图片格式
const imgSrc = supportsAvif() ? 'photo.avif' : 'photo.webp';

说白了,AVIF 是未来,但现在还不是全部。我建议主力用 WebP,AVIF 作为「锦上添花」。

2.3 无用代码与资源清理:别让「僵尸」占地方

项目迭代久了,代码里会积累大量「僵尸」——废弃的页面、没用的组件、注释掉的代码块。这些东西不会报错,但会白白增加包体积。

我曾经接手过一个项目,里面竟然有 5 个版本的登录页面,只有 1 个在用。删掉之后,包体积直接少了 200KB。你想想看,这 200KB 要是用来放新功能多好。

2.3.1 使用 ESLint 检测未使用变量

ESLint 的 no-unused-vars 规则能帮你揪出「死代码」:

// .eslintrc.js
module.exports = {
  rules: {
    'no-unused-vars': ['error', {
      vars: 'all',        // 检查所有变量
      args: 'after-used', // 只检查未使用的参数
      ignoreRestSiblings: true
    }]
  }
};

配合 eslint --fix 可以自动删除未使用的 import。但要注意,有些变量是「全局引用」的,比如挂在 wx 对象上的方法,ESLint 可能误报。这时候加个注释忽略就行:

// eslint-disable-next-line no-unused-vars
const unusedVar = '这个变量确实没用,但我先留着';

警告:别用 /* eslint-disable */ 全局关闭规则。那等于掩耳盗铃。我见过有人为了省事,直接关掉所有规则,结果代码里一堆死变量,包体积越来越大。

2.3.2 清理无用图片和字体文件

图片资源最容易「藏污纳垢」。设计师经常往项目里丢一堆「备选图」,结果从来没用过。我的做法是:

  1. 全局搜索引用:在 IDE 里搜索图片文件名,看有没有被引用。
  2. 使用工具扫描unused-webpack-plugin 可以自动找出未引用的资源。
  3. 定期清理:每个迭代结束,跑一次清理脚本。
// webpack.config.js 中配置
const UnusedWebpackPlugin = require('unused-webpack-plugin');

plugins: [
  new UnusedWebpackPlugin({
    directories: [path.join(__dirname, 'images')],
    exclude: ['*.ico'],  // 排除 favicon
    root: __dirname
  })
]

跑完构建,控制台会列出所有未使用的文件。嗯,这时候别手软,直接删。

2.3.3 删除注释掉的代码块

很多人习惯把旧代码注释掉,想着「以后可能用」。说实话,我从来没见过谁真的回头去翻那些注释。Git 历史里都有,怕丢就提交一次再删。

我建议用正则全局搜索 /\*[\s\S]*?\*///.*,把大段注释干掉。但要注意,有些注释是文档说明,比如函数用途、参数含义,这些得保留。

我的原则:注释只解释「为什么」,不解释「是什么」。代码本身应该能说明「是什么」。如果代码读不懂,那是代码的问题,不是注释的问题。

2.4 实战:一个完整的优化流程

说了这么多,咱们串起来走一遍。假设你有一个 1.5MB 的小程序,目标是压到 1MB 以内:

  1. 先跑分析工具:用微信开发者工具的「代码依赖分析」,看看哪些文件最大。
  2. 压缩代码:配置 TerserPlugin,开启 drop_consolemangle。这一步能省 200KB-300KB。
  3. 转换图片:把所有 PNG/JPEG 转成 WebP,质量设 80。这一步能省 300KB-500KB。
  4. 清理僵尸:删掉未使用的页面、组件、图片。这一步能省 100KB-200KB。
  5. 验证功能:压缩和混淆后,一定要跑一遍核心流程。我遇到过混淆把 wx.navigateTo 的参数搞乱的情况。

做完这四步,1.5MB 降到 800KB 是很常见的。用户加载速度从 3 秒降到 1.5 秒,体验提升是实打实的。

最后提醒:包体积优化不是一锤子买卖。我建议每次发版前都跑一遍分析工具,把「增重」的部分揪出来。养成习惯,你的小程序会一直保持「苗条」。

下一章咱们聊「包体积优化(下)」,重点讲分包策略和动态加载。那些才是真正的大招,能把 2MB 的包拆成几个 500KB 的小包,用户打开速度直接起飞。