小程序—解析分包过程、独立分包、分包预下载、分包异步化

1,913 阅读5分钟

一、什么是分包

随着业务量加大,小程序包的体积可能越来越大,小程序规定,包的大小不能超过2M

  • 当前小程序代码大小可通过:详情->基本信息->本地代码中去查看

  • 可通过点击旁边的“代码依赖分析”查看具体的内容所占的体积

我们可以将用户打开小程序时就需要依赖加载的内容放到“主包”中,将后续需要的话再去加载的内容放到“分包”中:

所谓的主包,即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。

目前小程序分包大小有以下限制:

  • 整个小程序所有分包大小不超过 20M
  • 单个分包/主包大小不能超过 2M

二、如何进行分包

小程序中规定,tabbar相关的页面是不能放到分包中的

  • 比如我们可将点击某一项进入的详情页面放到一个分包中
  • 每个分包中可有自己的assets、pages、components等

2-1、 创建分包文件夹

2-2、移动相关页面

2-3、去除app.json中这些页面的配置并修改跳转相关代码

去除在pages中配置的这些页面:

修改之前跳转的相关代码,由于放在了packageDetail的pages下了,所以要加一层“packageDetail”

2-4、在app.json中配置“subPackages”告知小程序哪些是分包

如:

"subPackages": [
  {
    "root": "packageDetail",
    "name": "pDetail",
    "pages": [
      "pages/detail-songs/index",
      "pages/detail-video/index",
      "pages/search-detail/index"
    ]
  }
]
  • root用来告知分包的入口
  • name用来起别名(不是必须配置的),如果root文件夹名称过长此时可配置别名来代替
  • pages用来配置其下分出来的页面所在路径的,注意这时候就不需要加前缀“packageDetail”了,因为root已经标识了,也需要注意前面不要加“/” 此时点击详情查看时,本地代码处便多了个下拉按钮,可查看到主包与分包大小信息:

三、什么是独立分包

分包是需要依赖主包中内容的则不是独立分包(如api接口获取到的数据等),如果不依赖于主包中的任何内容时可设置为独立分包。

独立分包在配置时,在分包配置的基础上,增加 "independent": true配置项即可,如:

"subPackages": [
  {
    "root": "a",
    "pages": [
      "pages/a/index"
    ],
    "independent": true
  }
]

此外,在使用独立分包时,要注意一些限制:

  • 独立分包中不能依赖主包和其他分包中的内容,包括 js 文件、template、wxss、自定义组件、插件等(使用 分包异步化时 js 文件、自定义组件、插件不受此条限制)
  • 主包中的 app.wxss 对独立分包无效,应避免在独立分包页面中使用 app.wxss 中的样式;
  • App 只能在主包内定义,独立分包中不能定义 App,会造成无法预期的行为;
  • 独立分包中暂时不支持使用插件

详情可参考文档:独立分包

四、分包预下载

当我们进行分包后,会产生一个问题:由于用户刚一进来时只加载主包中内容,虽然打开小程序加载变快了,但是在进行其他操作,比如跳转详情页面时才去加载分包内容,这样会导致跳转缓慢。

那么是否可以在打开小程序后一段时间处于闲置状态时将所依赖的分包慢慢下载下来呢?这样既可以提高首屏打开速度,又可以提高跳转速度。

此时,就可以使用分包预下载

  • 分包预下载目前只支持通过配置方式使用,暂不支持通过调用API完成

此时需要在app.json中通过配置preloadRule来实现:

如:

  "preloadRule": {
    "pages/home-music/index": {
      "network": "all",
      "packages": [ "packageDetail" ]
    }
  }
  • key值表示进入主包中的哪个页面时开始加载分包内容
  • network用来指定什么样的网络状态下才加载分包,默认值为"wifi",可以配置为"all",表示不管是wifi还是移动网络都进行加载
  • packages用来指定加载哪些分包,可以是配置的分包的root名,也可以是配置分包的name名

五、分包异步化

比如分包1中要依赖分包2中的内容,在小程序中,不同的分包对应不同的下载单元;因此,除了非独立分包可以依赖主包外,分包之间不能互相使用自定义组件或进行 require。

分包异步化特性将允许通过一些配置和新的接口,使部分跨分包的内容可以等待下载后异步使用,从而一定程度上解决这个限制。

5-1、跨分包自定义组件引用

一个分包使用其他分包的自定义组件时,由于其他分包还未下载或注入,其他分包的组件处于不可用的状态。通过为其他分包的自定义组件设置 占位组件,我们可以先渲染占位组件作为替代(可以是该分包中的自定义组件、也可以是原生组件),在分包下载完成后再进行替换。

通过在该页面中的json文件中,配置componentPlaceholder来实现:

{
  "usingComponents": {
    "button": "../../commonPackage/components/button",
    "list": "../../subPackageB/components/full-list",
    "simple-list": "../components/simple-list"
  },
  "componentPlaceholder": {
    "button": "view",
    "list": "simple-list"
  }
}

在这个配置中,button 和 list 两个自定义组件是跨分包引用组件,其中 button 在渲染时会使用内置组件 view 作为替代,list 会使用当前分包内的自定义组件 simple-list 作为替代进行渲染;在这两个分包下载完成后,占位组件就会被替换为对应的跨分包组件。

5-2、跨分包 JS 代码引用

如果在一个分包中引入了另一个分包的js代码,由于另一个分包还未加载,为了防止阻塞此分包代码运行,需要异步获取引用结果:

// 使用回调函数风格的调用
require('../subPackageB/utils.js', utils => {
  console.log(utils.whoami)
})
// 或者使用 Promise 风格的调用
require.async('../commonPackage/index.js').then(pkg => {
  pkg.getPackageName()
})