4、包体积优化:代码分包策略、图片资源压缩、无用代码移除

抖音小程序的包体积,说白了就是你的「入场券」。

我记得刚做小程序那会儿,团队吭哧吭哧写了一个月,结果上传代码时提示「主包超过2MB」。当时整个人都懵了。后来我才明白,包体积优化不是锦上添花,而是生死线。今天咱们就聊聊怎么把这体积降下来。

4.1 代码分包策略:别把所有鸡蛋放一个篮子里

抖音小程序有个硬性规定:主包不能超过2MB,整个小程序不能超过20MB。你想想看,一个页面带点图片、带点组件,分分钟就超了。

我个人的习惯是:先拆再写。不是等代码写完了再想怎么拆,而是项目初始化时就规划好分包结构。

4.1.1 分包的基本规则

分包的核心思路很简单:把不常用的页面扔到分包里。比如用户设置、帮助中心、活动页这些,用户不会一进来就点。

// app.json 分包配置示例
{
  "pages": [
    "pages/index/index",
    "pages/home/home"
  ],
  "subPackages": [
    {
      "root": "packageA",
      "pages": [
        "pages/setting/setting",
        "pages/help/help"
      ]
    },
    {
      "root": "packageB",
      "pages": [
        "pages/activity/activity",
        "pages/coupon/coupon"
      ]
    }
  ]
}
我的小技巧:分包名用「packageA」「packageB」这种命名,别用「user」「order」这种业务名。为什么?因为业务会变,今天叫user,明天改叫profile,改起来麻烦。

4.1.2 独立分包:让用户少等几秒

独立分包是个好东西。它不依赖主包,可以单独加载。我在做电商小程序时,把「秒杀页面」做成了独立分包。用户从分享链接点进来,直接加载秒杀页,不用等主包加载完。

{
  "subPackages": [
    {
      "root": "packageFlash",
      "pages": [
        "pages/flash/flash"
      ],
      "independent": true  // 独立分包
    }
  ]
}
注意:独立分包不能引用主包里的资源。如果你在独立分包里用了主包的公共组件,那它就不是独立分包了。我踩过这个坑,排查了半天。

4.1.3 预加载分包:提前加载,体验丝滑

用户从A页面跳到B页面,如果B在分包里,加载会有延迟。怎么办?预加载。

{
  "preloadRule": {
    "pages/index/index": {
      "network": "all",
      "packages": ["packageA"]
    }
  }
}

这样用户在首页时,系统已经在后台悄悄加载packageA了。等用户点击跳转,瞬间打开。

4.2 图片资源压缩:一张图省出100KB

小程序里最占体积的,往往不是代码,而是图片。我见过一个项目,光图片就占了1.5MB,代码才500KB。

4.2.1 图片格式怎么选

格式 适用场景 压缩率
JPEG 照片、渐变图
PNG 图标、透明图
WebP 通用(推荐) 极高
SVG 简单图标 极小

我个人强烈推荐WebP。同样的图片,WebP比PNG小30%-50%。抖音小程序原生支持WebP,放心用。

4.2.2 压缩工具怎么选

我常用的工具就两个:

  • TinyPNG:在线压缩,支持PNG和WebP。拖进去就行,傻瓜式操作。
  • ImageOptim:Mac端工具,批量压缩,能去掉图片里的EXIF信息(那些拍摄参数、GPS坐标,小程序里根本用不上)。

避坑指南:我曾经把一张1920x1080的图片直接放进了小程序。后来发现,手机屏幕才375x667,加载那么大图干嘛?先缩放到实际显示尺寸的2倍(适配Retina屏),再压缩。一张图从500KB变成了30KB。

4.2.3 图片放在哪里

能放CDN就别放本地。本地图片会打进包体里,CDN图片只占一个URL。

// 错误做法:本地图片
<image src="/images/banner.png" />

// 正确做法:CDN图片
<image src="https://cdn.example.com/banner.png" />

但注意:首屏的关键图片(比如首页Banner)建议放本地。因为CDN加载有网络延迟,首屏体验更重要。非首屏的图片,全扔CDN。

4.3 无用代码移除:别让死代码占地方

项目做久了,代码里难免有「僵尸代码」——写了但没用的函数、注释掉的代码块、重复的工具方法。这些代码不会报错,但会白白增加包体积。

4.3.1 手动清理:最笨但最有效

我每两个月会做一次「代码大扫除」。打开项目,搜索以下关键词:

  • // TODO —— 看看是不是忘了删
  • console.log —— 调试完记得删掉
  • function unused —— 没被调用的函数

嗯,这里要注意:别用全局搜索「删除」。我建议用VS Code的「引用查找」功能,右键点击函数名,看看有没有被调用。没被调用的,删。

4.3.2 工具辅助:让机器帮你找

手动清理太累,我推荐用工具:

  • ESLint + no-unused-vars:自动检测未使用的变量和函数。
  • Webpack Bundle Analyzer:可视化分析包体积,一眼看出哪个模块最大。
// 安装依赖
npm install --save-dev webpack-bundle-analyzer

// 在构建配置中启用
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
};

运行后浏览器会打开一个交互式图表。你一看就知道:哦,原来这个组件占了200KB,那个库占了500KB。然后决定要不要替换。

4.3.3 Tree Shaking:自动摇掉死代码

Tree Shaking是Webpack自带的功能。它会把「只导入但没使用」的代码自动移除。

// 错误导入:整个库都打包进来了
import _ from 'lodash';

// 正确导入:只打包用到的函数
import { debounce } from 'lodash';

但注意:Tree Shaking只对ES Module有效。如果你用CommonJS(require),它摇不动。所以写代码时尽量用importexport

我的经验:很多第三方库(比如moment.js)体积很大。我一般用day.js替代,体积只有moment的1/10。或者直接用原生Date方法,连库都不用引。

4.4 实战:一个优化案例

我接手过一个项目,包体积从3.2MB优化到了1.1MB。怎么做的?

  1. 分包:把「个人中心」「订单列表」「帮助中心」拆到分包里,主包从2.1MB降到1.3MB。
  2. 图片压缩:所有PNG转WebP,缩放到实际尺寸,从800KB降到200KB。
  3. 移除无用代码:删掉了3个没用的工具函数、2个废弃的页面、一堆console.log,省了150KB。
  4. 替换第三方库:把moment.js换成day.js,省了300KB。

你看,其实没什么高深的技术。就是该拆的拆、该压的压、该删的删。但很多人就是懒得做。

最后说一句:包体积优化不是一次性工作。每次发版前,都看一眼包体积。养成习惯,你会发现——原来2MB的包,也能装下这么多东西。