这里排除独立包异步化等场景,如果可以,优先选择文件独立分包异步化。
另外这里的背景是基于uniapp
编译成微信小程序。
vue
是2.x
版本,脚手架是vue-cli
。
最近发现部门负责的小程序中存在一些全局文件只有在分包中有依赖,想去优化这块,于是衍生出两种开发场景。
那么有没有办法可以将两个优点结合呢?
也就是文件依旧放到主包,但是打包后各分包依赖的文件不是主包的。
有的,并且方案不少。
loader
对开发源码匹配处理(或者自己写一套预编译处理)。这里我个人经过考虑后选择方案2,因为这个是打包准备部署的阶段而并非开发阶段,所以这点耗时影响可以接受。
既然选定了方案,接下来就是实现。
那么该从哪个点切入呢?
这里选择对请求的路径进行改动,将主包请求路径改动到分包自己种,比如@/components/xxx/xx.vue
改动为@/subpkg/xxx/xx.vue
,这样后续打包就不会去请求主包里的xx.vue
文件,自然就不会参与打包也就不侵占主包空间。
不过这里还有另一个问题,那就是分包中的xxx/xx.vue
是不存在的,如果直接改请求路径那么是找不到的,会导致报错。
我这里就直接用暴力的方案,在请求之前做copyDir
处理,这里面有挺多可以优化的点。
那么这俩问题的解决理论有了,可以动手实现了。
先来处理第一个问题,文件请求路径改写。
我这里最先是考虑通过babel
自定义plugin
的方式来改写路径。
但是这里有两个问题:
于是放弃。
webpack
自定义插件注册hooks
监听生命周期针对于尝试1中的第一个问题,我这里想着如果要不改动源码并且改动请求路径,那么就得在module
生成之前改动, 我选择监听的生命周期是normalModuleFactory
[1] 拿到normalModuleFactory
实例之后再监听它的生命周期beforeResolve
[2] ,这个时候是还没有处理request
的,所以在这里改动最好。
那么结果呢?
打包结果:
由于第二个问题过于奇怪,在挣扎了一段时间后选择放弃。
loader
实现,规则/.js$/
经过尝试2,我发现应该是选择的生命周期位置不够接近,所以干脆选择含有请求路径的文件被处理的时候来改写,这样应该就是最接近的时刻了。
那么自然是选择loader
来处理。
并且得在babel-loader
之前,因为得赶在源码被篡改之前动手改动。
代码就不放了,最终方案的代码差不多,到时直接看最终方案即可。
尝试之后依旧是失败了:
反思了下,想法是可以的,但是还是不够靠前,因为vue-loader
会调用@vue/compiler-sfc
将代码进行切割分别处理,babel
拿到的已经不是第一手代码了。
那么自然就得在vue-loader
之前。
loader
实现,规则/.vue$/这回咱们赶在vue-loader
处理前改动源码。
先在vue.config.js
中写规则
然后我们来实现这个loader
这里采用的是loader
异步环境[3] ,这么做是为了确保copy
文件/文件夹完成再改动请求路径。
这个方案最终的结果是:
那么这里就基本符合我个人预期了,放一下效果图:
这里基于主包30多个组件以及6个分包依赖
可以看到这里主包已经爆掉了
编译时间
可以看到主包降回2M
以内。
编译时间:
经过上面的效果图对比,你应该发现了几处问题:
copy
文件。虽然问题较多,但是实际上还是有价值使用的,比如:
这个方案其实还有一个问题,那就是copy
的副本会一直保留在分包中,这样就很恶心了,达不到我们“开发者无感知”的要求。
不过这个也好解决,我们可以暴力点,收集copy to
的路径,然后监听webpack
的生命周期,在done
的阶段将文件移除即可。
基于global
这个全局变量来缓存copy to
的路径
然后自定义webpack
插件
这回就是“无感知”啦~
这个方案被驳回了。。。。但确实有一定的可行性。
如果觉得有帮助请务必点个赞,这是对我这个方案的肯定。。。
编辑于 2023-02-18 17:57・IP 属地广东