Improving plotly.js bundling time using rollup
Feb 4, 2021 7:42 AMI love Plotly.js because the batteries come included. I’m using this on my site analytics page. It looks nice, is interactive, and has reasonably useful documentation. The one negative aspect of the library is its size — the latest minified bundle (v1.58.4) clocks in at about 3.32MB. It needs to be included in the head of the document to work, which does not jive with how Sapper rehydrates bundles for each route. Plotly also has issues with bundlers like rollup when using the ES module because this
is not set to window
in the context of ES6 modules (see plotly/plotly.js#3518) for more details.
I applied a janky patch to resolve the issue in my bundler. In my rollup.config.js
in my application, I have the following snippet in my client plugins list:
// https://github.com/plotly/plotly.js/issues/3518
replace({
"}()": "this.d3 = d3;\n}.apply(self);",
delimiters: ["this.d3 = d3;\n", ";"],
}),
Now I can import the module within the onMount
section of a page (which is necessary because the server portion of Sapper does not have the capability to run Plotly).
onMount(async () => {
const { default: Plotly } = await import("plotly.js/lib/core");
Plotly.newPlot(...);
})
After implementing this, I noticed that my builds became staggeringly slow. What gives? It turns out that by including plotly.js
into my application, the tree that rollup has to shake becomes significantly larger. It’s a little ridiculous.
Dependency tree of the custom plotly.js package
> npm ls --prod plotly.js-custom@1.0.0 acmiyaguchi.me\packages\plotly.js-custom `-- plotly.js@1.58.4 +-- @plotly/d3-sankey@0.7.2 | +-- d3-array@1.2.4 | +-- d3-collection@1.0.7 | `-- d3-shape@1.3.7 | `-- d3-path@1.0.9 +-- @plotly/d3-sankey-circular@0.33.1 | +-- d3-array@1.2.4 deduped | +-- d3-collection@1.0.7 deduped | +-- d3-shape@1.3.7 deduped | `-- elementary-circuits-directed-graph@1.2.0 | `-- strongly-connected-components@1.0.1 deduped +-- @plotly/point-cluster@3.1.9 | +-- array-bounds@1.0.1 | +-- binary-search-bounds@2.0.5 | +-- clamp@1.0.1 | +-- defined@1.0.0 | +-- dtype@2.0.0 | +-- flatten-vertex-data@1.0.2 | | `-- dtype@2.0.0 deduped | +-- is-obj@1.0.1 | +-- math-log2@1.0.1 | +-- parse-rect@1.2.0 | | `-- pick-by-alias@1.2.0 deduped | `-- pick-by-alias@1.2.0 +-- @turf/area@6.3.0 | +-- @turf/helpers@6.3.0 | `-- @turf/meta@6.3.0 | `-- @turf/helpers@6.3.0 deduped +-- @turf/bbox@6.3.0 | +-- @turf/helpers@6.3.0 deduped | `-- @turf/meta@6.3.0 deduped +-- @turf/centroid@6.3.0 | +-- @turf/helpers@6.3.0 deduped | `-- @turf/meta@6.3.0 deduped +-- alpha-shape@1.0.0 | +-- alpha-complex@1.0.0 | | +-- circumradius@1.0.0 | | | `-- circumcenter@1.0.0 | | | +-- dup@1.0.0 deduped | | | `-- robust-linear-solve@1.0.0 deduped | | `-- delaunay-triangulate@1.1.6 deduped | `-- simplicial-complex-boundary@1.0.1 | +-- boundary-cells@2.0.2 | `-- reduce-simplicial-complex@1.0.0 | +-- cell-orientation@1.0.1 | +-- compare-cell@1.0.0 | `-- compare-oriented-cell@1.0.1 | +-- cell-orientation@1.0.1 deduped | `-- compare-cell@1.0.0 deduped +-- canvas-fit@1.5.0 | `-- element-size@1.1.1 +-- color-alpha@1.0.4 | `-- color-parse@1.3.8 deduped +-- color-normalize@1.5.0 | +-- clamp@1.0.1 deduped | +-- color-rgba@2.1.1 deduped | `-- dtype@2.0.0 deduped +-- color-parse@1.3.8 | +-- color-name@1.1.4 | +-- defined@1.0.0 deduped | `-- is-plain-obj@1.1.0 +-- color-rgba@2.1.1 | +-- clamp@1.0.1 deduped | +-- color-parse@1.3.8 deduped | `-- color-space@1.16.0 | +-- hsluv@0.0.3 | `-- mumath@3.3.4 | `-- almost-equal@1.1.0 +-- convex-hull@1.0.3 | +-- affine-hull@1.0.0 | | `-- robust-orientation@1.1.3 deduped | +-- incremental-convex-hull@1.0.1 | | +-- robust-orientation@1.1.3 deduped | | `-- simplicial-complex@1.0.0 | | +-- bit-twiddle@1.0.2 deduped | | `-- union-find@1.0.2 deduped | `-- monotone-convex-hull-2d@1.0.1 | `-- robust-orientation@1.1.3 deduped +-- country-regex@1.1.0 +-- d3@3.5.17 +-- d3-force@1.2.1 | +-- d3-collection@1.0.7 deduped | +-- d3-dispatch@1.0.6 | +-- d3-quadtree@1.0.7 | `-- d3-timer@1.0.10 +-- d3-hierarchy@1.1.9 +-- d3-interpolate@1.4.0 | `-- d3-color@1.4.1 +-- d3-time-format@2.3.0 | `-- d3-time@1.1.0 +-- delaunay-triangulate@1.1.6 | +-- incremental-convex-hull@1.0.1 deduped | `-- uniq@1.0.1 +-- es6-promise@4.2.8 +-- fast-isnumeric@1.1.4 | `-- is-string-blank@1.0.1 +-- gl-cone3d@1.5.2 | +-- colormap@2.3.2 | | `-- lerp@1.0.3 | +-- gl-buffer@2.1.2 | | +-- ndarray@1.0.19 deduped | | +-- ndarray-ops@1.2.2 deduped | | `-- typedarray-pool@1.2.0 deduped | +-- gl-mat4@1.2.0 deduped | +-- gl-shader@4.2.1 | | +-- gl-format-compiler-error@1.0.3 | | | +-- add-line-numbers@1.0.1 | | | | `-- pad-left@1.0.2 | | | | `-- repeat-string@1.6.1 | | | +-- gl-constants@1.0.0 | | | +-- glsl-shader-name@1.0.0 | | | | +-- atob-lite@1.0.0 | | | | `-- glsl-tokenizer@2.1.5 deduped | | | `-- sprintf-js@1.1.2 | | `-- weakmap-shim@1.1.1 | +-- gl-texture2d@2.1.0 | | +-- ndarray@1.0.19 deduped | | +-- ndarray-ops@1.2.2 deduped | | `-- typedarray-pool@1.2.0 deduped | +-- gl-vao@1.3.0 | +-- gl-vec3@1.1.3 | +-- glsl-inverse@1.0.0 | +-- glsl-out-of-range@1.0.4 | +-- glsl-specular-cook-torrance@2.0.1 | | `-- glsl-specular-beckmann@1.1.2 deduped | +-- glslify@7.1.1 deduped | `-- ndarray@1.0.19 deduped +-- gl-contour2d@1.1.7 | +-- binary-search-bounds@2.0.5 deduped | +-- cdt2d@1.0.0 | | +-- binary-search-bounds@2.0.5 deduped | | +-- robust-in-sphere@1.1.3 | | | +-- robust-scale@1.0.2 deduped | | | +-- robust-subtract@1.0.0 deduped | | | +-- robust-sum@1.0.0 deduped | | | `-- two-product@1.0.2 deduped | | `-- robust-orientation@1.1.3 deduped | +-- clean-pslg@1.1.2 | | +-- big-rat@1.0.4 | | | +-- bit-twiddle@1.0.2 deduped | | | +-- bn.js@4.11.9 | | | `-- double-bits@1.1.1 | | +-- box-intersect@1.0.2 | | | +-- bit-twiddle@1.0.2 deduped | | | `-- typedarray-pool@1.2.0 deduped | | +-- nextafter@1.0.0 | | | `-- double-bits@1.1.1 deduped | | +-- rat-vec@1.1.1 | | | `-- big-rat@1.0.4 deduped | | +-- robust-segment-intersect@1.0.1 | | | `-- robust-orientation@1.1.3 deduped | | +-- union-find@1.0.2 | | `-- uniq@1.0.1 deduped | +-- gl-buffer@2.1.2 deduped | +-- gl-shader@4.2.1 deduped | +-- glslify@7.1.1 deduped | +-- iota-array@1.0.0 | +-- ndarray@1.0.19 deduped | `-- surface-nets@1.0.2 | +-- ndarray-extract-contour@1.0.1 | | `-- typedarray-pool@1.2.0 deduped | +-- triangulate-hypercube@1.0.1 | | +-- gamma@0.1.0 | | +-- permutation-parity@1.0.0 | | | `-- typedarray-pool@1.2.0 deduped | | `-- permutation-rank@1.0.0 | | +-- invert-permutation@1.0.0 | | `-- typedarray-pool@1.2.0 deduped | `-- zero-crossings@1.0.1 | `-- cwise-compiler@1.1.3 deduped +-- gl-error3d@1.0.16 | +-- gl-buffer@2.1.2 deduped | +-- gl-shader@4.2.1 deduped | +-- gl-vao@1.3.0 deduped | +-- glsl-out-of-range@1.0.4 deduped | `-- glslify@7.1.1 deduped +-- gl-heatmap2d@1.1.1 | +-- binary-search-bounds@2.0.5 deduped | +-- gl-buffer@2.1.2 deduped | +-- gl-shader@4.2.1 deduped | +-- glslify@7.1.1 deduped | +-- iota-array@1.0.0 deduped | `-- typedarray-pool@1.2.0 | +-- bit-twiddle@1.0.2 deduped | `-- dup@1.0.0 deduped +-- gl-line3d@1.2.1 | +-- binary-search-bounds@2.0.5 deduped | +-- gl-buffer@2.1.2 deduped | +-- gl-shader@4.2.1 deduped | +-- gl-texture2d@2.1.0 deduped | +-- gl-vao@1.3.0 deduped | +-- glsl-out-of-range@1.0.4 deduped | +-- glslify@7.1.1 deduped | `-- ndarray@1.0.19 deduped +-- gl-mat4@1.2.0 +-- gl-mesh3d@2.3.1 | +-- barycentric@1.0.1 | | `-- robust-linear-solve@1.0.0 | | `-- robust-determinant@1.1.0 | | +-- robust-compress@1.0.0 | | +-- robust-scale@1.0.2 deduped | | +-- robust-sum@1.0.0 deduped | | `-- two-product@1.0.2 deduped | +-- colormap@2.3.2 deduped | +-- gl-buffer@2.1.2 deduped | +-- gl-mat4@1.2.0 deduped | +-- gl-shader@4.2.1 deduped | +-- gl-texture2d@2.1.0 deduped | +-- gl-vao@1.3.0 deduped | +-- glsl-out-of-range@1.0.4 deduped | +-- glsl-specular-cook-torrance@2.0.1 deduped | +-- glslify@7.1.1 deduped | +-- ndarray@1.0.19 deduped | +-- normals@1.1.0 | +-- polytope-closest-point@1.0.0 | | `-- numeric@1.2.6 | +-- simplicial-complex-contour@1.0.2 | | +-- marching-simplex-table@1.0.0 | | | `-- convex-hull@1.0.3 deduped | | +-- ndarray@1.0.19 deduped | | +-- ndarray-sort@1.0.1 | | | `-- typedarray-pool@1.2.0 deduped | | `-- typedarray-pool@1.2.0 deduped | `-- typedarray-pool@1.2.0 deduped +-- gl-plot2d@1.4.5 | +-- binary-search-bounds@2.0.5 deduped | +-- gl-buffer@2.1.2 deduped | +-- gl-select-static@2.0.7 | | +-- bit-twiddle@1.0.2 deduped | | +-- gl-fbo@2.0.5 deduped | | +-- ndarray@1.0.19 deduped | | `-- typedarray-pool@1.2.0 deduped | +-- gl-shader@4.2.1 deduped | +-- glsl-inverse@1.0.0 deduped | +-- glslify@7.1.1 deduped | `-- text-cache@4.2.2 | `-- vectorize-text@3.2.1 deduped +-- gl-plot3d@2.4.7 | +-- 3d-view@2.0.0 | | +-- matrix-camera-controller@2.1.3 deduped | | +-- orbit-camera-controller@4.0.0 | | | +-- filtered-vector@1.2.4 | | | | +-- binary-search-bounds@1.0.0 | | | | `-- cubic-hermite@1.0.0 | | | `-- gl-mat4@1.2.0 deduped | | `-- turntable-camera-controller@3.0.1 | | +-- filtered-vector@1.2.4 deduped | | +-- gl-mat4@1.2.0 deduped | | `-- gl-vec3@1.1.3 deduped | +-- a-big-triangle@1.0.3 | | +-- gl-buffer@2.1.2 deduped | | +-- gl-vao@1.3.0 deduped | | `-- weak-map@1.0.5 | +-- gl-axes3d@1.5.3 | | +-- bit-twiddle@1.0.2 deduped | | +-- dup@1.0.0 deduped | | +-- extract-frustum-planes@1.0.0 | | +-- gl-buffer@2.1.2 deduped | | +-- gl-mat4@1.2.0 deduped | | +-- gl-shader@4.2.1 deduped | | +-- gl-state@1.0.0 | | | `-- uniq@1.0.1 deduped | | +-- gl-vao@1.3.0 deduped | | +-- gl-vec4@1.0.1 deduped | | +-- glslify@7.1.1 deduped | | +-- robust-orientation@1.1.3 deduped | | +-- split-polygon@1.0.0 | | | +-- robust-dot-product@1.0.0 | | | | +-- robust-sum@1.0.0 deduped | | | | `-- two-product@1.0.2 deduped | | | `-- robust-sum@1.0.0 deduped | | `-- vectorize-text@3.2.1 deduped | +-- gl-fbo@2.0.5 | | `-- gl-texture2d@2.1.0 deduped | +-- gl-mat4@1.2.0 deduped | +-- gl-select-static@2.0.7 deduped | +-- gl-shader@4.2.1 deduped | +-- gl-spikes3d@1.0.10 | | +-- gl-buffer@2.1.2 deduped | | +-- gl-shader@4.2.1 deduped | | +-- gl-vao@1.3.0 deduped | | `-- glslify@7.1.1 deduped | +-- glslify@7.1.1 deduped | +-- has-passive-events@1.0.0 deduped | +-- is-mobile@2.2.2 deduped | +-- mouse-change@1.4.0 deduped | +-- mouse-event-offset@3.0.2 deduped | +-- mouse-wheel@1.2.0 deduped | +-- ndarray@1.0.19 deduped | `-- right-now@1.0.0 deduped +-- gl-pointcloud2d@1.0.3 | +-- gl-buffer@2.1.2 deduped | +-- gl-shader@4.2.1 deduped | +-- glslify@7.1.1 deduped | `-- typedarray-pool@1.2.0 deduped +-- gl-scatter3d@1.2.3 | +-- gl-buffer@2.1.2 deduped | +-- gl-mat4@1.2.0 deduped | +-- gl-shader@4.2.1 deduped | +-- gl-vao@1.3.0 deduped | +-- glsl-out-of-range@1.0.4 deduped | +-- glslify@7.1.1 deduped | +-- is-string-blank@1.0.1 deduped | +-- typedarray-pool@1.2.0 deduped | `-- vectorize-text@3.2.1 | +-- cdt2d@1.0.0 deduped | +-- clean-pslg@1.1.2 deduped | +-- ndarray@1.0.19 deduped | +-- planar-graph-to-polyline@1.0.5 | | +-- edges-to-adjacency-list@1.0.0 | | | `-- uniq@1.0.1 deduped | | +-- planar-dual@1.0.2 | | | +-- compare-angle@1.0.1 | | | | +-- robust-orientation@1.1.3 deduped | | | | +-- robust-product@1.0.0 | | | | | +-- robust-scale@1.0.2 deduped | | | | | `-- robust-sum@1.0.0 deduped | | | | +-- robust-sum@1.0.0 deduped | | | | +-- signum@0.0.0 | | | | `-- two-sum@1.0.0 deduped | | | `-- dup@1.0.0 deduped | | +-- point-in-big-polygon@2.0.0 | | | +-- binary-search-bounds@1.0.0 | | | +-- interval-tree-1d@1.0.3 | | | | `-- binary-search-bounds@1.0.0 | | | +-- robust-orientation@1.1.3 deduped | | | `-- slab-decomposition@1.0.2 | | | +-- binary-search-bounds@1.0.0 | | | +-- functional-red-black-tree@1.0.1 | | | `-- robust-orientation@1.1.3 deduped | | +-- robust-orientation@1.1.3 deduped | | +-- robust-sum@1.0.0 deduped | | +-- two-product@1.0.2 deduped | | `-- uniq@1.0.1 deduped | +-- simplify-planar-graph@2.0.1 | | +-- robust-orientation@1.1.3 deduped | | `-- simplicial-complex@0.3.3 | | +-- bit-twiddle@0.0.2 | | `-- union-find@0.0.4 | +-- surface-nets@1.0.2 deduped | `-- triangulate-polyline@1.0.3 | `-- cdt2d@1.0.0 deduped +-- gl-select-box@1.0.4 | +-- gl-buffer@2.1.2 deduped | +-- gl-shader@4.2.1 deduped | `-- glslify@7.1.1 deduped +-- gl-spikes2d@1.0.2 +-- gl-streamtube3d@1.4.1 | +-- gl-cone3d@1.5.2 deduped | +-- gl-vec3@1.1.3 deduped | +-- gl-vec4@1.0.1 | +-- glsl-inverse@1.0.0 deduped | +-- glsl-out-of-range@1.0.4 deduped | +-- glsl-specular-cook-torrance@2.0.1 deduped | `-- glslify@7.1.1 deduped +-- gl-surface3d@1.6.0 | +-- binary-search-bounds@2.0.5 deduped | +-- bit-twiddle@1.0.2 | +-- colormap@2.3.2 deduped | +-- dup@1.0.0 | +-- gl-buffer@2.1.2 deduped | +-- gl-mat4@1.2.0 deduped | +-- gl-shader@4.2.1 deduped | +-- gl-texture2d@2.1.0 deduped | +-- gl-vao@1.3.0 deduped | +-- glsl-out-of-range@1.0.4 deduped | +-- glsl-specular-beckmann@1.1.2 | +-- glslify@7.1.1 deduped | +-- ndarray@1.0.19 deduped | +-- ndarray-gradient@1.0.0 | | +-- cwise-compiler@1.1.3 | | | `-- uniq@1.0.1 deduped | | `-- dup@1.0.0 deduped | +-- ndarray-ops@1.2.2 | | `-- cwise-compiler@1.1.3 deduped | +-- ndarray-pack@1.2.1 | | +-- cwise-compiler@1.1.3 deduped | | `-- ndarray@1.0.19 deduped | +-- ndarray-scratch@1.2.0 | | +-- ndarray@1.0.19 deduped | | +-- ndarray-ops@1.2.2 deduped | | `-- typedarray-pool@1.2.0 deduped | +-- surface-nets@1.0.2 deduped | `-- typedarray-pool@1.2.0 deduped +-- gl-text@1.1.8 | +-- bit-twiddle@1.0.2 deduped | +-- color-normalize@1.5.0 deduped | +-- css-font@1.2.0 | | +-- css-font-size-keywords@1.0.0 | | +-- css-font-stretch-keywords@1.0.1 | | +-- css-font-style-keywords@1.0.1 | | +-- css-font-weight-keywords@1.0.0 | | +-- css-global-keywords@1.0.1 | | +-- css-system-font-keywords@1.0.0 | | +-- pick-by-alias@1.2.0 deduped | | +-- string-split-by@1.0.0 | | | `-- parenthesis@3.1.7 | | `-- unquote@1.1.1 | +-- detect-kerning@2.1.2 | +-- es6-weak-map@2.0.3 | | +-- d@1.0.1 | | | +-- es5-ext@0.10.53 deduped | | | `-- type@1.2.0 | | +-- es5-ext@0.10.53 | | | +-- es6-iterator@2.0.3 deduped | | | +-- es6-symbol@3.1.3 deduped | | | `-- next-tick@1.0.0 | | +-- es6-iterator@2.0.3 | | | +-- d@1.0.1 deduped | | | +-- es5-ext@0.10.53 deduped | | | `-- es6-symbol@3.1.3 deduped | | `-- es6-symbol@3.1.3 | | +-- d@1.0.1 deduped | | `-- ext@1.4.0 | | `-- type@2.1.0 | +-- flatten-vertex-data@1.0.2 deduped | +-- font-atlas@2.1.0 | | `-- css-font@1.2.0 deduped | +-- font-measure@1.2.2 | | `-- css-font@1.2.0 deduped | +-- gl-util@3.1.3 | | +-- is-browser@2.1.0 deduped | | +-- is-firefox@1.0.3 | | +-- is-plain-obj@1.1.0 deduped | | +-- number-is-integer@1.0.1 | | | `-- is-finite@1.1.0 | | +-- object-assign@4.1.1 deduped | | +-- pick-by-alias@1.2.0 deduped | | `-- weak-map@1.0.5 deduped | +-- is-plain-obj@1.1.0 deduped | +-- object-assign@4.1.1 | +-- parse-rect@1.2.0 deduped | +-- parse-unit@1.0.1 | +-- pick-by-alias@1.2.0 deduped | +-- regl@1.7.0 deduped | +-- to-px@1.0.1 deduped | `-- typedarray-pool@1.2.0 deduped +-- glslify@7.1.1 | +-- bl@2.2.1 | | +-- readable-stream@2.3.7 | | | +-- core-util-is@1.0.2 | | | +-- inherits@2.0.4 deduped | | | +-- isarray@1.0.0 | | | +-- process-nextick-args@2.0.1 | | | +-- safe-buffer@5.1.2 | | | +-- string_decoder@1.1.1 | | | | `-- safe-buffer@5.1.2 | | | `-- util-deprecate@1.0.2 | | `-- safe-buffer@5.2.1 | +-- concat-stream@1.6.2 | | +-- buffer-from@1.1.1 | | +-- inherits@2.0.4 | | +-- readable-stream@2.3.7 | | | +-- core-util-is@1.0.2 deduped | | | +-- inherits@2.0.4 deduped | | | +-- isarray@1.0.0 | | | +-- process-nextick-args@2.0.1 deduped | | | +-- safe-buffer@5.1.2 | | | +-- string_decoder@1.1.1 | | | | `-- safe-buffer@5.1.2 deduped | | | `-- util-deprecate@1.0.2 deduped | | `-- typedarray@0.0.6 | +-- duplexify@3.7.1 | | +-- end-of-stream@1.4.4 | | | `-- once@1.4.0 | | | `-- wrappy@1.0.2 | | +-- inherits@2.0.4 deduped | | +-- readable-stream@2.3.7 | | | +-- core-util-is@1.0.2 deduped | | | +-- inherits@2.0.4 deduped | | | +-- isarray@1.0.0 | | | +-- process-nextick-args@2.0.1 deduped | | | +-- safe-buffer@5.1.2 | | | +-- string_decoder@1.1.1 | | | | `-- safe-buffer@5.1.2 deduped | | | `-- util-deprecate@1.0.2 deduped | | `-- stream-shift@1.0.1 | +-- falafel@2.2.4 | | +-- acorn@7.4.1 | | +-- foreach@2.0.5 | | +-- isarray@2.0.5 | | `-- object-keys@1.1.1 | +-- from2@2.3.0 | | +-- inherits@2.0.4 deduped | | `-- readable-stream@2.3.7 | | +-- core-util-is@1.0.2 deduped | | +-- inherits@2.0.4 deduped | | +-- isarray@1.0.0 | | +-- process-nextick-args@2.0.1 deduped | | +-- safe-buffer@5.1.2 | | +-- string_decoder@1.1.1 | | | `-- safe-buffer@5.1.2 deduped | | `-- util-deprecate@1.0.2 deduped | +-- glsl-resolve@0.0.1 | | +-- resolve@0.6.3 | | `-- xtend@2.2.0 | +-- glsl-token-whitespace-trim@1.0.0 | +-- glslify-bundle@5.1.1 | | +-- glsl-inject-defines@1.0.3 | | | +-- glsl-token-inject-block@1.1.0 | | | +-- glsl-token-string@1.0.1 deduped | | | `-- glsl-tokenizer@2.1.5 deduped | | +-- glsl-token-defines@1.0.0 | | | `-- glsl-tokenizer@2.1.5 deduped | | +-- glsl-token-depth@1.1.2 | | +-- glsl-token-descope@1.0.2 | | | +-- glsl-token-assignments@2.0.2 | | | +-- glsl-token-depth@1.1.2 deduped | | | +-- glsl-token-properties@1.0.1 | | | `-- glsl-token-scope@1.1.2 deduped | | +-- glsl-token-scope@1.1.2 | | +-- glsl-token-string@1.0.1 | | +-- glsl-token-whitespace-trim@1.0.0 deduped | | +-- glsl-tokenizer@2.1.5 | | | `-- through2@0.6.5 | | | +-- readable-stream@1.0.34 | | | | +-- core-util-is@1.0.2 deduped | | | | +-- inherits@2.0.4 deduped | | | | +-- isarray@0.0.1 | | | | `-- string_decoder@0.10.31 | | | `-- xtend@4.0.2 deduped | | +-- murmurhash-js@1.0.0 deduped | | `-- shallow-copy@0.0.1 | +-- glslify-deps@1.3.2 | | +-- @choojs/findup@0.2.1 | | | `-- commander@2.20.3 deduped | | +-- events@3.2.0 | | +-- glsl-resolve@0.0.1 deduped | | +-- glsl-tokenizer@2.1.5 deduped | | +-- graceful-fs@4.2.4 | | +-- inherits@2.0.4 deduped | | +-- map-limit@0.0.1 | | | `-- once@1.3.3 | | | `-- wrappy@1.0.2 deduped | | `-- resolve@1.19.0 deduped | +-- minimist@1.2.5 | +-- resolve@1.19.0 | | +-- is-core-module@2.2.0 | | | `-- has@1.0.3 | | | `-- function-bind@1.1.1 | | `-- path-parse@1.0.6 | +-- stack-trace@0.0.9 | +-- static-eval@2.1.0 | | `-- escodegen@1.14.3 | | +-- esprima@4.0.1 | | +-- estraverse@4.3.0 | | +-- esutils@2.0.3 | | +-- optionator@0.8.3 | | | +-- deep-is@0.1.3 | | | +-- fast-levenshtein@2.0.6 | | | +-- levn@0.3.0 | | | | +-- prelude-ls@1.1.2 deduped | | | | `-- type-check@0.3.2 deduped | | | +-- prelude-ls@1.1.2 | | | +-- type-check@0.3.2 | | | | `-- prelude-ls@1.1.2 deduped | | | `-- word-wrap@1.2.3 | | `-- source-map@0.6.1 | +-- through2@2.0.5 | | +-- readable-stream@2.3.7 | | | +-- core-util-is@1.0.2 deduped | | | +-- inherits@2.0.4 deduped | | | +-- isarray@1.0.0 | | | +-- process-nextick-args@2.0.1 deduped | | | +-- safe-buffer@5.1.2 | | | +-- string_decoder@1.1.1 | | | | `-- safe-buffer@5.1.2 deduped | | | `-- util-deprecate@1.0.2 deduped | | `-- xtend@4.0.2 deduped | `-- xtend@4.0.2 +-- has-hover@1.0.1 | `-- is-browser@2.1.0 +-- has-passive-events@1.0.0 | `-- is-browser@2.1.0 deduped +-- image-size@0.7.5 +-- is-mobile@2.2.2 +-- mapbox-gl@1.10.1 | +-- @mapbox/geojson-rewind@0.5.0 | | +-- concat-stream@2.0.0 | | | +-- buffer-from@1.1.1 deduped | | | +-- inherits@2.0.4 deduped | | | +-- readable-stream@3.6.0 | | | | +-- inherits@2.0.4 deduped | | | | +-- string_decoder@1.3.0 | | | | | `-- safe-buffer@5.2.1 deduped | | | | `-- util-deprecate@1.0.2 deduped | | | `-- typedarray@0.0.6 deduped | | `-- minimist@1.2.5 deduped | +-- @mapbox/geojson-types@1.0.2 | +-- @mapbox/jsonlint-lines-primitives@2.0.2 | +-- @mapbox/mapbox-gl-supported@1.5.0 | +-- @mapbox/point-geometry@0.1.0 | +-- @mapbox/tiny-sdf@1.2.2 | +-- @mapbox/unitbezier@0.0.0 | +-- @mapbox/vector-tile@1.3.1 | | `-- @mapbox/point-geometry@0.1.0 deduped | +-- @mapbox/whoots-js@3.1.0 | +-- csscolorparser@1.0.3 | +-- earcut@2.2.2 | +-- geojson-vt@3.2.1 | +-- gl-matrix@3.3.0 | +-- grid-index@1.1.0 | +-- minimist@1.2.5 deduped | +-- murmurhash-js@1.0.0 | +-- pbf@3.2.1 | | +-- ieee754@1.2.1 | | `-- resolve-protobuf-schema@2.1.0 | | `-- protocol-buffers-schema@3.5.1 | +-- potpack@1.0.1 | +-- quickselect@2.0.0 | +-- rw@1.3.3 | +-- supercluster@7.1.2 | | `-- kdbush@3.0.0 | +-- tinyqueue@2.0.3 | `-- vt-pbf@3.1.1 | +-- @mapbox/point-geometry@0.1.0 deduped | +-- @mapbox/vector-tile@1.3.1 deduped | `-- pbf@3.2.1 deduped +-- matrix-camera-controller@2.1.3 | +-- binary-search-bounds@1.0.0 | +-- gl-mat4@1.2.0 deduped | +-- gl-vec3@1.1.3 deduped | `-- mat4-interpolate@1.0.4 | +-- gl-mat4@1.2.0 deduped | +-- gl-vec3@1.1.3 deduped | +-- mat4-decompose@1.0.4 | | +-- gl-mat4@1.2.0 deduped | | `-- gl-vec3@1.1.3 deduped | +-- mat4-recompose@1.0.4 | | `-- gl-mat4@1.2.0 deduped | `-- quat-slerp@1.0.1 | `-- gl-quat@1.0.0 | +-- gl-mat3@1.0.0 | +-- gl-vec3@1.1.3 deduped | `-- gl-vec4@1.0.1 deduped +-- mouse-change@1.4.0 | `-- mouse-event@1.0.5 +-- mouse-event-offset@3.0.2 +-- mouse-wheel@1.2.0 | +-- right-now@1.0.0 deduped | +-- signum@1.0.0 | `-- to-px@1.0.1 deduped +-- ndarray@1.0.19 | +-- iota-array@1.0.0 deduped | `-- is-buffer@1.1.6 +-- ndarray-linear-interpolate@1.0.0 +-- parse-svg-path@0.1.2 +-- polybooljs@1.2.0 +-- regl@1.7.0 +-- regl-error2d@2.0.11 | +-- array-bounds@1.0.1 deduped | +-- color-normalize@1.5.0 deduped | +-- flatten-vertex-data@1.0.2 deduped | +-- object-assign@4.1.1 deduped | +-- pick-by-alias@1.2.0 deduped | +-- to-float32@1.0.1 | `-- update-diff@1.1.0 +-- regl-line2d@3.1.0 | +-- array-bounds@1.0.1 deduped | +-- array-find-index@1.0.2 | +-- array-normalize@1.1.4 | | `-- array-bounds@1.0.1 deduped | +-- color-normalize@1.5.0 deduped | +-- earcut@2.2.2 deduped | +-- es6-weak-map@2.0.3 deduped | +-- flatten-vertex-data@1.0.2 deduped | +-- glslify@7.1.1 deduped | +-- object-assign@4.1.1 deduped | +-- parse-rect@1.2.0 deduped | +-- pick-by-alias@1.2.0 deduped | `-- to-float32@1.0.1 deduped +-- regl-scatter2d@3.2.3 | +-- @plotly/point-cluster@3.1.9 deduped | +-- array-range@1.0.1 | +-- array-rearrange@2.2.2 | +-- clamp@1.0.1 deduped | +-- color-id@1.1.0 | | `-- clamp@1.0.1 deduped | +-- color-normalize@1.5.0 deduped | +-- color-rgba@2.1.1 deduped | +-- flatten-vertex-data@1.0.2 deduped | +-- glslify@7.1.1 deduped | +-- image-palette@2.1.0 | | +-- color-id@1.1.0 deduped | | +-- pxls@2.3.2 | | | +-- arr-flatten@1.1.0 | | | +-- compute-dims@1.1.0 | | | | +-- utils-copy@1.1.1 | | | | | +-- const-pinf-float64@1.0.0 | | | | | +-- object-keys@1.1.1 deduped | | | | | +-- type-name@2.0.2 | | | | | +-- utils-copy-error@1.0.1 | | | | | | +-- object-keys@1.1.1 deduped | | | | | | `-- utils-copy@1.1.1 deduped | | | | | +-- utils-indexof@1.0.0 | | | | | | +-- validate.io-array-like@1.0.2 | | | | | | | +-- const-max-uint32@1.0.2 | | | | | | | `-- validate.io-integer-primitive@1.0.0 deduped | | | | | | `-- validate.io-integer-primitive@1.0.0 | | | | | | `-- validate.io-number-primitive@1.0.0 | | | | | +-- utils-regex-from-string@1.0.0 | | | | | | +-- regex-regex@1.0.0 | | | | | | `-- validate.io-string-primitive@1.0.1 | | | | | +-- validate.io-array@1.0.6 deduped | | | | | +-- validate.io-buffer@1.0.2 | | | | | `-- validate.io-nonnegative-integer@1.0.0 | | | | | `-- validate.io-integer@1.0.5 deduped | | | | +-- validate.io-array@1.0.6 | | | | +-- validate.io-matrix-like@1.0.2 | | | | +-- validate.io-ndarray-like@1.0.0 | | | | `-- validate.io-positive-integer@1.0.0 | | | | `-- validate.io-integer@1.0.5 | | | | `-- validate.io-number@1.0.3 | | | +-- flip-pixels@1.0.2 | | | +-- is-browser@2.1.0 deduped | | | +-- is-buffer@2.0.5 | | | `-- to-uint8@1.4.1 | | | +-- arr-flatten@1.1.0 deduped | | | +-- clamp@1.0.1 deduped | | | +-- is-base64@0.1.0 | | | +-- is-float-array@1.0.0 | | | `-- to-array-buffer@3.2.0 | | | +-- flatten-vertex-data@1.0.2 deduped | | | +-- is-blob@2.1.0 | | | `-- string-to-arraybuffer@1.0.2 | | | +-- atob-lite@2.0.0 | | | `-- is-base64@0.1.0 deduped | | `-- quantize@1.0.2 | +-- is-iexplorer@1.0.0 | +-- object-assign@4.1.1 deduped | +-- parse-rect@1.2.0 deduped | +-- pick-by-alias@1.2.0 deduped | +-- to-float32@1.0.1 deduped | `-- update-diff@1.1.0 deduped +-- regl-splom@1.0.14 | +-- array-bounds@1.0.1 deduped | +-- array-range@1.0.1 deduped | +-- color-alpha@1.0.4 deduped | +-- flatten-vertex-data@1.0.2 deduped | +-- parse-rect@1.2.0 deduped | +-- pick-by-alias@1.2.0 deduped | +-- raf@3.4.1 | | `-- performance-now@2.1.0 | `-- regl-scatter2d@3.2.3 deduped +-- right-now@1.0.0 +-- robust-orientation@1.1.3 | +-- robust-scale@1.0.2 | | +-- two-product@1.0.2 deduped | | `-- two-sum@1.0.0 | +-- robust-subtract@1.0.0 | +-- robust-sum@1.0.0 | `-- two-product@1.0.2 +-- sane-topojson@4.0.0 +-- strongly-connected-components@1.0.1 +-- superscript-text@1.0.0 +-- svg-path-sdf@1.1.3 | +-- bitmap-sdf@1.0.3 | | `-- clamp@1.0.1 deduped | +-- draw-svg-path@1.0.0 | | +-- abs-svg-path@0.1.1 | | `-- normalize-svg-path@0.1.0 | +-- is-svg-path@1.0.2 | +-- parse-svg-path@0.1.2 deduped | `-- svg-path-bounds@1.0.1 | +-- abs-svg-path@0.1.1 deduped | +-- is-svg-path@1.0.2 deduped | +-- normalize-svg-path@1.1.0 | | `-- svg-arc-to-cubic-bezier@3.2.0 | `-- parse-svg-path@0.1.2 deduped +-- tinycolor2@1.4.2 +-- to-px@1.0.1 | `-- parse-unit@1.0.1 deduped +-- topojson-client@3.1.0 | `-- commander@2.20.3 +-- webgl-context@2.2.0 | `-- get-canvas-context@1.0.2 `-- world-calendars@1.0.3 `-- object-assign@4.1.1 deduped
I had an idea to create a custom package of plotly.js that exports the core library, which would be bundled and expose a browser package. It turns out that it helped a fair bit. The set up was simple. My index.js
contains two lines that re-exports the module.
import Plotly from "plotly.js/lib/core";
export default Plotly;
In my main application, I install it into my packages.json
as so:
"dependencies": {
...
"plotly.js-custom": "file:../packages/plotly.js-custom",
},
See the full package here.
It was faster, but I wanted to figure out whether this was real or if I was imagining things from having spent too long figuring out how to make a rollup package. Here’s some of the data I collected. All reported figures are in seconds. The summarized data is the mean plus or minus the standard deviation (MEAN ± SD) seconds.
The first table is the time it took for npm run build
to complete. I did 3 trials for 3 different commits: a time before plotly, the naive direct approach, the custom package approach.
Build time via npm run build
no plotly | direct esm | custom esm |
---|---|---|
32.5 | 70 | 81 |
32.5 | 71 | 80 |
32 | 74 | 84 |
32.3±0.29 | 71.7±2.08 | 81.7±2.08 |
I also took a look at the incremental builds via npm run dev
. Once the build is fully created, I hit save on a page to trigger a rebuild. Each rebuild includes a bundle for the server, the client, and the service worker.
Incremental build time via npm run dev
no plotly | direct esm | custom esm | |
---|---|---|---|
server | 1.4±0.12 | 8.±0.16 | 1.1±0.1 |
client | 3.5±0.23 | 8.1±0.21 | 5.4±0.16 |
total | 4.9±0.35 | 16.1±0.36 | 6.5±0.23 |
The time I care about is the incremental build time. This is where I spent the majority of my time. It’s annoying when it takes a full 16 seconds before I can see a new change to a page on the site. This feedback is important when trying out new layouts or playing with the functionality of an unfamiliar library. The custom ES module cut that time to 6.5 seconds, mostly by preventing the server bundle from ever having to traverse the dependency tree for plotly. It also does marginally better than the direct ES module by 2.7 seconds.
The refactor did not entirely line up with my expectations on the other hand. I thought I would be able to create a single bundle for plotly that included all of the dependencies in one fat script. This is not the case with rollup (or ES modules) because the full knowledge of the dependency tree is how the bundler can generate efficient code. The size of the bundle would probably bloat up if I included all the dependencies inline (like the 3MB minified source). The size is not too big of a deal because Sapper only includes on the pages that need it. It would have been nice to shave off few extra seconds on those incremental builds.
I’m happy enough with this setup to not touch it for a while. I may look into smaller plotting libraries that don’t contain as much baggage, but it would require learning yet another tool. Plotly is a great tool, all things considered. With reasonable bundle sizes and incremental builds, this is good enough for me.
Full data
Incremental build times
Incremental build times for custom plotly ES module
server | client | total |
---|---|---|
1.2 | 5.6 | 6.8 |
1.1 | 5.2 | 6.3 |
0.919 | 5.3 | 6.2 |
1.1 | 5.4 | 6.5 |
1.1 | 5.5 | 6.6 |
1.1±0.1 | 5.4±0.16 | 6.5±0.23 |
Incremental build times for direct plotly ES module
server | client | total |
---|---|---|
8.2 | 8.4 | 16.6 |
7.8 | 7.9 | 15.7 |
7.9 | 7.9 | 15.8 |
8.1 | 8.1 | 16.2 |
8 | 8 | 16 |
8.±0.16 | 8.1±0.21 | 16.1±0.36 |
Incremental build times for no plotly
server | client | total |
---|---|---|
1.2 | 3.1 | 4.3 |
1.5 | 3.6 | 5.1 |
1.5 | 3.7 | 5.2 |
1.4 | 3.5 | 4.9 |
1.4 | 3.5 | 4.9 |
1.4±0.12 | 3.5±0.23 | 4.9±0.35 |
Command log output
commit c5ac12f90f97458b4d3c6ecf2ac51dc5bfee26ba (HEAD -> main) Author: Anthony Miyaguchi <acmiyaguchi@gmail.com> Date: Wed Feb 3 22:17:21 2021 -0800 Add node_modules to ignores > sapper dev ✔ server (7.1s) ✔ client (19.7s) ✔ service worker (45ms) > Listening on http://localhost:3000 src\routes\analytics\Plot.svelte changed. rebuilding... src\routes\analytics\Plot.svelte changed. rebuilding... ✔ server (1.2s) ✔ client (5.6s) ✔ service worker (44ms) src\routes\analytics\Plot.svelte changed. rebuilding... src\routes\analytics\Plot.svelte changed. rebuilding... ✔ server (1.1s) ✔ client (5.2s) ✔ service worker (34ms) src\routes\analytics\Plot.svelte changed. rebuilding... src\routes\analytics\Plot.svelte changed. rebuilding... ✔ server (919ms) ✔ client (5.3s) ✔ service worker (35ms) src\routes\analytics\Plot.svelte changed. rebuilding... src\routes\analytics\Plot.svelte changed. rebuilding... ✔ server (1.1s) ✔ client (5.4s) ✔ service worker (33ms) src\routes\analytics\Plot.svelte changed. rebuilding... src\routes\analytics\Plot.svelte changed. rebuilding... ✔ server (1.1s) ✔ client (5.5s) ✔ service worker (32ms) npm run build > Finished in 1m10s. Type node **sapper**/build to run the app. > Finished in 1m11s. Type node **sapper**/build to run the app. > Finished in 1m14s. Type node **sapper**/build to run the app. commit cc5e80ab3aa7934679c2a58a9cf83a0f8cc7ad4e (origin/main) Author: Anthony Miyaguchi <acmiyaguchi@gmail.com> Date: Wed Feb 3 00:14:11 2021 -0800 Add plotly plot for analytics > sapper dev ✔ server (28.3s) ✔ client (28.4s) ✔ service worker (38ms) > Listening on http://localhost:3000 src\routes\analytics\Plot.svelte changed. rebuilding... src\routes\analytics\Plot.svelte changed. rebuilding... ✔ server (8.2s) ✔ client (8.4s) ✔ service worker (30ms) src\routes\analytics\Plot.svelte changed. rebuilding... src\routes\analytics\Plot.svelte changed. rebuilding... ✔ server (7.8s) ✔ client (7.9s) ✔ service worker (35ms) src\routes\analytics\Plot.svelte changed. rebuilding... src\routes\analytics\Plot.svelte changed. rebuilding... ✔ server (7.9s) ✔ client (7.9s) ✔ service worker (31ms) src\routes\analytics\Plot.svelte changed. rebuilding... src\routes\analytics\Plot.svelte changed. rebuilding... ✔ server (8.1s) ✔ client (8.1s) ✔ service worker (32ms) src\routes\analytics\Plot.svelte changed. rebuilding... src\routes\analytics\Plot.svelte changed. rebuilding... ✔ server (8.0s) ✔ client (8.0s) ✔ service worker (34ms) npm run build > Finished in 1m21s. Type node **sapper**/build to run the app. > Finished in 1m20s. Type node **sapper**/build to run the app. > Finished in 1m24s. Type node **sapper**/build to run the app. commit 05af63470f6f590b90dbc7e3a7ae987776651067 Author: Anthony Miyaguchi <acmiyaguchi@gmail.com> Date: Tue Feb 2 23:10:50 2021 -0800 Update analytics page with more tables > sapper dev ✔ server (26.0s) ✔ client (26.1s) ✔ service worker (35ms) > Listening on http://localhost:3000 src\routes\analytics\index.svelte changed. rebuilding... src\routes\analytics\index.svelte changed. rebuilding... ✔ server (1.2s) ✔ client (3.1s) ✔ service worker (31ms) src\routes\analytics\index.svelte changed. rebuilding... src\routes\analytics\index.svelte changed. rebuilding... ✔ server (1.5s) ✔ client (3.6s) ✔ service worker (33ms) src\routes\analytics\index.svelte changed. rebuilding... src\routes\analytics\index.svelte changed. rebuilding... ✔ server (1.5s) ✔ client (3.7s) ✔ service worker (33ms) src\routes\analytics\index.svelte changed. rebuilding... src\routes\analytics\index.svelte changed. rebuilding... ✔ server (1.4s) ✔ client (3.5s) ✔ service worker (32ms) src\routes\analytics\index.svelte changed. rebuilding... src\routes\analytics\index.svelte changed. rebuilding... ✔ server (1.4s) ✔ client (3.5s) ✔ service worker (30ms) npm run build > Finished in 32.5s. Type node **sapper**/build to run the app. > Finished in 32.5s. Type node **sapper**/build to run the app. > Finished in 32.0s. Type node **sapper**/build to run the app.