Minor Changes
- 5455320: Register call-shaped component bindings in the refresh (HMR) pass (#3090). A component produced by a factory call —
styled(...), an HOC, a tagged template — was never registered, and once a registered sibling made the module self-accept,hot.accept()disabled the very module invalidation its staleness relied on: the export went permanently stale, silently. Two compile-time admission gates fix this. A call-shaped top-level binding rendered as a JSX tag in its own module is proven a component and registers automatically (resolution is scope-aware — shadowing locals don't count). For export-only shapes with no in-module usage, the per-binding@refresh componentpragma asserts it:export const Badge = /* @refresh component */ styled.span\...``. Registered call bindings get the full treatment — location, granular signature, and dependencies, with same-module registered components excluded from the dependency set (edits propagate through the proxy chain; counting them would remount the consumer on every edit of the module). This is a deliberate native-first divergence from the frozen Babel-plugin reference.
Patch Changes
- 3a2d214: The native compiler's JS loader accepts the
patchDriveroption and normalizes the boolean opt-in: the Rust core supports the option (dormant by default), butvalidateOptions' whitelist rejected it, and the napi wrapper mapping collapsestrueintoWrapper::Default— whichpatch_driveruniquely treats as disabled. The loader now whitelists the option and mapstrueto the default"patchDriver"import name so an explicit opt-in through@solidjs/vite-pluginreaches the native core. - bfc834e: Prefer a local development build (
compiler.node) over the installed@solidjs/compiler-*platform package when loading the native binding. The published package ships no local binary, so a local build can only mean development — but the loader tried the platform package first, which made the monorepo's own tests (locally and in CI) silently run against the last published release instead of the code under test. A present-but-unloadable local build now fails loudly instead of degrading to the published binary. - 2f01f23: Module-level "use server" exports now register by value: the server build registers each export's evaluated terminal initializer whole, so server-side wrappers compose onto every call path —
export const getUser = withValidation(schema, fn)applies the wrapper to HTTP dispatch and in-process SSR calls alike, and patterns likewithDelay(fn, 400)work for server mocks. The client build always emits bare references, so wrappers, schemas, and helpers stay server-only by construction. The compiler never inspects the initializer's shape;registerServerReferencenow throws at module eval when handed a non-function, turning stray non-function exports into loud boot errors instead of dead references. Anonymous default expressions (export default withDelay(...),export default async () => ...) get a synthesized binding and register too — previously they were silently dropped from both builds. Supersedes the unreleased wrapped-export compile error. - 8d249c7: Patch-channel contract hardening from the stage-2 re-audit: ordinary
patchDriverregistrations unbind with their owner (entries no longer leak past unmount); merged transitions move their held-patch stash so no patch strands; the optimistic drain shares the normal drain's per-entry error isolation and boundary routing; accessor-bearing records are excluded at admission (scan-before-trust) and records that acquire accessors demote their patches to tracked effect fallbacks; writable projection arrays emit setter row ops at their fold-commit visibility moment; row-ops/slot registrations resolve chained backings to the ultimate owner; duplicate keys match occurrence-aware instead of first-wins; the production dev-token typo (_DX_DEV_) is fixed;patchDriver: truenormalizes identically in Babel and the native loader, the option is typed inTransformOptions, and adom-patchparity tier ratchets patch-mode output across both compilers (currently byte-identical on all fixtures). - b534733: Scope-wrap bare function children in hydratable mode. A function child (
<main>{() => <App/>}</main>, including via thechildrenattribute) is a deferred hole at runtime, but it never classified asdynamic, so neither generate reserved an id scope for it — its owner ids drifted across async retry passes on the server and desynced from the client (the #2900 hydration-id-parity class). Both compilers now treat syntactic function expressions as scope-eligible alongside dynamic values, emitting_$scope(...)in the ssr generate and around the matching insert accessor in the dom generate. The native compiler also unwraps TS casts in the allocate-ids predicate, matching Babel (fixes a scope-emission desync for{call() as any}children).