Skip to content

Modernize SigPlot build, test, and CI tooling#18

Draft
mrecachinas wants to merge 17 commits intospectriclabs:mainfrom
mrecachinas:modernize/build-tooling
Draft

Modernize SigPlot build, test, and CI tooling#18
mrecachinas wants to merge 17 commits intospectriclabs:mainfrom
mrecachinas:modernize/build-tooling

Conversation

@mrecachinas
Copy link

@mrecachinas mrecachinas commented Mar 10, 2026

Modernize SigPlot build, test, and CI tooling

Replaces the entire legacy toolchain (Grunt, Karma, QUnit, JSHint, jsbeautify) with modern equivalents:

Build & Dev: esbuild bundler + Vite dev server (replaces Grunt + RequireJS)
Test: Vitest with jsdom (replaces Karma + QUnit) — 128+ new tests added for math, ColorMap, and Plugin coverage
Lint/Format: ESLint 9 flat config + Prettier (replaces JSHint + jsbeautify)
CI: GitHub Actions workflow (replaces Travis CI)
Deps: Dependabot with grouped update schedule

Code changes:

  • Convert all source files from CommonJS IIFE → ES modules
  • Replace underscore dependency with native JS equivalents
  • Replace spin.js and lru with zero-dependency alternatives
  • Remove legacy polyfills from common.js (Promise, Worker, requestAnimationFrame, etc.)

60 files changed across build config, source, and tests.

mrecachinas and others added 17 commits March 8, 2026 14:40
Replace dated build tooling with modern equivalents:

- esbuild replaces Browserify + Babel + Closure Compiler (~200× faster builds)
  Outputs: UMD, minified, ESM, and plugins bundles
- ESLint 9 (flat config) replaces JSHint with auto-fixable rules
- Prettier replaces jsbeautifier for code formatting
- GitHub Actions CI updated: Node 20, modern action versions, lint+build jobs
- package.json: add 'module' and 'exports' fields for dual CJS/ESM publish
- Grunt tooling preserved under 'grunt:*' scripts for backward compatibility

Legacy files (.jshintrc, .jsbeautifyrc, Gruntfile.js, karma.conf.js) kept
for now — will be removed after full migration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Vite config for instant HMR dev server (replaces budo)
- Vitest config with jsdom environment for unit tests
- Vitest browser mode configured (Playwright/Chromium) for canvas tests
- Setup file that makes sigplot globally available for tests
- Smoke test suite (11 tests) validating build output and core APIs
- npm scripts: 'dev', 'test', 'test:watch', 'test:browser'

Existing QUnit tests remain runnable via 'npm run grunt:test'.
New tests use Vitest API — existing tests can be migrated incrementally.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Migrate all 18 source files in js/ from the CommonJS IIFE pattern:
  (function() { var x = require(...); module.exports = X; }());
to standard ES module syntax:
  import x from './x.js'; export default X;

- Remove IIFE wrappers from all files
- Convert require() to import (with .js extension for relative paths)
- Convert module.exports to export default
- Update ESLint config sourceType to 'module'
- esbuild handles the ES module bundling natively

No behavioral changes — same bundle output, same API surface.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove 35+ packages and 7 config files:
- Gruntfile.js, karma.conf.js, .jshintrc, .jsbeautifyrc, .travis.yml, .nvmrc
- All grunt-* plugins (12 packages)
- Karma + launchers + adapters (5 packages)
- Babel toolchain (3 packages)
- QUnit, Jasmine, and related test deps
- JSDoc template deps (catharsis, marked, minami, taffydb)
- budo dev server, travis CLI

Net result: 33 devDependencies → 14, dependencies: 8 → 7
Build toolchain is now: esbuild + ESLint + Prettier + Vitest + Vite

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Convert math, graphics, and colormap tests from QUnit to Vitest:
- tests.m.test.js: sec2tod time formatting tests
- tests.mx.test.js: format_f, real_to_pixel, distance, box tests
- tests.colormap.test.js: ColorMap construction with various color formats

Migration pattern: QUnit.test → it(), assert.equal → expect().toBe(),
assert.close → expect(Math.abs()).toBeLessThanOrEqual()

Total: 4 test files, 17 tests, all passing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
These tests have been migrated to Vitest (.test.js files).
The HTML test runners are no longer needed (Vitest replaces Karma).

Remaining QUnit files (tests.js, tests.sigplot.js, tests.interactive-*.js)
are kept for reference — they require real browser canvas and will be
migrated when Vitest browser mode is fully set up.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Convert tests.sigplot.js from QUnit to Vitest API:
- 17 tests pass in jsdom (Plot construction, overlay, layers, zoom, etc.)
- 8 tests skipped: need real browser (layout-dependent or XHR-based)
- Enhanced vitest.setup.js with canvas 2D context stub for jsdom
- Removed migrated QUnit files (tests.sigplot.js, tests.js)

