微信小程序开发(三):分包加载

微信小程序分包加载

小程序开发完成后,开发者需要将代码包上传到小程序管理后台上线,这时候我们会发现,小程序后台对开发者上传的代码包有严格的大小要求:本地代码超过2M就会限制上传

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

1、单个分包\主包大小不能超过2M
2、 整个小程序所有包大小不能超过20M

这种情况下,我们需要将小程序划分成不同的子包,在构建时打包成不同的分包,用户可以在使用时根据实际需要进行加载,这样可以优化小程序首次启动的下载时间

使用分包加载的小程序中包含一个主包一个或多个分包,所谓的主包,放置默认启动页面和TabBar页面,以及一些所有分包都会用到的公共资源和JS脚本;分包中的内容根据开发者的配置进行划分。

如何进行分包

下面这张图是我创建的一个支持分包操作的小程序项目结构:
微信小程序开发(三):分包加载_第1张图片
如上图所示,我用微信开发工具创建了一个QuickStart项目,然后在根目录下增加了packageApackageB两个分包文件夹,这两个文件夹就是要进行分包操作的部分。

我们通过在app.json文件中subpackages字段中配置项目分包结构:

{
  "pages":[
    "pages/index",
    "pages/logs"
  ],
  "subpackages": [
    {
      "root": "packageA",
      "name": "packageA",
      "pages": [
        "pages/cat"      ]
    }, {
      "root": "packageB",
      "name": "packageB",
      "pages": [
        "pages/apple"
      ]
    }
  ]
}

root:分包根目录
name:分包别名,在分包预下载会用到
pages:分包页面路径,相对分包根目录
independent:分包是否是独立分包

打包的原则

1、配置subpackages字段后,开发工具会按照subpackages配置的路径打包,subpackages字段的每个子元素会根据对应配置打包成一个分包subpackages配置之外的目录将被打包到主包中

2、app.json文件中最外层的pages字段配置的是主包的页面路径

3、subpackages的根目录不能是另一个subpackages内的子目录,这句话的意思是,小程序的子包中不能再嵌套子包(禁止套娃~)

4、TabBar页面必须在主包内

分包小程序中的文件引用

子包可以引用主包中的公共文件,也可以引用自己的包内文件,但不可以引用另一个子包内的文件。
资源文件、template、JS脚本都需要遵守这一引用原则(分包隔离原则),但是在分包异步化时JS脚本不受限制

独立分包

独立分包一种特殊类型的分包,它可以独立于主包和其他分包运行。从独立分包中的页面进入小程序时,不需要下载主包,当用户进入普通分包或者主包所属的页面时,主包才会被下载。

由于不需要首先下载主包,独立分包可以很大程度上提高分包页面的启动速度

通过在app.json文件中的subpackages字段中配置independent字段来声明对应分包是否为独立分包,在下面的示例代码中,packageB分包就被声明为独立分包:

{
  "pages":[
    "pages/index",
    "pages/logs"
  ],
  "subpackages": [
    {
      "root": "packageA",
      "name": "packageA",
      "pages": [
        "pages/cat"      ]
    }, {
      "root": "packageB",
      "name": "packageB",
      "pages": [
        "pages/apple"
      ],
       "independent": true
    }
  ]
}
使用独立分包的注意事项

1、独立分包可以独立于主包和普通分包运行,所以独立分包中不能有依赖主包和其他分包的内容(JS文件、template、WXSS等),也就是说,公共样式对独立分包无效

2、App只能在主包中定义,不能再独立分包中定义

3、独立分包运行时,App可能没有注册 (用户从独立分包进入小程序时,主包不存在,所以也就没有App对象)独立分包中的getApp()可能无法获得App对象。所以开发者无法通过App对象实现独立分包和其他包之间的全局变量共享,为了解决这个问题,getApp支持allowDefault参数,在App未定义时返回一个默认对象,当主包加载时,默认对象中定义的属性会被覆盖合并到真正的App中。

// 独立分包中有以下代码:
const app = getApp({allowDefault: true}) // {}
app.data = 456
app.global = {}
// app.js
App({
  data: 123,
  other: 'hello'
})

console.log(getApp()) // {global: {}, data: 456, other: 'hello'}

如同上面两段代码所示,小程序由独立分包中的页面进入,这时程序没有加载主包,所以没有App对象,在代码中使用getApp方法可能会出现问题,这时候我们在getApp方法时使用allowDefault参数,之后就可以正常使用app对象了;

当主包加载后,App对象被注册,这时候我们在独立分包中定义的属性会被覆盖合并到主包的App中。

分包预下载

1、进入小程序某一个页面时,自动预下载可能需要的分包,这样可以提高分包页面加载速度
2、由独立分包页面进入的小程序,也可以从独立分包中预加载主包
3、分包预下载目前只支持通过配置方式使用
4、同一个分包的页面合计只有2M的预下载限额

配置方法

如下面代码所示,在app.json中设置分包预下载时,需要配置两个字段:
subpackages字段,在这个字段中进行分包设置;
preloadRule字段,在这个字段中进行预下载设置,preloadRule字段的值是一组key-value,其中key的值是可以触发预下载的页面路径,value的值是在此页面下的预下载配置,配置的字段包括连个:

  • packages:字符串数组,是需要预下载分包的root或者name,如果值为_APP_表示预下载主包
  • network:字符串,指定可以预下载的网络条件(all:不限网络,只要有网就可以触发预下载;wifi:WiFi下会触发预下载)
{
  "pages": ["pages/index"],
  "subpackages": [
    {
      "root": "important",
      "pages": ["index"],
    },
    {
      "root": "sub1",
      "pages": ["index"],
    },
    {
      "name": "hello",
      "root": "path/to",
      "pages": ["index"]
    },
    {
      "root": "sub3",
      "pages": ["index"]
    },
    {
      "root": "indep",
      "pages": ["index"],
      "independent": true
    }
  ],
  "preloadRule": {
    "pages/index": {
      "network": "all",
      "packages": ["important"]
    },
    "sub1/index": {
      "packages": ["hello", "sub3"]
    },
    "sub3/index": {
      "packages": ["path/to"]
    },
    "indep/index": {
      "packages": ["__APP__"]
    }
  }
}

分包异步化

分包异步化是一个比较新的特性,是为了解决分包加载中出现的一系列问题而出现的。
原有的分包隔离机制(指分包之间无法相互引用)导致各分包之间无法引用自定义组件或JS代码,导致分包出现一系列难题。

分包异步化能力打通了不同分吧之间的引用关系,支持跨分包组件、跨分包方法,我们可以通过分包异步化这一特性,通过一些配置和接口使部分内容可以跨分包使用(等待下载,异步使用)

自定义组件跨分包引用

自定义组件的跨分包使用是借助占位组件来实现的,在其他分包没有加载时,通过渲染占位组件替代未下载分包的自定义组件,等分包下载完成后进行替换。

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

// subPackageA/pages/index.json
{
  "usingComponents": {
    "button": "../../commonPackage/components/button",
    "list": "../../subPackageB/components/full-list",
    "simple-list": "../components/simple-list"
  },
  "componentPlaceholder": {
    "button": "view",
    "list": "simple-list"
  }
}
JS脚本跨分包

JS代码跨分包使用时,为了避免出现阻塞,需要使用异步获取引用。

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

你可能感兴趣的:(微信开发,微信小程序)