当前位置: 首页 > 科技观察

关于小程序分包的一些思考和Uiniapp分包优化逻辑的验证

时间:2023-03-13 14:22:33 科技观察

大家好,我是小智。今天,我带来了我在团队中的最新分享。什么是分包分包是指将一个完整的小程序项目按照需求分成不同的分包,在构建时打包成不同的分包,在用户使用时按需加载。分包的好处分包小程序的好处主要有:可以优化小程序第一次启动的下载时间,多个团队共同开发时可以更好的解耦和协同。包的uni-app目录结构如下:┌─pages│├─index││└─index.vue│└─login│└─login.vue├─pagesA│├─static│└─list│└─list.vue├─pagesB│├─static│└─detail│└─detail.vue├─static├─main.js├─App.vue├─manifest.json└─pages.json需要填写页面.json:{"pages":[{"path":"pages/index/index","style":{...}},{"path":"pages/login/login","style":{...}}],"subPackages":[{"root":"pagesA","name":"分包的别名""pages":[{"path":"list/list",“风格”:{。..}}]},{"root":"pagesB","pages":[{"path":"detail/detail","style":{...}}]}],}动手:https://github.com/qq449245884/uniapp-subpackage-demo/tree/feature/01.%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%88%86%E5%8C%85%E9%85%8D%E7%BD%AE运行后可以在开发者详情中查看分包信息:这样配置的目录结构真的好吗?按照官网上的例子,如果我们要分成两个包,那么在同级页面下创建两个目录pageA和pageB。这样分真的好吗?假设我们有一个活动业务模板,对应的活动详情地址为/pages/activity/detailpages.json配置如下:"pages":[{"path":"pages/index/index","style":{"navigationBarTitleText":"Homepage"}},{"path":"pages/activity/detail","style":{"navigationBarTitleText":"Eventdetails"}}],随着业务的发展,功能这个模块越来越多。哪天我们要分包这个包的时候,如果按照之前的分包方式,如果我们在pages同级下创建一个分包目录,假设我们这里叫它pagesA,然后把对应activity模块的文件移动他们到该目录下,对应的pages.json配置如下:"subPackages":[{"root":"pagesA","pages":[{"path":"activity/detail"}]}]在此time,对应的activity详情地址为/pagesA/activity/detail,会出现问题。此时活动明细的路径发生了变化,所以分包必须正常工作,必须改变之前的路径。如果有其他小程序跳转到详情页,也得修改。显然,这种分包结构是非常不可靠的。一个分包,需要修改多个文件,甚至多个小程序。那么如何解决这个问题呢?显然,只要路径不变,但包能正确分包,这个问题就可以解决。想到分包无非就是在subPackages中指定一个分包名,分包页面对应分包名下的文件。因此,我们可以将原页面下的模块指定为分包,这样配置就可以解决分包后路径不一致的问题。改写后的结构如下:"subPackages":[{"root":"pages/activity","pages":[{"path":"detail"}]}],示例地址:https://github。com/qq449245884/uniapp-subpackage-demo/tree/feature/02.%E9%85%8D%E7%BD%AE%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84%E7%9A%84%E5%90%88%E7%90%86%E6%80%A7分包预加载分包预加载配置。配置preloadRule后,当进入小程序的某个页面时,框架会自动预下载可能需要的分包,以提高进入后续分包页面时的启动速度。假设我们有两个分包pagesA和pagesB。当我们进入详情页,想要预添加pagesA时,对应的配置如下:{"pages":[//pages数组第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages{"path":"pages/index/index","style":{"navigationBarTitleText":"主页"}},{"path":"pages/detail/index",“样式”:{“navigationBarTitleText”:“详细信息”}}}],“subPackages”:[{“根”:“pagesA”,“页面”:[{“路径”:“详细信息/索引”}]},{"root":"pagesB","pages":[{"path":"detail/index"}]}],"preloadRule":{"pages/detail/index":{"network":"wifi","packages":["pagesA","pagesB"]}}}preloadRule中key为页面路径,value为进入该页面的预下载配置,packages为预加载的子包-进入页面后下载。network指定网络下预下载,可选值有:all(不限网络),wifi(仅在wifi下预下载)。示例地址:https://github.com/qq449245884/uniapp-subpackage-demo/tree/feature/03.%E5%88%86%E5%8C%85%E9%A2%84%E5%8A%A0%E8%BD%BD分包加载规则分包需要注意一件事:tabBar页面需要放在主包中,假设我们有两个tabBar,配置如下:{"pages":[{“路径”:“页面/频道/索引”,“样式”:{“disableScroll”:真}},{“路径”:“页面/成员/索引”,“样式”:{“disableScroll”:真}}],"tabBar":{"color":"#BBBBBD","selectedColor":"#1C1C1C","borderStyle":"white","backgroundColor":"#ffffff","list":[{"pagePath":"pages/channel/index","iconPath":"static/tabbar_icon_channel.png","selectedIconPath":"static/tabbar_icon_channel_active.png","text":"仅限会员"},{"pagePath":"pages/member/index","iconPath":"static/tabbar_icon_member.png","selectedIconPath":"static/tabbar_icon_member_active.png","text":"Member"}]}}如果我们将tabBar页面配置为subPackages,会出现错误:案例地址:https://github.com/qq449245884/uniapp-subpackage-demo/tree/feature/04.%E5%88%86%E5%8C%85%E7%9A%84%E9%99%90%E5%88%B6分包优化在对应平台的配置下添加"optimization":{"subPackages":true}开启分包优化分包优化具体逻辑静态文件:分包下支持static,etc静态资源拷贝,即放在子包目录下的静态资源不会被打包到主包中,js文件不能在主包中使用:当某个js只被一个子包引用时,js会被打包到这个子包中,否则还是打到主包里(即被主包引用,或者被多个子包引用)。自定义组件:如果一个自定义组件只被一个分包引用,并且没有放在分包中,编译时会输出提示信息。首先,我们来测试第一条规则,并为首页创建相应的配置:{"pages":[{"path":"pages/index/index",}],"subPackages":[{"root":"pagesA","pages":[{"path":"detail/index"}]}],}这里我们有一个分包pagesA对应一个详情页,里面用到了A图片,图片放在static下面当前包下的文件,内容如下:然后,我们开始打包,然后点击开发者工具的详细信息,点击LocalCode->DependencyAnalysis,可以查看打包的详细信息,如下图所示:可以看到,我们点击主包下的static没有我们的分包中使用的不是test.png图片,而是打包在自己的分包下。即放在子包目录下的静态资源不会被打包到主包中,它是成立的。接下来我们验证一下如果在主包中使用分包的test.png图片会发生什么?重写我们主包的索引文件的内容:运行后控制台会报错:因此分包下支持static等静态资源拷贝,即分包目录下的静态资源不会被打包到主包中,也不能在主包中使用包裹。示例地址:https://github.com/qq449245884/uniapp-subpackage-demo/tree/feature/05.%E5%88%86%E5%8C%85%E4%BC%98%E5%8C%96__%E9%9D%99%E6%80%81%E6%96%87%E4%BB%B6然后我们来验证第二条规则:js文件:当某个js只被一个分包引用时,该js会被打包打入子包,否则仍会打入主包(即被主包引用,或被多个子包引用)。首先,我们在主包的src/utils中创建一个common.ts,内容如下:exportconstadd=(a:number,b:number)=>{returna+b}然后,在子包pagesA导入用法:同样,打包,然后点击开发者工具的详细信息,点击本地代码->依赖分析:从上图可以看出,我们在vendor.js中没有找到src/utils主包/common.ts中的add方法,却在子包pagesA中找到。某个js被多个分包引用怎么办?我们再创建一个子包pagesB,同样的方法在子包pagesB中导入common.ts:extend({created(){console.log(add(1,2))}})同理打包,点击开发者工具查看详情,点击LocalCode->DependencyAnalysis:从中可以看出如图,我们可以在主包中找到我们在vendor.js中使用的add方法,但是在子包中却没有找到对应的vendor.js,所以当一个js只被多个子包引用时,js会打包到主包中。示例地址:https://github.com/qq449245884/uniapp-subpackage-demo/tree/feature/05.%E5%88%86%E5%8C%85%E4%BC%98%E5%8C%96__JS%E6%96%87%E4%BB%B6最后验证第三条规则:自定义组件:如果自定义组件只被一个分包引用,没有放入分包中,编译时会输出一条提示信息。首先,我们在主包的src/components中创建一个自定义组件SayHello,内容如下:然后,构建一个自定义组件以同样的方式分包(步骤同上例),在分包中引用我们的组件SayHello:然后编译就可以看到控制台提示信息:自定义组件被多个分包引用怎么办?提示应该消失。为了严谨起见,我们再建一个分包pagesB以同样的姿势引用该组件,然后编译,然后查看控制台:可以看到提示信息Disappeared。至此,我们验证了UniApp官网Nice提到的分包优化的具体逻辑。示例地址:https://github.com/qq449245884/uniapp-subpackage-demo/tree/feature/0.5.%E5%88%86%E5%8C%85%E4%BC%98%E5%8C%96__%E7%BB%84%E4%BB%B6