小程序体积优化

878 阅读5分钟

为什么要做体积优化

  • 微信小程序发布主包限制大小为2M,超出无法发布
    • 常见场景:日常开发打体验码大家会打开4M预览限制,本地预览是ok的,临近发布时,突然发现体积超了,阻塞发布,就会紧急处理一波,这样极其容易发生线上问题

怎么做优化

首先需要了解依赖分析

  • 打开微信小程序ide,点击图示 image.png
  • 目前是将整个项目打包到主包里,体积1.37M
  • 可以点击主包,查看更详细内容分布
  • 注意修改配置重新编译后,微信ide体积分布会展示不准确,关闭后重新进入ide即可

image.png

分包加载

小程序推荐采用分包形式解决体积问题

分包概念
  1. 每个分包的体积不可超出2M
  2. 分包不可引用其他分包内容,但可引用主包内容
  3. 主包不可引用分包内容
  4. 分包异步化可突破包之间的限制,实现任何包都可以访问分包
开始分包
  • 在app.config.json中配置subpackages

  • 以下为项目页面结构图示

  • image.png

  • 目前我们有3个页面,pages/index/index为主页面,那么sub中的两个页面就可以放到分包中去

  • 图示:将pages中目录去除,放到subpackages中

  • image.png

  • image.png

  • 可以看到目前主包体积变小,增加了两个分包

    • 疑问:这俩分包合起来也没超过2M,为啥分开拆,不能合并到一起吗?
    • 答:在微信和支付宝环境是可以的,但是在mpaas环境,一个分包只能放置一个页面,否则分包中的第二个页面跳转过去会白屏
组件的分包
  • 现在出现了一个问题,业务代码中,通常是会有通用组件的,那么这个通用组件存在三种情况
    • 主包分包都使用
    • 多个分包使用
    • 单个分包使用
  • 这几种情况在项目中的体现还各不相同,
    • 表现1:公共组件打包在主包
    • 表现2:每个分包打包一份,taro会帮我们自动cv到使用目录
      • image.png
    • 表现3:只有用到的分包打包一份
  • 但是当作公共组件的初衷就是为了多方使用,taro虽然帮我们处理了,但会增加总体积,比如组件体积为1,两个分包都使用,那么总体积就是4
  • 所以最佳方案应该是将组件真正的抽离,多方调用,而不是cv,那么我们先将组件打包为自定义组件,然后进行分包
  • 这种方案小程序称为分包异步化
分包异步化
  • 分包异步化简单来讲就是H5中异步加载的一种演变,在异步加载的过程中中,使用componentPlaceholder中指定的组件做替身(可以做loading),当资源加载好后进行自动替换
  • 我们在index.config.js中增加usingComponents和componentPlaceholder配置项
    • usingComponents
      • key要使用的组件别名
      • value为组件地址(相对本文件即可)
    • componentPlaceholder
      • key同上
      • value为替补渲染标签或组件
{
  usingComponents: {
    'ccc-container': '../../scopeComponent/cccContainer/index',
  },
  componentPlaceholder: {
    'ccc-container': 'view',
  },
}
  • 然后直接在页面里调用即可,usingComponents本身就是注册组件的意思,在页面级注册后,整个页面中都可以直接使用
<ccc-container />
  • 现在dist目录中增加了scopeComponent目录,但是查看目录包体积划分可以看到这个文件目前还算在主包中,所以我们需要在app.config.js的subPackages增加一个配置
  • image.png
subPackages: [
  {
      root: 'scopeComponent',
      pages: [],
    },
]

image.png

组件抽离后存在的问题
  1. 抽离后可能会存在一定的样式问题,所以需要自行校对
    • 可在自定义组件index同级目录增加index.config.js
export default {
  component: true,
  styleIsolation:'shared'
};
  1. 传参问题与组件调用模式
    • 比如我是使用vue3开发,那么我肯定期望抽离出去的组件是可以想vue一样去props传参数的,而不是像真正的小程序那样传递,那仅仅按照上述步骤,是参数是失效的,组件永远拿不到
    • 如何解决:
      • package.json 的taro build命令增加 --new-blended,开启新混合模式
      • 传递参数为props,不是直接传递,比如正常传递为a=1,b=2,现在为props={{a:1,b:2}}
      • app.config.ts中配置components属性,value为自定义组件地址Arrayimage.png
      • 图示:
      • image.pngimage.png
      • 新混合模式方案目前官方只适配了react,在vue3使用会出现vue自定义组件不渲染的问题,已在github上反馈,应该是bug
      • 对比了下前后dist产物,发现vue3混合模式下自定义组件的导入函数有变化,应该是这里有问题
插件体积优化
  • 开发过程中,可能会用到一些插件,那么这些插件通常是直接在app.config.js中直接注册,大概率会打包到主包中
    • 而且微信ide的依赖分析检测不出来,我们在发布的时候就可能被卡住
  • 可以选择结合分包异步化,将插件抽离到分包中
    • 然后封装分包自定义组件,在自定义组件中调用plugin内容
    • 正常运行代码调用自定义组件即可
app.config.js
// 原始写法
{
plugins:[xx]
}

// 分包写法
{
    subPackages:[
        {
            root: 'aaa',
            pages: ['index'],
            plugins:[xx]
        }
}
如何查看分包数量

在ide的控制台,可以看到目前有3个分包

image.png

预加载

如何配置?

配置preloadRule,指定某个分包资源提前加载

如何查看是否加载成功?

可以通过vconsole中的preloadSubpackages查看是否加载成功

预加载时机? 默认为当前页面ready后200ms触发,可通过index.config.json中的handleWebviewPreload参数调整

有什么限制?

同一批次预加载中,分包总体积不可超出2M

一些其他的点

base64链接过长,也会大量占用体积,可以改换成cdn