引言
在使用Taro开发偏大型小程序应用过程中,我们可能经常会遇到这么个问题:小程序的主包体积超过了2M,没办法发布。针对这个问题,本文讲一讲我在业务中经常使用到的4种优化手段。
优化方式
页面分包
微信主包体积限制2MB
主包空间寸土寸金,仅放置默认启动页面/TabBar 页面,其他页面均迁移至分包。这也是主包体积最基本的优化方式。
公共模块分包
改造后分包加载的页面体积不计入主包体积内,但是在默认配置下被多个页面所引用的模块会被打包进主包。这里截取了未做优化页面分包后直接打包后的代码依赖分析图。其中:
common.js
包含了业务中的公共组件、工具方法、hooks
等逻辑common.wxss
包含了业务中公共组件的样式、全局样式vendors.js
包含了三方依赖逻辑
解决方案
那么我们能不能识别哪些页面使用了这些公共模块,如果某个公共模块虽然被多个分包使用,但是使用它的分包均不在主包中那么我们这个模块是不是应该被打包进对应的分包内减少主包体积占用。
技术实现
Taro
配置mini.optimizeMainPackage
就能实现这一功能Taro
官方对这一配置的描述是:可以避免主包没有引入的module
不被提取到commonChunks
中,该功能会在打包时分析module
和chunk
的依赖关系,筛选出主包没有引用到的module
把它提取到分包内。
开启mini.optimizeMainPackage
后的代码依赖分析图如下:
源码解析
那么Taro
是如何实现这一功能的呢?我们来看源码:
- 收集分包入口数据用于后续判断
chunk
是否属于分包
1 | typescript复制代码const PLUGIN_NAME = 'MiniSplitChunkPlugin' |
- 找到分包入口
chunk
。循环构成chunk
的module
。其中没有被主包引用,且被多个分包引用的记录在subCommonDeps
中。并基于subCommonDeps
生成新的cacheGroups
配置用于SplitChunksPlugin
作为配置拆分chunks
。
1 | javascript复制代码const PLUGIN_NAME = 'MiniSplitChunkPlugin' |
- 在
SplitChunksPlugin
完成chunks
拆分后收集分包下的sub-vendors
和sub-common
下的公共模块信息
1 | typescript复制代码export default class MiniSplitChunksPlugin extends SplitChunksPlugin { |
- 基于收集的分包下的
sub-vendors
和sub-common
下的公共模块信息。为分包require
对应公共模块。SplitChunksPlugin
导出路径为编译产物根目录即主包根目录,这里为了不占主包体积所以这里需要将sub-common
迁移至对应分包,故此处require
的文件路径都是基于分包根目录。
1 | typescript复制代码export default class MiniSplitChunksPlugin extends SplitChunksPlugin { |
require
的文件路径基于分包根目录。所以对应的文件也需要做迁移。
1 | typescript复制代码export default class MiniSplitChunksPlugin extends SplitChunksPlugin { |
以上就是 MiniSplitChunksPlugin
实现公共模块分包的核心流程
引用方式
在完成公共模块分包后主包体积的确有所减少,但是在后续的迭代中发现公共组件并没有全部都按页面分包打包。以@/components
举例,通过排查发现@/components
是通过index.ts
统一导出内部的子模块页面通过import { ComponentName } from '@/components'
方式引入。
而这种导出方式会使webpack
将这个@/components
识别为一个单独模块,由于主包内存在页面引用@/component
下的公共组件,所以@/components
会被完整的打包进主包内。
解决方案
解决方法也很简单就是将@/components
修改为@/components/component-path
,跳过index.ts
直接引用内部组件文件。
那么我们如何将现存项目中使用的组件引用路径都替换掉呢?
- ❎ 人工逐个替换
- 需要修改使用到公共组件的业务代码工作量大且易出错
- 且后续全局组件使用也较繁琐需要直接引用文件路径
@/components/component-path
。
- ✅ 使用
babel
插件批量替换- 仅需引入插件
babel-plugin-import
做对应配置,无需修改业务代码。 - 开发无感,
@/components
的使用方式不变
- 仅需引入插件
技术实现
- 引入插件
babel-plugin-import
,并配置组件路径与组件文件路径之间的转换关系
1 | javascript复制代码module.exports = { |
- 按照配置的文件名与文件路径之间的转换关系定义组件
1 | javascript复制代码// component file -> @/components/component-a |
这里需要注意如果组件路径与组件名不符合所配置的规范,编译时会找不到对应的组件。
图片资源优化
这里截取了「古茗点单小程序」在不采用其他优化手段直接将图片资源打包后的代码依赖分析图,可以看到其中图片资源的尺寸足足有22.07MB
,这与微信限制的主包大小2MB
整整相差了20MB
。
解决方案
我们可以将这22.07MB
的图片资源上传至云端。在小程序使用时直接使用网络路径。那么打包时这部分资源尺寸就不会计算在主包尺寸中。
那么我们如何将现存项目中使用的图片资源路径替换成网络路径?
- ❎ 人工逐个替换
- 需要修改使用到图片资源的业务代码工作量大且易出错
- 且后续图片资源使用也很繁琐需要开发上传图片资源后使用网络地址编码。
- ✅ 使用
babel
插件批量替换- 仅需要实现对应的
babel
插件逻辑并引入,无需修改业务代码 - 开发无感,图片资源的使用方式不变
- 仅需要实现对应的
技术实现
- Taro 编译开始时使用
taro
插件上传本地图片资源
1 | typescript复制代码import type {IPluginContext} from '@tarojs/service' |
- 使用
babel
插件替换ts
或js
中导入的图片
1 | typescript复制代码import type {NodePath, PluginItem, PluginPass} from '@babel/core' |
- 使用
postcss
插件替换样式文件中导入的图片
1 | typescript复制代码import {AcceptedPlugin} from "postcss"; |
总结
这里介绍了页面分包、公共模块分包和图片资源优化的方式优化小程序包体积。我们还可以共同探讨其他优化策略如:TS枚举编译优化、小程序分包异步化、提取公共样式、原子化样式组件等。
最后
📚 小茗文章推荐:
关注公众号「Goodme前端团队」,获取更多干货实践,欢迎交流分享~
本文转载自: 掘金