Skip to content

Convert the render client to TypeScript with a vite-minified build - #159

Merged
Alek99 merged 2 commits into
mainfrom
feat/ts-vite-client
Jul 22, 2026
Merged

Convert the render client to TypeScript with a vite-minified build#159
Alek99 merged 2 commits into
mainfrom
feat/ts-vite-client

Conversation

@Alek99

@Alek99 Alek99 commented Jul 22, 2026

Copy link
Copy Markdown
Member

What

The render client moves from concat-ordered plain JS parts to TypeScript ES modules, bundled and minified by vite — and the minified bundles are what ships to the client.

  • js/src/*.ts: real modules with explicit imports/exports (generated from the cross-file symbol graph); the ChartView prototype-augmentation parts (51–57) import ChartView and are side-effect-imported by the entry; bytesToSpan moved 60_entries00_header to keep the graph acyclic. git mv renames, so blame/history follow.
  • js/build.mjs keeps its exact CLI (node js/build.mjs / --check) but now runs tsc → shader lint → two vite (rolldown/oxc) builds: static/index.js (minified ESM for anywidget, unchanged export surface) and static/standalone.js (minified IIFE; top-level var xy = window.xy).
  • Bundle size: 389 KB → 283 KB (~76 KB gzipped).
  • Typing starts pragmatic (js/tsconfig.json documents the migration posture; ChartView carries an index-signature merge until annotated field-by-field). tsc --noEmit gates every build.

Test/infra fallout

  • Tests that grepped exact source lines out of the built bundles now assert them against the TS sources only; bundles are asserted via minification-surviving markers (string literals, .innerHTML counts, export aliases, IIFE namespace props). The --check freshness gate is what carries source-level invariants into the shipped artifacts (rationale documented in tests/test_static_client_security.py).
  • Every CI/release job that builds the client gains npm ci; the sdist now ships js/ plus the npm manifests so the client is rebuildable from source.
  • CLAUDE.md + spec amended: the §33 no-npm stance becomes dev-time-only toolchain deps (vite/typescript, pinned by package-lock.json); the shipped client remains runtime-dependency-free.

Verification

  • Full pytest suite: 2117 passed / 69 skipped; ruff check/format + pre-commit clean; scripts/verify_ci_workflow.py passes.
  • scripts/render_smoke_nonumpy.py probe matrix fully green against the minified standalone bundle (96.5% lit pixels, picking/selection/modebar/LOD drill, 3 context-loss cycles with identical pixel hashes).
  • Build determinism: --check rebuild is byte-identical across macOS-arm64, linux-arm64, linux-x86_64 (docker rebuilds), so the CI freshness gate holds cross-platform.
  • node -e "import('./python/xy/static/index.js')" export-shape check and node --check standalone.js both pass.

Note: uv run ty check in a fresh venv reports ~15 pre-existing diagnostics in pyplot files byte-identical to main (env/version drift, unrelated to this change).

The client source js/src/* moves from concat-ordered plain JS parts to
TypeScript ES modules: explicit imports/exports replace filename-order
concatenation, the prototype-augmentation parts (51-57) import ChartView
directly, and bytesToSpan moves 60_entries -> 00_header to keep the module
graph acyclic. Typing starts pragmatic (js/tsconfig.json documents the
migration posture); tsc --noEmit now gates every build.

js/build.mjs keeps its CLI (node js/build.mjs / --check) but now runs
tsc -> the shader-convention lint -> two vite (rolldown/oxc) builds, and the
shipped artifacts are minified: static/index.js (anywidget ESM, same export
surface) and static/standalone.js (IIFE; top-level var xy == window.xy).
Bundle drops 389 KB -> 283 KB (~76 KB gzipped). --check byte-compares a
scratch rebuild, verified byte-identical across macOS-arm64, linux-arm64,
and linux-x86_64.

Tests that grepped exact source lines out of the built bundles now assert
them against the TS sources only; bundles are asserted via
minification-surviving markers (string literals, .innerHTML counts, export
aliases), with the --check freshness gate carrying source-level invariants
into the shipped artifacts. CI/release jobs that build the client gain
npm ci; the sdist ships js/ plus the npm manifests; CLAUDE.md and the spec
amend the no-npm stance (SS33) to dev-time-only toolchain dependencies.

Verified: full pytest suite (2117 passed), render_smoke_nonumpy probe
matrix green against the minified standalone bundle, ruff/pre-commit clean.
@codspeed-hq

codspeed-hq Bot commented Jul 22, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 11.24%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
✅ 96 untouched benchmarks
⏩ 1 skipped benchmark1

Performance Changes

Benchmark BASE HEAD Efficiency
test_html_export_line 7.7 ms 6.9 ms +11.24%

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing feat/ts-vite-client (6caeeb0) with main (a763d5f)

Open in CodSpeed

Footnotes

  1. 1 benchmark was skipped, so the baseline result was used instead. If it was deleted from the codebase, click here and archive it to remove it from the performance reports.

@greptile-apps

greptile-apps Bot commented Jul 22, 2026

Copy link
Copy Markdown

Greptile Summary

This PR converts the render client to TypeScript modules and a minified Vite build. The main changes are:

  • Explicit imports and exports across the render client.
  • Minified ESM and standalone IIFE bundles.
  • Type-checking and bundle freshness checks.
  • npm setup in CI and release workflows.
  • Rebuildable JavaScript sources in source distributions.

Confidence Score: 5/5

This looks safe to merge.

No blocking issues found in the changed code.

T-Rex T-Rex Logs

What T-Rex did

  • Recorded a pre-migration standalone smoke page render and captured a poster frame to establish the baseline, with the full command probe logged.
  • Compared the shipped bundle render against the baseline by reviewing the shipped render video and its poster frame, and noted that the comparison and capture logs indicate both sides exited successfully.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
js/build.mjs Replaces source concatenation with TypeScript checking, shader linting, and deterministic Vite builds.
js/src/60_entries.ts Defines the shared entry point, public exports, and side-effect imports for ChartView extensions.
js/src/50_chartview.ts Converts the core ChartView implementation to an exported TypeScript class with explicit dependencies.
js/src/00_header.ts Exports protocol and frame-decoding helpers and relocates aligned payload handling.
pyproject.toml Adds the JavaScript build sources and npm manifests to source distributions.
.github/workflows/ci.yml Installs the npm toolchain before client build and freshness checks.
.github/workflows/release.yml Installs the npm toolchain in release jobs that verify or rebuild the client.

Reviews (2): Last reviewed commit: "Invoke tsc via node, not the .bin shim, ..." | Re-trigger Greptile

spawnSync(node_modules/.bin/tsc) is ENOENT on Windows — the shim there is
tsc.cmd, which spawnSync cannot exec. Running typescript/bin/tsc through
process.execPath works on every platform (caught by the windows-latest
wheel job on #159).
@Alek99
Alek99 merged commit b0f8780 into main Jul 22, 2026
29 checks passed
FarhanAliRaza added a commit that referenced this pull request Jul 22, 2026
The #159 vite-minified build mangles internal declarations, so grepping the
installed bundle for 'function renderStandalone(' has failed ever since when
reflex is installed. Assert on the public export names instead — they are the
stable identity of the real render client.
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