uniapp分包(详尽版)
PS:本文是笔者对基于uniapp的一小程序项目进行分包后的复盘文档,不足之处请多多指教。
一:分包相关概念
-
本质上是改变项目的路由以及优化项目各个模块的启动时间的一种优化技术。
-
主包与分包的概念
1). 主包:本项目中初始化时所必须的页面。
项目在启动时,将从主包进入,分包在用户未进入时不会加载,只有在进入分包模块时才会加载。
tabbar页面以及模块间共有的页面,如果该项目有账号限制(即非注册账号不可进入主界面),也应将登录页放置在主包内
2). 分包:除主包外的所有页面都应放置在分包内,为避免读者混淆,本文会将该分包定义为子包
二:为什么要分包
优化项目首次启动的下载时间;小程序默认就是整包(主包)下载,但这会导致整个项目只有在全部加载完毕后才会回显到用户眼前,这样虽然可以使用加载动画进行优化,但也会有部分可能导致用户流失;
防止项目超出小程序官方对小程序项目打包后的大小限制;
若不分包,整个程序最大限制不能超过2M,分包后,整个项目(包含主包+子包)最大不能超过16M,单个包不能超过2M (这样就规避了项目最大不得超过2m的限制)
三: 分包基本逻辑
- 静态文件:分包下支持 static 等静态资源拷贝,即分包目录内放置的静态资源不会被打包到主包中,也不可在主包中使用
- js文件:当某个 js 仅被一个分包引用时,该 js 会被打包到该分包内,否则仍打到主包(即被主包引用,或被超过 1 个分包引用)
- 自定义组件:若某个自定义组件仅被一个分包引用时,且未放入到分包内,编译时会输出提示信息
四: 分包步骤详解
PS: 由于笔者仅做了微信小程序分包,因而以下也仅对面向微信小程序的uniapp项目有效
PS: 笔者是tabbar页作为单模块划分子包,即每个tabbar均作为一个子包模块
- (manifest.json ) 开启分包优化
添加相关字段
// "mp-weixin"
"optimization":{
"subPackages":true //是否启用分包优化
}
- (pages.json) 声明项目分包结构
- pages:
原则:pages内只允许存放tabbar页面路由,以及各个子包所共有的页面页面,如果有登录页且不登录无法进入主页面,该登录页面路由也应放置在pages路由内
- subPackages:
定义:单个模块内的除主包内文件的所有的文件,
比如: 假设一个tabbar模块内原本有index(tabbar页).vue,notice.vue,about.vue这三个页面,将index.vue这个页面路由放置pages.json中的pages数组内,对应的将index.vue放置在项目中的pages目录内
假设notice.vue与about.vue没有在别的tabbar模块中被使用,则应该将notice.vue和about.vue两个页面文件放置在subPackages中
若notice.vue与about.vue这两个页面中有被别的模块使用,则同样应该将其放置在pages主包内,为防止其与其他tabbar页面混淆,应该在pages目录内再单独开辟一个目录专门用于存放共有页
弄懂了以上原则,接下来便可以实践一下了
(pages.json)内新增subPackages字段,与pages同级,同样是数组格式,期内每一个对象均对应tabbar内的每一个模块,
(项目目录)每一个对象都应在项目中生成每一个目录,这个目录与pages目录同级
//pages.json
"pages":[
//这里仅存放tabbar,以及公共页
],
"subPackages":[
//subPackages数组里的每一个对象都代表了对应tabbar模块里的除tabbar中index.vue以外所有的页面,且该数组里每一个对象都在项目目录中与pages目录平级
//举个栗子 这里是首页模块,index.vue由于是tabbar页面,故而被放置在了pages.json中,剩余两个文件并没有被其他tabbar模块使用,因而被放置在了这里
{
"root":"pages_Index", //这里代表根目录的映射,表示在项目中这个模块的根目录也就是上面说的与pages目录平级的目录名
"pages":[ // 这里的pages表示分包内的页面,凡在该子包的pages目录下,均不可被其他子包模块访问
//这里指的是原本从pages页中迁移来的,仅本模块专属的页面,其格式规范遵循tabbar所在pages数组规范
{
// 网上有人说path路径必须由pages_Index根目录开始,但是在实践过程中发现不从根目录开始也可以,原因猜测是root本身已定义了根目录
// 原目录为: /pages_index/packet/notice
path":"packet/notice",
"style": {
"navigationBarTitleText": "我是子包文件"
}
},
]
}
]
目录结构如下:
pages.json如下:
这样便完成了配置的第二步
- 更换各个页面路由
笔者之前一直强调的分包越早越好的原因就在于此,一但项目到了微信2m限制,则会直接导致项目无法在开发者工具中运行,虽然分包可以在整个项目周期任一进度进行,但是需花费的时间是与项目进度是成正比的,即项目进度越到尾期,则分包需要花费的时间也就越长,笔者对此深有体会(流眼泪.jpg)
如果在项目中末期才进行分包,此时需要开发者站在整个项目角度上,对每个模块,每个页面,每个网络请求都要了然于胸,可以借助于思维导图工具,将项目所有模块所有页面都列出来,剔除tabbar页面和模块间共有页面,然后将剩余页面填充至指定子包目录下,并在subPackages目录下声明该页面路径,并且,开发者必须要重新定义路由跳转路径以及组件引入方式,这一点极为繁琐,且极易出错造成损失,因而建议开发者在走这一步前预先做好备份。
导入组件路径建议直接更换成以@开头的绝对路径来替换省略号开头的相对路径,防止以后可能再次发生的变更
跳转路由也应换成绝对路径,(路由更换后跳转失败? 请点击这里)
在本过程中,可能会出现各种引用错误或者无法跳转的问题,此时需要开发者心态平缓,并一定要谨慎检查
如果在开发者工具中运行整个项目显示没有报错信息,则可以在真机调试,如果有短时弹框 “ 加载模块中 ”,则表示分包成功
那么问题来了:我不想用户看到这几个丑陋的字,该怎么做?
出现这几个字的原因是由于用户刚进入的界面必定是主包,而在用户进入分包的时候,由于分包资源还未下载,所以微信官方便贴心的提示用户正在加载分包资源
笔者:微信我谢谢你呀!(超大声哔哔)
那么接下来要说的,就是关于这类问题的解决办法: 分包预加载
- (pages.json)实现分包预加载
定义:在用户进入某个页面时,同时静默下载跟该页面有关的子包文件
与subPackages平级添加preloadRule对象,
该对象内部的key指的是某个页面路径,也就是当用户进入某个页面时,需要预加载的页面路径,
value
//pages.json
//以子包pages_index为例
"subPackages":[
//分包模块
{
"root" : "pages_index",
"pages" : [
{
"path" : "packet/notice",
"style" : { "navigationBarTitleText": "我是子包页面"}
}
]
}
],
"preloadRule" :{
"pages/index/index":{ //要进行预加载时用户要进入的页面路径
"network":"all", // 什么网络下支持允许预加载,默认wifi: wifi/all
"packages":["pages_Index"] // 要进行预加载的子包名
},
}
使用分包预加载功能,
如果配置成功,开发者console控制台会输出以下信息:
- 几点原则
- 主包可以引用分包内文件,分包仅可引用自身目录内的文件,分包与分包间文件无法互相引用,
- 要清楚的是分包是一种不得已而为之的手段,确保在分包前项目中静态资源已优化完毕,且没有大量注释或无用代码也是一种手段
————————-假装这是一条分割线———————————————————-
这篇文章是笔者在复盘项目时的心得,不足之处欢迎在评论区指教,不胜感激
以上。