feat(signals,solid): pay-for-use tree-shaking phase 3 — audited cleanups (#2883) - #2890
Conversation
Mechanical cleanups chosen by the phase-3 cost/benefit audit (delegation seam and snapshot seam rejected by design ruling / weight gate): signals: - dedupe effect re-enqueue block (4 copies) + zombie/dirty queue ternaries into enqueueSub/queueFor; hot write loop microbenched, no regression - _-prefix boundary/reveal internal method names so property mangling reaches them (verified internal-only) - trim prod error strings to diagnostic codes; dev keeps full sentences - stop stripping /*@__PURE__*/ from dist/prod: drop rollup-plugin-prettier from the prod tree (it deletes annotations), terser preserve_annotations in mangle-props.mjs, new scripts/check-pure.mjs fails the build if annotations vanish again solid-js client: - sharedConfig.getNextContextId installs from enableHydration(); defining it in the object literal retained context/error machinery in every CSR bundle (SharedConfig.getNextContextId now optional) - lazy()'s hydration-module lookup moves behind _lazyHydrationLookup, installed by enableHydration() - MockPromise: class static block defeated DCE in every client bundle; now a PURE-annotated factory packaging: unpkg/jsdelivr fields point at browser prod ESM (were CJS, browser-fatal on bare CDN URLs) Measured (esbuild, minify, mangle-props ^_, gzip -9): - minimal app: 27,570/10,870 -> 26,429/10,432 - CSR app (+Loading/lazy): 35,565/13,935 -> 32,067/12,601 (incl. DOMElements dedup propagating through rebuilt web runtime) - signals floor: 18,921/7,687 -> 18,539/7,515 - full bundle: 55,366/20,587 -> 54,587/20,315 (hook-tax clawback) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 5946c0e The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
Coverage Report for CI Build 29448338455Warning No base build found for commit Coverage: 74.74%Details
Uncovered Changes
Coverage RegressionsRequires a base build to compare against. How to fix this → Coverage Stats
💛 - Coveralls |
Merging this PR will not alter performance
Comparing Footnotes
|
Rollup literal-tracks never-written module state and folds the dead branches; esbuild cannot, so these paths shipped only to esbuild-class consumers. Restructured so both bundlers land in the same place, all Rollup-neutral by measurement: - external-source wiring (computed setup + untrack) moves behind GlobalQueue hooks whose installs mirror enableExternalSource()'s config liveness exactly (installed on enable, removed on reset) - onlyMarkPending moves from async.ts into affects.ts behind the activeAffectsMarks-gated hook (mark-transparency is affects-only) - the optimistic-store settle loop moves inside the store-side hook (_clearOptimisticStores takes the batch; scheduler keeps a size-guarded call) esbuild minimal app: -77 gz from these + -194 gz from the companion dom-expressions hydration-hook change (ryansolid/dom-expressions#544). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 3 of #2883 — every item here passed the cost/benefit audit (wins-population / pays-population / complexity, adversarially verified with byte-exact reproduction). Two analyst-proposed items were rejected by ruling: the event-delegation seam (delegation is the blessed path — all apps are assumed to have it) and the snapshot-capture seam (win too small for a new seam under the weight gate).
Measured (esbuild, minify,
--mangle-props='^_', gzip -9)<Loading>/lazy*includes ryansolid/dom-expressions#543 (DOMElements dedup) propagating through the rebuilt web runtime.
Cumulative over phases 1–3: minimal app 12,656 → 10,432 gz (−17.6%), signals floor 8,885 → 7,515 gz (−15.4%).
Changes
@solidjs/signals
enqueueSub/queueFor— the hot write-propagation loop was microbenched against baseline (interleaved 100-fanout write+flush ×20k), no regression._-prefixed so property mangling reaches them (verified not part of any exported surface; the server'srevealGroup.registeris a different object)./*@__PURE__*/annotations —rollup-plugin-prettierstrips them, and terser only re-emits them withpreserve_annotations. Prettier is off the prod tree (the mangle post-pass beautifies anyway), terser preserves, and a newscripts/check-pure.mjsguard fails the build if src has annotations and dist has none.solid-js (client)
sharedConfig.getNextContextIdwas defined in the object literal, retaininggetContext/NoHydrateContext/getNextChildIdand the signals context+error machinery in every CSR bundle; it now installs fromenableHydration()(type becomes optional; both callers sit behindsharedConfig.hydrating).lazy()'s hydration-module lookup (positional id +_$HY.modules+ error string) moves behind an_lazyHydrationLookupslot installed byenableHydration()— the 12th instance of the existing override-slot pattern.static {}block marked the class side-effectful, defeating DCE in every client bundle (the code comment claiming it shakes was wrong); it's now a PURE-annotated factory that shakes with its only consumer.Packaging
unpkg/jsdelivrfields pointed at CJS files (browser-fatal on bare CDN URLs — verified over the network); they now point at browser production ESM for all three packages.Verification
984 signals + 456 solid + 501 solid-web tests green; both typechecks clean;
check-pureguard active in the signals build. Rejected-by-audit items are documented in the analysis (dist minification, standalone CDN bundle,reconcileArraysdetach, hydration guards ininsert, flatten split, optimistic helper dedup — each with the measured reason).🤖 Generated with Claude Code