likes
comments
collection
share

小程序webpack异步分包实践-以echarts为例

作者站长头像
站长
· 阅读数 13
  1. 背景

需求中需要在分包页面中使用echarts进行绘图。但是小程序本身对于分包使用是有大小限制的,再加上echarts使用场景比较局限,放在包内会增大分包下载耗时。所以不能在业务分包里面直接使用echarts,避免业务包过大,也需要在使用echarts的地方开启按需加载和预加载,增强用户体验。加上项目是wepack进行构建的,所以探索异步分包在webpack中的实现很有必要。

参考了echarts在小程序中的实践发现,echarts.js即使在最精简的情况下仍然有1m。

github.com/ecomfe/echa…

小程序webpack异步分包实践-以echarts为例

实践也推荐使用异步分包,那就需要探索小程序的异步分包能力究竟该怎么使用了。先看文档

  1. 官网 分包异步化指南

官网地址:developers.weixin.qq.com/miniprogram…

支持版本: 需要基础库版本 2.11.2 或以上

组件的跨分包引用

list来自subPackageB

在分包内容未拉取成功的情况下可以使用

buttonlist 两个自定义组件是跨分包引用组件,其中 button 在渲染时会使用内置组件 view 作为替代,list 会使用当前分包内的自定义组件 simple-list 作为替代进行渲染;在这两个分包下载完成后,占位组件就会被替换为对应的跨分包组件。

小程序webpack异步分包实践-以echarts为例

加载成功的回调

在基础库 2.24.3 之后,可以使用 wx.onLazyLoadError 监听加载事件。

js的跨分包引用

通过 require 的异步加载对应地址即可加载成功

小程序webpack异步分包实践-以echarts为例

异步加载非常熟悉,只要使用import或者require就能异步的加载amd,cmd文件,但事情往往没有这么简单。

2.异步加载函数分析

import().then

不可用, 小程序异步加载只能使用commonjs require规范

require.ensure

webpack require.ensure语法在原生小程序中并不支持

require.ensure是一个在Webpack中用于代码分割的方法。它允许将模块按需加载,而不是一次性加载所有模块。这样可以提高应用程序的性能,因为只有在需要时才会加载所需的模块。

require.async require 回调方法

小程序webpack异步分包实践-以echarts为例

直接使用require方法

require(['../../../packageEcharts/ec-canvas/echarts'], function (chart) {}

会产生对应报错

小程序webpack异步分包实践-以echarts为例

进入报错源码看看

小程序webpack异步分包实践-以echarts为例

可以看出webpack使用require的时候会在webpack缓存中判断需要加载key是否存在

如果不存在就创建script去加载对应的url。但是小程序中是没有原生创建标签能力的。此处第一版的做法是不停的在加载资源后重新调用加载资源方法,不停重试,直到通过使用小程序预加载能力把echarts.js加载到本地后,webpack才能读取到文件后会清空对应key,这样就不会进入引入标签流程,而直接使用对应的require文件,从而达到异步获取标签能力。

第二个较为简单的方案是在使用处创建script标签,通过onload去返回对应的文件。但是这样也有缺点

1. 不是小程序推荐的实践,使用不到小程序的预加载能力

2. 因为是通过打包后放cdn形式,所以js能力较为固定,需要专门维护对应js,不够灵活。

但你就说能不能用吧?

能用,但是非常不优雅,不停的重试会引入不可知问题。两种方式都完全没有使用到小程序提供的require本身的能力,既然小程序本身提供了,还是按照官方能力去使用吧。

3.异步分包的最佳实践

1.webpack的require

我们都知道Webpack在打包过程中会对模块的加载进行处理,将require语句替换为__webpack_require__函数调用。使用自己的模块加载系统来管理模块的依赖关系和加载顺序。

__webpack_require__函数是Webpack提供的模块加载函数,它会根据模块的ID进行模块的加载和执行。在Webpack打包过程中,会将每个模块分配一个唯一的ID,并且将模块的代码包装在一个函数中,该函数接受__webpack_require__函数作为参数。Webpack会将其替换为__webpack_require__函数的调用,并传递模块的ID作为参数。通过这种方式,Webpack可以在运行时根据模块的依赖关系和加载顺序来动态加载和执行模块。

所以当使用require方法时,Webpack会将其转换为__webpack_require__.e函数的调用,以实现按需加载模块的功能。webpack_require.e函数会根据传入的模块ID异步加载对应的模块,并返回一个Promise对象,可以通过该Promise对象来处理模块加载完成后的逻辑。

2.不使用webpack require

可以明显发现在webpack环境下,require被改造了,我们需要通知webpack不改造对应的require,才能符合微信官方的能力所以使用,经过阅读webpack文档,需要给require加上标志前缀就能避免webpack对require进行改造

__non_webpack_require__(ECHARTS_SRC, (chart) => {

通过打包后的源码分析可以发现已经从webpack_require.e

小程序webpack异步分包实践-以echarts为例

变更为

小程序webpack异步分包实践-以echarts为例

符合预期,但查看加载结果发现,echarts实例并未加载到

小程序webpack异步分包实践-以echarts为例

2.未能加载的对应文件

未获取文件往往是因为文件地址不对或者文件没有正确导出echarts导致的

查看打包后的文件地址

小程序webpack异步分包实践-以echarts为例

可以看出echarts文件因为splitchunk的存在被打包进了分包的主文件内了。因为我们使用的是原生的require,使用的是相对路径'

../../../packageEcharts/ec-canvas/echarts'

然而,echarts.js本身却被打包进了index.js。

确实是没有对应文件。所以无法加载到对应文件。

因此需要让webpack忽略掉队echarts.js文件的操作,使其是一个完整干净的js.所以必须把文件内容从webpack的构建过程中拿掉

3.忽略对文件的操作

loader忽略对js文件的编译

小程序webpack异步分包实践-以echarts为例

从编译生命周期中去除文件,此处使用ignorePlugin,忽略对应文件夹

小程序webpack异步分包实践-以echarts为例

别忘记,原文件是还是需要打包进代码的,使用CopyWebpackPlugin将开发目录打包进构建目录

小程序webpack异步分包实践-以echarts为例

4.分析对应文件

查看构建后packageEcharts目录

小程序webpack异步分包实践-以echarts为例

可以看到和开发目录完全一致

小程序webpack异步分包实践-以echarts为例

验证require效果

小程序webpack异步分包实践-以echarts为例

为什么还是none呢

进入details源码

可以看出因为splictChunk的规则存在

小程序webpack异步分包实践-以echarts为例

details文件被打包进了components.js内。

小程序webpack异步分包实践-以echarts为例

这样文件目录路径就不对了,因为没有使用webpack能力,没有处理引用路径问题。此处需要写死引用路径

小程序webpack异步分包实践-以echarts为例

查看对应效果,可以看出

小程序webpack异步分包实践-以echarts为例

echarts内容最后被正确加载了

完结,撒花