Skip to content

Latest commit

 

History

History
122 lines (87 loc) · 6.04 KB

File metadata and controls

122 lines (87 loc) · 6.04 KB

plotly.js fork context

This is a fork of plotly/plotly.js maintained at runsascoded/plotly.js.

Purpose

Provide a customized plotly.js for use across several projects (NJ crashes, PATH ridership, hub-bound travel, hudson-transit, awair, etc.) via pltly (React wrapper) and pds (dependency management).

Current fork changes (vs upstream v3.3.1)

  • ESM conversion: All 971 source files converted from CJS to ES modules. "type": "module" in package.json. Enables tree-shaking by bundlers.
  • d3 v7 migration: Replaced @plotly/d3 (vendored d3 v3, 229 KB CJS blob) with modern d3 v7 ESM packages. src/lib/d3-compat.js polyfills v3 patterns (enter/merge, .style({}), .select() data propagation).
  • Tree-shakeable factory: createPlotly() in lib/factory.js — consumers import only traces/components they need. Scatter+bar+legend: 741 KB min (-32% vs upstream basic 1,089 KB).
  • Dep inlining: gl-mat4 → inline 4x4 ops, Node.js events → MiniEmitter, shapes decoupled from core
  • z-order fix: Preserve z-indexed subplots during relayout for correct pan/zoom
  • Touch fix: Prevent duplicate plotly_click and scroll-triggered clicks
  • Flush legend toggle rects: Expand legend item hit areas so they tile flush (no hover gaps)
  • Custom legend symbols: legendsymbol.path trace attribute for custom SVG legend icons
  • Treemap transpose: Add tiling.transpose attribute for treemap traces
  • exports map: Subpath imports (plotly.js/basic, plotly.js/core, etc.) via lib/
  • Lite bundle: plotly.js/lite — scatter + bar with only essential components
  • Deferred margins: config.deferAutoMargin for 15-29% faster first paint
  • Perf instrumentation: performance.measure() around key render phases
  • pnpm: Switched from npm to pnpm (lockfile, overrides, build scripts)

Build & dist

Built files are not tracked on main. dist/ is fully gitignored. Source data files (topojson, schema) live under topojson/dist/ and are generated by the build.

The dist branch is auto-built by GHA (runsascoded/npm-dist@v1) on push to main. It includes ESM source (lib/, src/) for tree-shakeable imports AND pre-built bundles (dist/) for CDN/script-tag use.

# Full local build (all bundles + locales + schema)
pnpm run build

# Individual steps
pnpm run bundle          # main plotly.js + plotly.min.js
pnpm run extra-bundles   # basic, cartesian, finance, geo, gl2d, gl3d, mapbox
pnpm run fork-bundles    # lite, minimal
pnpm run schema dist     # generate plot-schema.json

Build scripts in tasks/ are .cjs (CJS) or .mjs (ESM). The preprocess step generates src/plotcss.js and lib/*.js entry points — run it before bundling.

Bundle variants

Bundle Entry point Unminified Contents
lite plotly.js/lite 1,944 KB scatter + bar, 6 components
minimal plotly.js/minimal 2,251 KB scatter + bar, all 15 components
basic plotly.js/basic 2,550 KB scatter + bar + pie + calendars, all components

Performance testing

pnpm run perf        # benchmark minimal bundle
pnpm run perf:lite   # benchmark lite bundle
pnpm run perf:basic  # benchmark basic bundle

# Options:
node perf/bench.mjs --lite --minify   # minified bundle
node perf/bench.mjs --lite --defer    # with deferAutoMargin
node perf/bench.mjs --lite --update   # accept new bundle size
node perf/bench.mjs --lite --headed   # visible browser

Bundle sizes are asserted at the exact byte level in perf/thresholds.json. Pass --update to accept changes.

Downstream stack

plotly.js (this fork, ESM)
  └─ pltly (React hooks: hover, solo, pin, fade, dual-axis, theme)
       └─ consumer apps (crashes, path, hub-bound, hudson-transit, awair, etc.)
  • pltly wraps plotly.js with React hooks for legend interaction, trace highlighting, mobile touch fixes, and theme support
  • pds manages switching between local/GH-dist/npm versions across the stack

Testing in consumer projects

# In consumer project:
pds l plotly     # switch to local ESM source (Vite imports directly, no pre-bundling)
pds gh plotly    # switch to GitHub dist branch (ESM source + pre-built bundles)
pds n plotly     # switch to upstream npm

With ESM, pds l and pds g behave identically — no more CJS pre-bundling issues, no resolve.alias hacks, no optimizeDeps configuration needed.

Design philosophy

ESM-first

The fork is fully ESM. Consumer bundlers (Vite, esbuild) handle plotly natively — no CJS pre-bundling, no plotly.js-dist-min separate package, no Vite optimizeDeps workarounds.

Minimize "custom" code in consumer apps

Consumer apps should NOT need to build their own legend UIs, implement trace fading/highlighting, handle mobile touch quirks, or manage plotly bundle loading. These are handled by plotly.js (rendering) and pltly (React integration).

What to upstream vs keep in fork

Keep in fork: ESM conversion, custom legend symbols, lite bundle, registration system changes

Consider upstreaming (bug fixes, non-breaking): flush legend toggle rects, z-order relayout fix, touch interaction fixes, deferAutoMargin

Specs

Active specs in specs/:

  • remove-registration-system.md — eliminate global registry, enable full tree-shaking (partially done: factory entry point works, shapes/modebar decoupled, drawing converted to named exports)
  • pltly-factory-migration.md — migrate pltly React wrapper to use createPlotly() factory

Completed specs in specs/done/ (15 total): esm-conversion, esm-cjs-interop, esm-ternary-attrs, esm-css-imports, stackgl-esm-shim, dist-branch-esm, dist-extra-bundles, dist-branch-missing-dirs, dist-lib-stale, flush-legend-toggle-rects, legend-icon-symbols, custom-minimal-bundle, perf-harness, fast-initial-render, d3-v7-migration