一、app.json配置属性之subpackages和preloadRule
1.subpackages
分包的功能主要是实现小程序按需加载,进入分包页面才会进行分包的加载。
在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包小程序必定含有一个主包。所谓的主包,即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。
在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。
目前小程序分包大小有以下限制:
整个小程序所有分包大小不超过 20M
单个分包/主包大小不能超过 2M
对小程序进行分包,可以优化小程序首次启动的下载时间,以及在多团队共同开发时可以更好的解耦协作。
2.preloadRule
当分包预加载以后,我们进入这个包所在的页面后就会流畅运行了,因为资源已经事先加载
。
二、小程序普通分包配置
{ "entryPagePath": "pages/index/index", "pages": [ "pages/index/index", "pages/getOpenId/index", "pages/getMiniProgramCode/index", "pages/deployService/index", "pages/createCollection/index", "pages/uploadFile/index", "pages/selectRecord/index", "pages/updateRecord/index", "pages/updateRecordResult/index", "pages/updateRecordSuccess/index", "pages/sumRecord/index", "pages/sumRecordResult/index" ], "subPackages": [ { "root": "packageA", "pages": [ "pages/cat/cat", "pages/dog/dog" ] }, { "root": "packageB", "pages": [ "pages/apple/apple", "pages/banana/banana" ] } ], "window": { "backgroundColor": "#F6F6F6", "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#F6F6F6", "navigationBarTitleText": "云开发 QuickStart", "navigationBarTextStyle": "black" }, "tabBar": { "list": [ { "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/getOpenId/index", "text": "看资讯" }, { "pagePath": "pages/getMiniProgramCode/index", "text": "我的" } ], "backgroundColor": "#fff", "color": "#000", "selectedColor": "#0286f1" }, "networkTimeout": { "request": 10000, "downloadFile": 10000, "connectSocket": 10000, "uploadFile": 10000 }, "sitemapLocation": "sitemap.json", "style": "v2", "debug":true }
1.打包原则
声明 subpackages 后,将按 subpackages 配置路径进行打包,subpackages 配置路径外的目录将被打包到
app(主包) 中
app(主包)也可以有自己的 pages(即最外层的 pages 字段)
subpackage 的根目录不能是另外一个 subpackage 内的子目录
tabBar 页面必须在 app(主包)内
2.引用原则
packageA 无法 require packageB JS 文件,但可以 require app、自己 package 内的 JS
文件;使用 分包异步化 时不受此条限制
packageA 无法 import packageB 的 template,但可以 require app、自己 package 内的
template
packageA 无法使用 packageB 的资源,但可以使用 app、自己 package 内的资源
三、小程序独立分包配置
独立分包属于分包的一种。普通分包的所有限制都对独立分包有效。独立分包中插件、自定义组件的处理方式同普通分包。
此外,使用独立分包时要注意:
独立分包中不能依赖主包和其他分包中的内容,包括 js 文件、template、wxss、自定义组件、插件等(使用 分包异步化 时 js
文件、自定义组件、插件不受此条限制)
主包中的 app.wxss 对独立分包无效,应避免在独立分包页面中使用 app.wxss 中的样式;
App 只能在主包内定义,独立分包中不能定义 App,会造成无法预期的行为;
独立分包中暂时不支持使用插件。
const app = getApp({allowDefault: true}) // 分包中默认定义进入主包App会重新覆盖 app.data = 456 app.global = {}
App({ data: 123, other: 'hello' }) console.log(getApp()) // {global: {}, data: 456, other: 'hello'}
四、小程序分包预加载配置
{ "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__"] } } }
五、分包异步化
在小程序中,不同的分包对应不同的下载单元;因此,除了非独立分包可以依赖主包外,分包之间不能互相使用自定义组件或进行 require。「分包异步化」特性将允许通过一些配置和新的接口,使部分跨分包的内容可以等待下载后异步使用,从而一定程度上解决这个限制。
1.跨分包自定义组件引用
一个分包使用其他分包的自定义组件时,由于其他分包还未下载或注入,其他分包的组件处于不可用的状态。通过为其他分包的自定义组件设置 占位组件,我们可以先渲染占位组件作为替代,在分包下载完成后再进行替换。例如:
// 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" } }
在这个配置中,button 和 list 两个自定义组件是跨分包引用组件,其中 button 在渲染时会使用内置组件 view 作为替代,list 会使用当前分包内的自定义组件 simple-list 作为替代进行渲染;在这两个分包下载完成后,占位组件就会被替换为对应的跨分包组件。
2.跨分包 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' })
在其它分包中的插件也可以通过类似的方法调用:
// 使用回调函数风格的调用 requirePlugin('live-player-plugin', livePlayer => { console.log(livePlayer.getPluginVersion()) }) // 或者使用 Promise 风格的调用 requirePlugin.async('live-player-plugin').then(livePlayer => { console.log(livePlayer.getPluginVersion()) })