Remaining unmigrated: 12 interactive test files (manual visual verification
tests using interactiveTest() — these prompt humans to verify rendering).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove .jshintignore (JSHint no longer used)
- Remove .npmignore (empty; package.json 'files' field handles publishing)
- Trim .gitignore from 100+ lines of boilerplate to ~25 relevant entries

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- engines: node >= 18
- Dependabot: weekly npm + GitHub Actions updates
- Groups: dev deps (minor/patch), prod deps (minor/patch), actions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove underscore dependency — all 11 usages replaced with builtins:
- _.clone(obj) → Object.assign({}, obj)
- _.has(obj, key) → Object.prototype.hasOwnProperty.call(obj, key)
- _.indexOf(arr, val) → arr.indexOf(val)
- _.isFunction(fn) → typeof fn === 'function'
- _.size(obj) → Object.keys(obj).length
- _.each(arr, fn) → arr.forEach(fn)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace spin (2013, unmaintained) with a CSS-only spinner:
  28px border-based circle with @Keyframes rotation, injected once
- Replace lru (uses Node 'events' module) with inline js/lru.js:
  25-line Map-based LRU cache with get/set/eviction
- Remove events polyfill (no longer needed without lru)
- Fix leftover _.mapObject call in hide_spinner

Dependencies dropped: spin, lru, events (3 packages removed)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove polyfills targeting IE/ancient browsers (now targeting ES2018+):
- ArrayBuffer.prototype.slice (iOS/old Firefox)
- ArrayBuffer.isView
- requestAnimFrame/cancelAnimFrame shims → native requestAnimationFrame
- Float64Array polyfill (iOS)
- String.prototype.endsWith (ES6)
- TypedArray.prototype.slice (6 types)
- Array.isArray
- console shim
- Firefox 4 subarray bug workaround
- addWheelListener (mousewheel/DOMMouseScroll) → native 'wheel' event
- Proxy polyfill
- mozDash/webkitLineDash fallbacks in dashOn/dashOff → setLineDash only
- window.event/attachEvent fallbacks

Kept: ArrayBuffer.transfer polyfill (not yet universal),
dashOn/dashOff, getKeyCode, setKeypressHandler, update, debounce, uuidv4.

common.js: 393 lines → 100 lines

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Configure @vitest/coverage-v8 with text, lcov, and html reporters
- Add npm script: test:coverage

New test files:
- lru.test.js: 8 tests — eviction, recency refresh, overwrite, edge cases (100% coverage)
- common.test.js: 11 tests — dashOn/Off, getKeyCode, update, debounce, uuidv4
- m.math.test.js: 20 tests — vmov, vmovmax, vmxmn, vsmul, vfill, vabs,
  cvmag, cvmag2, PointArray, throttle

Total: 8 test files, 71 passing, 8 skipped
Coverage: lru.js 100%, common.js 82% (+29), m.js 62% (+7)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
New test files:
- m.extended.test.js (84 tests): log10, vlog10, vlogscale, cvmag2logscale,
  cvpha, cvphad, trunc, sign, bound, mult_prefix, trim_name, epoch
  conversion round-trips, pad
- ColorMap.extended.test.js (21 tests): construction, setRange,
  getColorIndex, getColorByIndex, getNColors, interpolation, edge cases
- sigplot.plugin.test.js (23 tests): Plugin lifecycle, init/dispose,
  addListener/removeListener, menu/refresh hooks, properties

Coverage improvements:
  m.js:              62% → 80% stmts, 42% → 64% branch, 61% → 85% funcs
  ColorMap.js:       75% → 81% stmts
  sigplot.plugin.js: 42% → 84% stmts, 42% → 100% funcs

Total: 11 files, 199 passing, 8 skipped

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mock clientWidth/clientHeight on the container element to return
dimensions based on style.width/height (accounting for display:none).
This lets the 5 previously-skipped tests pass in jsdom without a
real browser layout engine.

Remaining 3 skipped: XHR-based tests (overlay_href needs file loading)

Tests: 204 passing, 3 skipped (was 199 passing, 8 skipped)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Vitest browser mode requires server-side preprocessing of setup files,
but sigfile's UMD wrapper references 'window' at top level, causing
failures in Node context. Until sigfile ships proper ESM exports,
jsdom with canvas context stubs is the correct approach.

The canvas stubs are sufficient for testing data structures, API surface,
math operations, and plot construction logic — which is what matters for
unit tests. Visual rendering is covered by the interactive test suite.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant