Craft your own d3 build
2022-11-10 09:59:38 +0100 +0100
File this in the maybe-it’s-obvious-to-others-but-not-to-me category: here’s a quick post about how you can craft your own d3.js build with just the d3 packages that you need.
Why
d3’s minified JavaScript file from npmjs is 276kB. We’re using it for a feature on Wikipedia; at that scale, every kilobyte counts for serving users in low bandwidth environments and reducing carbon footprint 🌳.
In our use case, we don’t need all the dependencies. Can we make a smaller build with just the packages we need?
To investigate, my colleague Sergio filed T321215 .
What we did
After more flailing around than I care to admi1t, and some helpful contributions from Eric, this is what I’ve landed on (patch):
Entrypoint to determine which modules from d3 to include
In modules/lib/d3/index.js
we have:
export * from "d3-array";
export * from "d3-interpolate"; export * from "d3-path";
export * from "d3-scale";
export * from "d3-selection";
export * from "d3-shape";
export * from "d3-time";
export * from "d3-time-format";
package.json
I added the relevant d3`` subpackages to
devDependenciesin
package.json`:
"devDependencies": {
"d3-array": "3.2.0",
"d3-interpolate": "3.0.1",
"d3-path": "3.0.1",
"d3-scale": "4.0.2",
"d3-selection": "3.0.0",
"d3-shape": "3.1.0",
"d3-time": "3.0.0",
"d3-time-format": "4.1.0",
}
For convenience, I also added a scripts
entry for rollup
aliased to rollup -c
.
rollup.config.js
The complicated part was figuring out the correct rollup
config. After quite a bit of experimentation, we ended up with:
'use strict';
const resolve = require( '@rollup/plugin-node-resolve' );
const terser = require( '@rollup/plugin-terser' );
/**
* Config file for generating a custom build of d3, containing only the packages
* we need for the Impact module.
*/
module.exports = {
input: 'modules/lib/d3/index.js',
output: {
file: 'modules/lib/d3/d3.min.js',
format: 'umd',
compact: false,
name: 'd3'
},
plugins: [
resolve(),
terser()
],
// upstream d3 rollup.config.js has this as well.
onwarn( message, warn ) {
if ( message.code === 'CIRCULAR_DEPENDENCY' ) {
return;
}
warn( message );
}
};
Mysteriously, not including the terser plugin results in a broken build. (We don’t need the code minified here since MediaWiki’s ResourceLoader would do that for us.)
⚡️ Build!
Now npm run rollup
generates a d3.min.js
file in modules/lib/d3/d3.min.js
. The end result is a reduction from 278kB to 115kB.
You’re welcome to visit the history of the patch and its child patches 😅 ↩︎