坏蛋Dan
知乎@坏蛋Dan
发布时间:2024.5.27

前言

在开始实现之前,我得说,本篇要实现的功能用rust + WebAssembly来实现只能装逼,性能各方面都不如直接用js来写。。。。

因为不允许使用rust涉及系统的api,所以基本只是换了个皮,核心各种都是js的。

各位老哥引以为戒,不要为了装B而去写,要从实用出发!

github链接:https://github.com/1714080902120/uniapp-async-pkg-inject

另外搞了个npm包,可以直接引入:uniapp-async-pkg-inject - npm (npmjs.com)


实现

基于

  1. 微信小程序分包异步化
  2. https://ask.dcloud.net.cn/article/id-39622 大佬的方案

要解决的问题

解决当前uniapp不支持分包异步化的问题(底层原理是转换成小程序代码时pages.json会过滤pages为空的分包)

比如pages.json中:

最终是会被过滤掉的

我们要解决的就是被过滤掉的问题


原理

原理很简单,最终uniapp的代码都会转换成符合微信小程序要求的代码,所以我们可以在uniapp => miniprogram完成之后,我们直接操作pages.json,把我们被过滤掉的给补充回去。

得益于组件并不会被编译进vendor,所以我们可以直接把一堆组件所在的文件夹直接定义成一个包!

当然,只是补充pages.json还是不够的,根据微信官方的要求,如果分包异步化的分包还没加载,那么组件就不能被使用,这个时候如果不用componentPlaceholder的话会直接报错,所以我们还需要给所有的组件的.json修改一波。

比如组件xxx.vue引用了xx组件,我们把这个xx迁移至需要分包异步化:

转换成微信小程序的代码后,会生成我们熟悉的xxx.json:

我们还需要给这个xx补充一个未加载前的占位元素,一般可以是view

那么到这原理就基本解释完了。


依赖


代码

代码就不多说了,直接放出来:

简单的说下:

  • #[wasm_bindgen(module = "fs")]:用来指定当前要使用的js module是哪个,这里指定fs,然后我们就可以直接引入fs的方法,比如readFileSync
  • rewrite_dist_app_json:重写编译生成的app.json,插入我们被过滤掉的分包
  • inject_empty_wrapper:插入占位元素,这里我搞成一个组件,也可以直接用view,都行,但一定要有占位元素,不然会报错。
  • traverse_all_components_json:遍历整个mp-weixin文件夹里的json文件,然后插入占位组件
  • traverse_some_components_json:同上,但是只处理传入的参数这部分,为什么要单独再写一个,等会你就知道了

打包

不多说


使用

实现只是完成了第一步,还需要知道怎么使用

这里我们直接在项目中引入:

然后创建一个webpack插件:

  1. 我们在hooks.done阶段执行我们的方法
  2. 我们在hooks.assetEmitted注册了回调,获取此次重新编译的assets或者叫chunk,然后给done时使用。

这么做之后 只需要重写app.json文件一次(后续改动涉及app.json还是需要重写),并且除了第一次,后面都是差量调整,耗时算下来会少很多。

最后引入webpack插件即可,比如在vue.config.js中:

那么到这就完成啦~


总结

其实主要逻辑还是那位老哥的方案,但是那位老哥的代码只是针对于生产环境的,对开发环境不太友好,所以才有了这次的实现。

最后强调一次:从实用出发!