如何按需加载D3.js中的模块

最近有个组件需求,是用D3.js写的,自己写的代码总共就几KB大小,但是最终打包出来的压缩版JS居然有98KB。考虑到D3是按照模块化编写的,因此我想尝试下通过按需引入模块,来精简最终的JS。

查询某个函数在哪个模块下面

从D3.js的API页面上,找到函数名称,就可以找到其所属的模块了。比如查询d3.max()这个函数:

d3.max

可以看到它是属于d3-array这个模块下的。

引入模块

我习惯于将d3-selection模块引入后重命名为d3,因为这个模块用得最多;其他模块则直接采用模块名:

1
2
import * as d3 from 'd3-selection';
import * as scale from 'd3-scale';

优化大小对比

引入整个d3.js:98KB

按需引入后:79KB

只精简了20KB,优化效果很有限。

原因在于d3模块与模块之前其实也是存在依赖的,比如d3-transition模块就依赖了color、dispatch、ease、interpolate、selection、timer这几个模块,因此使用一个transition,实际上会将N个模块都加载进来。

如下是这次项目中用到的几个模块的自身代码的大小:

模块 本模块大小(KB)
d3-selection 13
d3-transition 12
d3-array 6
d3-color 11
d3-interpolate 8
d3-scale 15

可以看到加起来已经65KB了,所以虽然我自己写的代码不多,但是整体也达到了79KB。

按需引入函数

如果优化只进行到这一步,明显还不够,考虑到这些模块里面,其实很多暴露出来的接口我都没用到,因此准备再进一步,只引入模块中被我用到的函数接口,类似这样:

1
2
3
4
5
6
import {select, selectAll, style} from 'd3-selection';
let d3 = {
select: select,
selectAll: selectAll,
style: style
}

结果发现并没有减小最终的文件。虽然我只引用了单个函数,但是仍然会把整个模块代码加载进来。

然后同事推荐了一个文章,这是D3的作者写的,通过rollup.js实现按需加载代码:

https://gist.github.com/mbostock/bb09af4c39c79cffcde4

操作步骤按照文档执行即可,经测试后,确实能够精简文件大小。单独算D3相关的文件,从84KB精简到69KB了。虽然会给开发增加一些额外成本,不过用开发成本换线上性能,还是值得的。

2021.02.07 项目实践记录

动态图表组件的代码,经过压缩后有142KB,比较大,我准备尝试下按需引入。

一些方法

如何查看模块依赖了哪些其他的模块

具体模块的主页,会注明该模块包含了哪些其他的模块:

https://github.com/d3/d3-transition

如何查看模块对外暴露了哪些接口

可以进入下载好的模块包,查看末尾的代码,看看该模块对外导出了哪些函数接口。