Skip to content

feat(unplugin): build-time catalogue narrowing for tree-shaking#60

Closed
bigmistqke wants to merge 27 commits into
solidjs-community:nextfrom
bigmistqke:unplugin-solid-three
Closed

feat(unplugin): build-time catalogue narrowing for tree-shaking#60
bigmistqke wants to merge 27 commits into
solidjs-community:nextfrom
bigmistqke:unplugin-solid-three

Conversation

@bigmistqke
Copy link
Copy Markdown
Contributor

@bigmistqke bigmistqke commented May 31, 2026

Summary

Adds packages/unplugin-solid-three, a build-time plugin that rewrites createT(THREE) into a curated createT({ Mesh: THREE.Mesh, … }) containing only the classes actually reached through T, so bundlers can tree-shake the rest. You keep writing the concise, fully-typed createT(THREE); the plugin automates the manual curation the Tour already recommends.

  • Symbol-accurate analysis (ts-morph): follows T across files, re-exports, renames, and aliases via findReferences; collects member/JSX-member/element/destructure accesses.
  • Sound by construction: narrows only when provably safe (a five-clause narrowability definition). Dynamic access (T[expr]), escapes, proxies, and reactive stores keep the full catalogue — with a warn (or build error under strict) for defeated namespaces and info for non-analyzable arguments.
  • Precedence-correct spread collapsing (last-write-wins), verbatim opaque values (getters/methods), build-only (dev keeps the runtime proxy).
  • Ships as an unplugin (Vite/Rollup/webpack/esbuild/rspack); ts-morph isolated to this build-only package.

Design + scenario docs under docs/superpowers/.

Test Plan

  • pnpm -C packages/unplugin-solid-three test — 52 Node tests (analysis matrix, rewrite, diagnostics, factory, e2e Vite bundle, js/jsx support)
  • pnpm -C packages/unplugin-solid-three test:oracle — browser soundness oracle: mounts a real scene, asserts every key the proxy is asked for ⊆ the narrowed catalogue
  • pnpm -C packages/unplugin-solid-three exec tsc --noEmit — typecheck
  • pnpm -C packages/unplugin-solid-three build — tsup dist

Known limitation

Analysis covers files in your tsconfig Program; mixed JS/TS projects must enable allowJs/include their JS. A bundler-module-graph cross-check guard (bail+warn on any unanalyzed createT/T module) is the planned follow-up. Documented in the package README.

🤖 Generated with Claude Code

bigmistqke added 27 commits May 31, 2026 08:43
…ition

Distill the design discussion: createT-only (provided-T and extends
deferred but architecturally allowed), five-clause narrowability
definition as the centerpiece, precedence-correct spread collapsing,
opaque-value rule, escape guard, curation-as-escape-hatch, and two-tier
diagnostics. Add companion scenarios/complexity exploration doc.
Make explicit that the failure mode is silent and catastrophic, so the
test suite is the safety net. Add the soundness oracle (instrument the
proxy, assert requested keys subseteq narrowed catalogue) as the
linchpin, a layered fixture-matrix + bundler-matrix + fuzz strategy,
mutation/TS-version meta-tests, and a soundness-vs-effectiveness release
gate.
Expand layer 5 into a full subsection: grammar over the three axes
grounded in real @types/three exports, white-box + black-box oracles
layered by cost, metamorphic relations needing no ground truth, fast-check
shrinking with failures promoted to permanent fixtures, and seed
reproducibility.
v1 = analysis fixture-matrix, rewrite snapshots, soundness oracle,
Vite-only bundle assertions, diagnostics, modest TS-version matrix.
Generative/fuzz (blueprint retained), the full bundler matrix, and
mutation testing move to follow-ups; release gate updated accordingly.
Approve the spec: factory-returned T is treated as an escape (keep whole)
except trivially-local cases; interprocedural relaxation deferred. The
only remaining open item is Project build-cost tuning, a non-blocking
implementation-time concern.
18 TDD tasks: scaffold, ts-morph analysis (find createT, classify refs,
used-set, namespace enumeration, precedence providers, five-clause
resolve), rewrite/emit, two-phase unplugin wiring, Vite bundle assertion,
browser soundness oracle, TS-version matrix, README. Clause 4/5 edge
cases documented as tracked follow-ups.
Also tighten Identifier narrowing in find-createt and the classify-ref
test helper so the package type-checks under tsc --noEmit.
Log via console and throw on strict (unplugin's build context exposes no
warn/error). Serialize test files and raise the timeout so parallel
ts-morph language services don't trip the per-test timeout.
Use the namespace identifier's resolved type properties instead of
Symbol.getExports(), which doesn't flatten the `export *` re-exports the
three types are built from. Caught only by the real-three bundle test.
Mount the fixture in a real Canvas in Chromium, record every key requested
of the T proxy, and assert it equals the analyzer's narrowed set. Mount
Canvas + entities from the same mocked solid-three module to share one
threeContext; key the generated set by basename so the browser test needs
no node:path. Add jsx/DOM to tsconfig for the .tsx fixtures.
JS/JSX files are followed when part of the TS Program (allowJs on); files
outside it are invisible to the analyzer. Document this and the planned
bundler-graph cross-check guard.
Swallow exactly the solid-three frameloop's async boundingSphere error
(thrown after the assertion); any other error still fails the run.
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 31, 2026

commit: 4afe08e

@bigmistqke
Copy link
Copy Markdown
Contributor Author

Superseded by #61, which takes a fundamentally different approach: instead of reconstructing cross-file usage analysis with ts-morph (plus alias resolution and a soundness guard), it lets the bundler's own tree-shaking measure which catalogue keys are used. Exact rather than over-approximate, sound by the bundler's deopt, and Vite-native. Closing in favor of #61.

@bigmistqke bigmistqke closed this Jun 1, 2026
@bigmistqke bigmistqke deleted the unplugin-solid-three branch June 2, 2026 19:00
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