diff --git a/.changeset/pre.json b/.changeset/pre.json index ff321db92..96701a721 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -103,6 +103,7 @@ "compiler-component-names", "compiler-loader-accepts-patch-driver", "compiler-loader-prefer-local-build", + "compiler-spread-sources-array", "composed-header-bounds-transport", "contain-flight-collector-errors", "container-tier-projection-traces", @@ -119,6 +120,7 @@ "dedupe-strict-read-diagnostics", "demote-boundary-primitives", "deprecate-create-tracked-effect", + "deprecate-dynamic-component", "deprecate-server-writes", "dev-artifact-naming", "dev-error-invalid-refresh-target", @@ -149,9 +151,12 @@ "drop-compiler-legacy", "dynamic-factory-redesign", "dynamic-remount-latest-address", + "dynamic-run-hydration-events", + "dynamic-xmlns-namespace", "effect-cleanup-unwind-order", "effect-error-arm-queued", "effect-error-handler-unwrap", + "effect-mainline-ownership-3412", "effect-phase-write-visibility", "effect-relay-tear", "effect-run-trims", @@ -183,6 +188,7 @@ "fix-array-target-dictionary-mode", "fix-asset-preload-rejection", "fix-async-boundary-diagnostic", + "fix-async-chain-second-write", "fix-async-generator-action-freeze", "fix-async-iterable-hydration-flush", "fix-async-iterator-cancellation-wrappers", @@ -242,6 +248,10 @@ "fix-frames-web-path-mapping", "fix-get-grant-lifetime-and-read-folding", "fix-halt-error-swallow", + "fix-held-conditional-effect", + "fix-held-conditional-memo", + "fix-held-reader-disposed-lane-hold", + "fix-held-transition-child-disposal", "fix-hybrid-iterable-signal-takeover", "fix-hydrated-nullish-values", "fix-hydration-and-signals-baseline", @@ -283,6 +293,7 @@ "fix-maparray-async-store-settle-wedge", "fix-maparray-notready-exception-safety", "fix-memo-created-inside-latest-window", + "fix-merge-plain-result-not-flattened", "fix-merged-lane-hold-per-node", "fix-mid-recompute-missed-wakes", "fix-nested-array-async-reconcile", @@ -293,8 +304,10 @@ "fix-nullish-lone-spread", "fix-omit-merge-sources-tunnel", "fix-onsettled-unowned-cleanup", + "fix-optimistic-lane-release", "fix-optimistic-override-premature-revert", "fix-optimistic-same-value-overlap", + "fix-optimistic-settle-verdicts", "fix-optimistic-store-layer-scope", "fix-optimistic-store-refetch-hold", "fix-optimistic-store-stash-flicker", @@ -304,6 +317,7 @@ "fix-owned-write-guard-docs", "fix-ownerless-conditional-memos", "fix-pending-autodispose-release", + "fix-pending-companion-lane-parent", "fix-pending-gated-landing-replay", "fix-portal-mount-ref-timing", "fix-portal-ownership-and-accumulation", @@ -377,6 +391,7 @@ "fix-spread-hydration-mismatch", "fix-ssr-async-error-handling", "fix-ssr-bench-shape", + "fix-ssr-element-nullish-style-class", "fix-ssr-errored-async-retry-loop", "fix-ssr-escape-function-results", "fix-ssr-loading-errored-hydration", @@ -391,6 +406,7 @@ "fix-ssr-spread-children-read-once", "fix-ssr-stream-rejected-fragment-hang", "fix-ssr-sync-memo-child-id-leak", + "fix-ssr-text-separators-resolved", "fix-ssr-textarea-spread-value", "fix-ssrsource-client-hybrid-hydration", "fix-stateful-prop-hydration-adoption", @@ -473,6 +489,7 @@ "improve-tsrx-lazy-destructuring", "include-web-cookie-declarations", "inv2-active-override-assertion", + "ispending-held-sync-memo", "ispending-loading-guard", "ispending-wrapper-fresh-hold", "iterate-bare-step-tolerance", @@ -486,6 +503,7 @@ "late-boundary-held-fragment-wait", "latest-lazy-companion-backfill", "latest-probe-order-independence", + "latest-shadow-owned-write", "lazy-assets-post-settle-livelock", "lazy-async-asset-resolver", "lazy-async-inflight-autodispose", @@ -525,6 +543,7 @@ "nohydration-lazy-maparray-deps", "notready-skip-stack-capture", "npm-descriptions", + "observe-exclude-interaction-writes", "observe-node-shapes", "observe-shape-freeze", "observe-tier", @@ -566,6 +585,7 @@ "perf-2893-guard-cleanup", "perf-dep-revalidation-and-reconcile", "perf-footer-attribution-discovery", + "perf-ssr-walker-entry", "perfect-spies-pretend", "phase2-optimistic-code-reduction", "pin-prop-condition-memo-id-parity", @@ -574,6 +594,7 @@ "portal-marker-cleanup", "predigested-flight-outcome", "preload-identity-qualifiers", + "preloadable-server-function-reads", "preserve-bound-event-tuples", "preserve-store-symbol-snapshots", "projection-leaf-release", @@ -628,11 +649,13 @@ "remove-loading-notify-through-remap", "remove-on-namespace-events", "remove-patch-channel", + "remove-server-function-instance-header", "remove-ssr-run-in-scope", "remove-store-readonly", "rename-createLoadingBoundary", "rename-pending-to-latest", "rename-purewrite-to-ownedwrite", + "render-to-string-sync-dispose", "renderer-owned-jsx-types", "repeat-disjoint-window", "republish-fresh-signals-build", @@ -657,6 +680,7 @@ "serialization-decode-entry", "server-component-context-barrier", "server-dev-build", + "server-diagnostics-channel", "server-first-value-lock", "server-function-call-observers", "server-function-data-address-split", @@ -671,9 +695,11 @@ "server-memo-commit-liveness", "server-memo-scaffold-diet", "server-mock-csp-nonce", + "server-observe-install-point", "server-projection-errors", "server-slot-store-and-boundary-trims", "server-store-replacement-optimistic-noop", + "server-trace-context", "setter-row-ops-tentative-lists", "settle-superseded-flight-dependents", "settle-unchanged-pending-branches", @@ -703,6 +729,10 @@ "snapshot-trailing-holes", "solid-native-frame-protocol-identifiers", "spread-direct-sources", + "spread-fewer-nodes", + "ssr-boundary-resolve-scope-3414", + "ssr-component-names", + "ssr-element-sources", "ssr-falsy-rejections-and-thenables", "ssr-hole-id-scopes", "ssr-retry-robustness", @@ -768,6 +798,7 @@ "two-weeks-smell", "typed-preload-links", "universal-renderer-effect-names", + "universal-spread-sources", "unstable-list-identity", "until-flip-entanglement", "until-live-source-ack", diff --git a/packages/babel-plugin/CHANGELOG.md b/packages/babel-plugin/CHANGELOG.md index ed1892028..ee42b65a0 100644 --- a/packages/babel-plugin/CHANGELOG.md +++ b/packages/babel-plugin/CHANGELOG.md @@ -1,5 +1,16 @@ # @solidjs/babel-plugin +## 2.0.0-rc.9 + +### Patch Changes + +- 8d6de07: Native elements with several spread sources compile to the runtimes' array form instead of a `mergeProps()` call, in DOM and SSR output: `
` becomes `spread(el, [{ id: "x" }, a, b], …)` on the client and `ssrElement("div", [{ id: "x" }, a, b], …)` on the server. The runtimes read the sources directly — later sources win per key, only the winning source is read — with no merge proxy to build and walk, and a reactive spread is a plain thunk called inside the tracking scope, so it mints no memo and consumes no hydration id on either side (the hydratable SSR `() => mergeProps(…)` wrapper is gone for the same reason). A lone spread still passes straight through (#3105). Requires `@solidjs/web` with the `spread`/`ssrElement` array forms (#3418, #3419). +- 63560a1: `componentNames` now applies to SSR output. Under the option both compilers keep the `createComponent` call they otherwise inline to `Comp(props)` and pass the source tag name — `createComponent(Comp, props, "Comp")` — so the server runtime's observe/dev `createComponent` labels the owner and a server finding's `ownerPath` reads `` like the client's. Without the option (prod builds) SSR output is unchanged. `@solidjs/vite-plugin` already passes the option for its dev and observe postures, so app server builds pick this up with no config change. + + Fixes `ssrScope` under transparent owners: the virtual hole scope swapped the current owner's id counter, but content inside a hole resolves ids by walking past transparent owners, so with one in between (the server-component scope owner; now the labelled component owner) the hole's content took ids from the enclosing counter and disagreed with the client. The scope now swaps the nearest id-bearing owner. + +- 1643d2a: The universal renderer's `spread()` follows the `@solidjs/web` contract (#3388): `ref` folds into the props effect and is re-applied only when its identity changes (refs run with no owner, so nothing they create is disposed by the fold); children keep their own owned `insert` — that effect owns the child subtree — but a plain object whose `children` is a data property inserts the value with no effect at all. Three reactive nodes become two when children flow through the spread, one when they don't. `spread` also resolves a lone function source inside its own tracking scopes and accepts an array of sources — `spread(node, [a, b], skipChildren)` — the union of their keys with later sources winning, only the winning source read, function sources called inline with no merge and no memo. Both compilers' universal output uses it: a lone spread passes straight through (reactive included, no more `mergeProps(() => …)`), and several sources compile to the array instead of a `mergeProps()` call. + ## 2.0.0-rc.8 ### Patch Changes diff --git a/packages/babel-plugin/package.json b/packages/babel-plugin/package.json index ef17c5206..775382b76 100644 --- a/packages/babel-plugin/package.json +++ b/packages/babel-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@solidjs/babel-plugin", "description": "Babel compiler plugin for Solid templates", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "author": "Ryan Carniato", "license": "MIT", "repository": { diff --git a/packages/compiler/CHANGELOG.md b/packages/compiler/CHANGELOG.md index 3091161bd..b804a38af 100644 --- a/packages/compiler/CHANGELOG.md +++ b/packages/compiler/CHANGELOG.md @@ -1,5 +1,16 @@ # @solidjs/compiler +## 2.0.0-rc.9 + +### Patch Changes + +- 8d6de07: Native elements with several spread sources compile to the runtimes' array form instead of a `mergeProps()` call, in DOM and SSR output: `
` becomes `spread(el, [{ id: "x" }, a, b], …)` on the client and `ssrElement("div", [{ id: "x" }, a, b], …)` on the server. The runtimes read the sources directly — later sources win per key, only the winning source is read — with no merge proxy to build and walk, and a reactive spread is a plain thunk called inside the tracking scope, so it mints no memo and consumes no hydration id on either side (the hydratable SSR `() => mergeProps(…)` wrapper is gone for the same reason). A lone spread still passes straight through (#3105). Requires `@solidjs/web` with the `spread`/`ssrElement` array forms (#3418, #3419). +- 63560a1: `componentNames` now applies to SSR output. Under the option both compilers keep the `createComponent` call they otherwise inline to `Comp(props)` and pass the source tag name — `createComponent(Comp, props, "Comp")` — so the server runtime's observe/dev `createComponent` labels the owner and a server finding's `ownerPath` reads `` like the client's. Without the option (prod builds) SSR output is unchanged. `@solidjs/vite-plugin` already passes the option for its dev and observe postures, so app server builds pick this up with no config change. + + Fixes `ssrScope` under transparent owners: the virtual hole scope swapped the current owner's id counter, but content inside a hole resolves ids by walking past transparent owners, so with one in between (the server-component scope owner; now the labelled component owner) the hole's content took ids from the enclosing counter and disagreed with the client. The scope now swaps the nearest id-bearing owner. + +- 1643d2a: The universal renderer's `spread()` follows the `@solidjs/web` contract (#3388): `ref` folds into the props effect and is re-applied only when its identity changes (refs run with no owner, so nothing they create is disposed by the fold); children keep their own owned `insert` — that effect owns the child subtree — but a plain object whose `children` is a data property inserts the value with no effect at all. Three reactive nodes become two when children flow through the spread, one when they don't. `spread` also resolves a lone function source inside its own tracking scopes and accepts an array of sources — `spread(node, [a, b], skipChildren)` — the union of their keys with later sources winning, only the winning source read, function sources called inline with no merge and no memo. Both compilers' universal output uses it: a lone spread passes straight through (reactive included, no more `mergeProps(() => …)`), and several sources compile to the array instead of a `mergeProps()` call. + ## 2.0.0-rc.8 ### Patch Changes diff --git a/packages/compiler/npm/darwin-arm64/package.json b/packages/compiler/npm/darwin-arm64/package.json index d427695d2..1c554263a 100644 --- a/packages/compiler/npm/darwin-arm64/package.json +++ b/packages/compiler/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@solidjs/compiler-darwin-arm64", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "cpu": [ "arm64" ], diff --git a/packages/compiler/npm/darwin-x64/package.json b/packages/compiler/npm/darwin-x64/package.json index 8e046f74f..7841eeb18 100644 --- a/packages/compiler/npm/darwin-x64/package.json +++ b/packages/compiler/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@solidjs/compiler-darwin-x64", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "cpu": [ "x64" ], diff --git a/packages/compiler/npm/linux-arm64-gnu/package.json b/packages/compiler/npm/linux-arm64-gnu/package.json index 2b5207267..7a473938d 100644 --- a/packages/compiler/npm/linux-arm64-gnu/package.json +++ b/packages/compiler/npm/linux-arm64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@solidjs/compiler-linux-arm64-gnu", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "cpu": [ "arm64" ], diff --git a/packages/compiler/npm/linux-x64-gnu/package.json b/packages/compiler/npm/linux-x64-gnu/package.json index af8dd9847..d0affc884 100644 --- a/packages/compiler/npm/linux-x64-gnu/package.json +++ b/packages/compiler/npm/linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@solidjs/compiler-linux-x64-gnu", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "cpu": [ "x64" ], diff --git a/packages/compiler/npm/wasm32-wasi/package.json b/packages/compiler/npm/wasm32-wasi/package.json index 2749a8050..d34b29b99 100644 --- a/packages/compiler/npm/wasm32-wasi/package.json +++ b/packages/compiler/npm/wasm32-wasi/package.json @@ -1,6 +1,6 @@ { "name": "@solidjs/compiler-wasm32-wasi", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "main": "compiler.wasi.cjs", "files": [ "compiler.wasm32-wasi.wasm", diff --git a/packages/compiler/npm/win32-x64-msvc/package.json b/packages/compiler/npm/win32-x64-msvc/package.json index 270f4c33e..d38212f4a 100644 --- a/packages/compiler/npm/win32-x64-msvc/package.json +++ b/packages/compiler/npm/win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@solidjs/compiler-win32-x64-msvc", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "cpu": [ "x64" ], diff --git a/packages/compiler/package.json b/packages/compiler/package.json index 6ffbd670d..f8a234a17 100644 --- a/packages/compiler/package.json +++ b/packages/compiler/package.json @@ -1,7 +1,7 @@ { "name": "@solidjs/compiler", "description": "Solid's native Oxc JSX compiler", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "author": "Ryan Carniato", "license": "MIT", "repository": { @@ -62,11 +62,11 @@ "emnapi": "^1.11.3" }, "optionalDependencies": { - "@solidjs/compiler-darwin-x64": "2.0.0-rc.8", - "@solidjs/compiler-darwin-arm64": "2.0.0-rc.8", - "@solidjs/compiler-linux-x64-gnu": "2.0.0-rc.8", - "@solidjs/compiler-linux-arm64-gnu": "2.0.0-rc.8", - "@solidjs/compiler-win32-x64-msvc": "2.0.0-rc.8", - "@solidjs/compiler-wasm32-wasi": "2.0.0-rc.8" + "@solidjs/compiler-darwin-x64": "2.0.0-rc.9", + "@solidjs/compiler-darwin-arm64": "2.0.0-rc.9", + "@solidjs/compiler-linux-x64-gnu": "2.0.0-rc.9", + "@solidjs/compiler-linux-arm64-gnu": "2.0.0-rc.9", + "@solidjs/compiler-win32-x64-msvc": "2.0.0-rc.9", + "@solidjs/compiler-wasm32-wasi": "2.0.0-rc.9" } } diff --git a/packages/diagnostics/CHANGELOG.md b/packages/diagnostics/CHANGELOG.md index 65de3e371..5320228f3 100644 --- a/packages/diagnostics/CHANGELOG.md +++ b/packages/diagnostics/CHANGELOG.md @@ -1,5 +1,26 @@ # @solidjs/diagnostics +## 2.0.0-rc.9 + +### Patch Changes + +- Updated dependencies [50323b4] +- Updated dependencies [d7cb456] +- Updated dependencies [a0d6dd2] +- Updated dependencies [c3ae310] +- Updated dependencies [6095955] +- Updated dependencies [e80f241] +- Updated dependencies [14ded24] +- Updated dependencies [25c5064] +- Updated dependencies [1ce0f85] +- Updated dependencies [9da7f0a] +- Updated dependencies [76230f9] +- Updated dependencies [632e45c] +- Updated dependencies [ca05917] +- Updated dependencies [7623ce1] +- Updated dependencies [af94f67] + - @solidjs/signals@2.0.0-rc.9 + ## 2.0.0-rc.8 ### Patch Changes diff --git a/packages/diagnostics/package.json b/packages/diagnostics/package.json index 5050b9b0d..1485f8035 100644 --- a/packages/diagnostics/package.json +++ b/packages/diagnostics/package.json @@ -1,6 +1,6 @@ { "name": "@solidjs/diagnostics", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "description": "Agent-consumable diagnostics harness for Solid: capture the dev-mode diagnostic and attribution channels as structured artifacts, with assertion helpers for tests and agent loops.", "author": "Ryan Carniato", "license": "MIT", @@ -52,7 +52,7 @@ "test:watch": "vitest watch tests" }, "dependencies": { - "@solidjs/signals": "^2.0.0-rc.8" + "@solidjs/signals": "^2.0.0-rc.9" }, "peerDependencies": { "vitest": ">=2.0.0" diff --git a/packages/element/CHANGELOG.md b/packages/element/CHANGELOG.md index 5a3bda285..437b23136 100644 --- a/packages/element/CHANGELOG.md +++ b/packages/element/CHANGELOG.md @@ -1,5 +1,28 @@ # solid-element +## 2.0.0-rc.9 + +### Patch Changes + +- Updated dependencies [17b0bda] +- Updated dependencies [1af28a1] +- Updated dependencies [c452850] +- Updated dependencies [5b31076] +- Updated dependencies [084e621] +- Updated dependencies [da6ed76] +- Updated dependencies [5f688a6] +- Updated dependencies [c66130d] +- Updated dependencies [36db287] +- Updated dependencies [7623ce1] +- Updated dependencies [af94f67] +- Updated dependencies [042b540] +- Updated dependencies [7f6332a] +- Updated dependencies [5426ffb] +- Updated dependencies [63560a1] +- Updated dependencies [40977c9] + - @solidjs/web@2.0.0-rc.9 + - solid-js@2.0.0-rc.9 + ## 2.0.0-rc.8 ### Patch Changes diff --git a/packages/element/package.json b/packages/element/package.json index f0f953103..b0efb16e2 100644 --- a/packages/element/package.json +++ b/packages/element/package.json @@ -3,7 +3,7 @@ "description": "Webcomponents wrapper for Solid", "author": "Ryan Carniato", "license": "MIT", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "homepage": "https://github.com/solidjs/solid/blob/main/packages/element#readme", "repository": { "type": "git", @@ -30,8 +30,8 @@ "component-register": "^0.8.7" }, "peerDependencies": { - "solid-js": "^2.0.0-rc.8", - "@solidjs/web": "^2.0.0-rc.8" + "solid-js": "^2.0.0-rc.9", + "@solidjs/web": "^2.0.0-rc.9" }, "devDependencies": { "solid-js": "workspace:*", diff --git a/packages/h/CHANGELOG.md b/packages/h/CHANGELOG.md index ee3f70689..e96160ec9 100644 --- a/packages/h/CHANGELOG.md +++ b/packages/h/CHANGELOG.md @@ -1,5 +1,31 @@ # @solidjs/h +## 2.0.0-rc.9 + +### Patch Changes + +- c452850: `dynamic()` / `Dynamic` with a tag-name source honor an `xmlns` prop when creating the element (#3386) + + The compiler resolves a tag's namespace from its parent at build time; the `dynamic()` runtime path creates the element before it has a parent, so a tag that exists in both HTML and SVG (`a`, `script`, `style`, `title`) was always created as an HTML element — `` with `Link = dynamic(() => "a")` produced an HTML anchor inside the SVG tree. The instance can now say which one it means with the same attribute compiled JSX uses for the same purpose: ``. Like `is`, `xmlns` is read once, untracked, at creation (the DOM can't re-namespace a node) and then applied as an ordinary attribute, so a client-rendered element carries the same attribute the server serializes. Without `xmlns` the namespace is still inferred from the tag name. Hydration is unaffected: it claims the parser-namespaced node. + + Types: `xmlns` is now accepted on the four tags that exist in both HTML and SVG (`a`, `script`, `style`, `title`) in addition to the SVG/MathML attribute sets that already had it — those are the only tags where the attribute changes what gets created, and the compiler has honored `` on them all along. Unambiguous HTML tags (`div`, `span`, …) still reject it. `dynamic()`'s tag-name components inherit it through their intrinsic attribute types. Also syncs `@solidjs/h`'s generated JSX types. + +- Updated dependencies [17b0bda] +- Updated dependencies [1af28a1] +- Updated dependencies [c452850] +- Updated dependencies [5b31076] +- Updated dependencies [084e621] +- Updated dependencies [da6ed76] +- Updated dependencies [5f688a6] +- Updated dependencies [c66130d] +- Updated dependencies [36db287] +- Updated dependencies [7623ce1] +- Updated dependencies [af94f67] +- Updated dependencies [042b540] +- Updated dependencies [7f6332a] +- Updated dependencies [40977c9] + - @solidjs/web@2.0.0-rc.9 + ## 2.0.0-rc.8 ### Patch Changes diff --git a/packages/h/package.json b/packages/h/package.json index 458c86edd..0771aca02 100644 --- a/packages/h/package.json +++ b/packages/h/package.json @@ -1,7 +1,7 @@ { "name": "@solidjs/h", "description": "Hyperscript / h() factory for Solid — write components without compiled JSX.", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "author": "Ryan Carniato", "license": "MIT", "homepage": "https://solidjs.com", @@ -58,7 +58,7 @@ "test": "vitest run" }, "peerDependencies": { - "@solidjs/web": "^2.0.0-rc.8" + "@solidjs/web": "^2.0.0-rc.9" }, "devDependencies": { "@solidjs/web": "workspace:*", diff --git a/packages/html/CHANGELOG.md b/packages/html/CHANGELOG.md index 60d698416..c5610d2f7 100644 --- a/packages/html/CHANGELOG.md +++ b/packages/html/CHANGELOG.md @@ -1,5 +1,25 @@ # @solidjs/html +## 2.0.0-rc.9 + +### Patch Changes + +- Updated dependencies [17b0bda] +- Updated dependencies [1af28a1] +- Updated dependencies [c452850] +- Updated dependencies [5b31076] +- Updated dependencies [084e621] +- Updated dependencies [da6ed76] +- Updated dependencies [5f688a6] +- Updated dependencies [c66130d] +- Updated dependencies [36db287] +- Updated dependencies [7623ce1] +- Updated dependencies [af94f67] +- Updated dependencies [042b540] +- Updated dependencies [7f6332a] +- Updated dependencies [40977c9] + - @solidjs/web@2.0.0-rc.9 + ## 2.0.0-rc.8 ### Patch Changes diff --git a/packages/html/package.json b/packages/html/package.json index 1e2e5f253..74d5d8f51 100644 --- a/packages/html/package.json +++ b/packages/html/package.json @@ -1,7 +1,7 @@ { "name": "@solidjs/html", "description": "Tagged-template-literal templating for Solid — write components with no build step.", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "author": "Ryan Carniato", "license": "MIT", "homepage": "https://solidjs.com", @@ -42,7 +42,7 @@ "test": "vitest run" }, "peerDependencies": { - "@solidjs/web": "^2.0.0-rc.8" + "@solidjs/web": "^2.0.0-rc.9" }, "devDependencies": { "@solidjs/web": "workspace:*", diff --git a/packages/signals/CHANGELOG.md b/packages/signals/CHANGELOG.md index 133ca6c67..6160e613f 100644 --- a/packages/signals/CHANGELOG.md +++ b/packages/signals/CHANGELOG.md @@ -1,5 +1,56 @@ # @solidjs/signals +## 2.0.0-rc.9 + +### Patch Changes + +- 50323b4: Keep a mainline-computed effect value out of a parked transaction. When an effect stamped by a held transaction recomputed on an unrelated write and no longer read the held source, the forced re-run inside that transaction re-claimed ownership of the value it had just published. A finalize-time re-entry (a `Loading` boundary's `on` reset flipping its fallback state) then parked the effect with the transaction, leaving a `show() ? details() : "hidden"` reader stale until the unrelated async settled (#3412). +- d7cb456: Fix a second write arriving while an async chain is still in flight (#3373, #3374, #3375, #3376). + - A flight's landing now retires only the node's own pending entry. When an input was re-asked mid-flight (`a` restarted while `b`'s first flight was up), `b` stays pending on `a`; the stale landing no longer let the transaction commit the newer signal beside the older derived value (`2 / 1`, #3373) or blip `isPending` to `false` (#3376). A fresh flight drops pending entries its inputs propagated earlier — the run read them, so a masked input (an active override, A17) does not hold it. + - A transaction now tests whether a source's own flight is still up by its self entry rather than `_error.source`, which a later-pending input overwrites; the held write no longer commits ahead of its answer once the load is re-asked under an `on`-scoped boundary (#3375). + - A collecting `Loading` boundary records every source the notifying effect is pending on, not only the one the notification carries — an `on` reset no longer reveals content when the boundary's one collected source settles while the effect is still pending on a flight it already carried (#3375). + - A render effect served a pending node's committed value (the A15 reveal carve-out) joins the transaction's reporters for that node, so a keyed remount that disposes the original reader no longer lets a same-value rewrite commit the held write while the derivation is in flight (`Count: 1` beside `Details: 0`, #3374). + - A `Loading` boundary's `on` reset ends the hold on writes that only its readers observed: a reader registered while the boundary showed content stops blocking once the boundary flips to its fallback, and the parked transaction is woken and re-judged in the same drain. A reader outside the boundary that also observes the flight still holds it (#3375). + +- a0d6dd2: Conditional JSX across a held branch change stays coherent with its inputs (#3438). + + An effect's dependencies are the committed frame's until its run applies — the effect twin of the memo rule from #3410. A pass that direct-committed its value but whose run was stashed with a hold (the same flush pended an async memo) used to trim the dependencies its previous run still displayed, so a later mainline write to one of them never reached the effect: `{show() ? count() : "hidden"}` held on `show → false` showed `Count: 1` beside `Panel: 0` while `Show` still read `true`. The trim now waits for the run to apply, so the write re-derives the effect against the committed inputs (`Panel: 1` beside `Count: 1`), and the hold's landing reveals `hidden` with `Show: false`. + +- c3ae310: Conditional memos across a held branch change stay coherent with their inputs (#3408, #3410). + - A tracked computation served a live transaction's staged value now enters that transaction, so its result is held with it (#3408). A memo whose branch flipped mainline and started reading a held signal previously published the staged value beside the signal's committed one (`Panel: 1` next to `Count: 0`). The read entry is the twin of the existing write-side (`setSignal`) and stamped-recompute entries. + - A memo's dependencies are the committed frame's until the frame is replaced (#3410): a pass that stages its value leaves the previous pass's dependency tail linked, and the commit trims it. A write to a dependency the committed value still derives from reaches the memo and joins its hold — as an unconditional read would — instead of revealing the write beside a stale committed derivation (`Count: 1` next to `Selected: 0` while `Fixed: false`). + +- 6095955: Two ways a held write stayed staged past the point it should have revealed: + - A transaction whose only reporter is disposed by ambient work (a `` unmounting the reader of a pending memo) was never re-judged — the flush only evaluates the active transaction, and nothing re-entered a parked one. The writes held with that reader (a signal set while it was pending) stayed staged forever. Disposing a pending reader parked in a transaction now wakes it; the flush re-enters a woken transaction on an otherwise idle pass, prunes the dead reporter and commits (#3372). + - An effect that reads `latest()` (or otherwise adopts an optimistic lane through its deps) direct-commits on a lane pass, but a hold it had staged on an earlier, lane-free pass of the same transaction was left in place and the transaction's commit published that older frame over the fresh value — `Pair: 0 / 0` for good. A lane recompute now drops the hold it supersedes, override or not (#3377). + +- e80f241: A node recomputed under a held transaction no longer tears down the committed frame's children immediately. Status propagation stamps a parked dependent with the transaction without recomputing it, so its owned children (nested render effects, memos, `onCleanup` registrations) still belong to what is on screen; when the pending source landed, the recompute disposed them on the spot and their cleanups ran mid-hold, before the transaction's atomic reveal (#3404). Those children are now deferred as zombies until the node commits, matching the plain-flush path. Children built by a recompute that never committed (a staged value, a pending window, a run under the transaction) are still disposed immediately on the next re-run — no frame ever showed them. +- 14ded24: `merge()` no longer flattens through a plain-object merge result. That form is a real object callers may copy (`Reflect.ownKeys` descriptor copies, `{...props}`) or mutate afterwards (`@solidjs/html` assigns props and a `children` getter after spreading), and a later `merge` tunnelled back to the original sources through the `$SOURCES` symbol — resurrecting removed keys and dropping added or overwritten ones (#3384). The plain result now records no sources and is read like any other object; only merge _proxies_, whose writes are no-ops, are still flattened. A side effect: `merge(defaults, props)` where `props` is itself a plain merge result that covers every default now returns `props` directly instead of always allocating. +- 25c5064: Optimistic frames release when nothing authoritative is left to wait on, and a shared render effect no longer entangles unrelated updates (#3426, #3427, #3407). + - The last async reader of an optimistic value unmounting mid-action releases the frame (#3426): the lane's hold check prunes dead reporters itself (`sourceObserved`, shared with the settle verdict), instead of waiting for a flight nobody observes to land. + - The action body ending starts the correction (#3427): with the bodies over and no authoritative work in flight — no override node's own source, no held plain load the action asked for — each override's truth supersedes it now and the graph re-derives from it as the transaction's held work, settling when that lands. Before, the settle waited for the obsolete lane-derived flight, flashed the obsolete optimistic frame, then reverted and re-asked. A co-written flag stays through a plain load; optimistic store edits keep the settle-then-revert order. + - A render effect's pass belongs to whatever dirtied it (#3407): a sync `action` write to a signal that shared a hole with a held async (`{b()}:{detailsA()}`) merged into the async's transaction and waited (`0:0 → 2:1`) while the same plain write passed through. `recompute` re-enters a stamped node's transaction for memos only; the landing of a flight enters every transaction waiting on it (`enterWaiting`), which is where the effect re-entry's one legitimate job — completing the reveals that discovered the flight — now lives. Two independent flights read in one hole land at their own times. + +- 1ce0f85: Optimistic settle verdicts (#3409, #3411). + - `isPending(() => [a(), b()])` over two async siblings of an optimistic value reports pending as soon as either read is (#3409). `assignOrMergeLane` now follows a merged lane to its root and runs the parent/child check on it; the old "merged lane is stale, take the source lane" shortcut moved the combined probe's effect onto the held parent lane, where its verdict waited on the async it reports. + - An unowned `onSettled` callback (event handler, action body) reads a settled world (#3411). The settle only enqueues the reverted subscribers for the next pass, so a callback fired in the commit pass saw the optimistic source reverted beside a sync memo of it still holding the optimistic value. The fire now waits for the heap to drain. + +- 9da7f0a: `isPending(details)` reports the load of an optimistic value when `details` derives it through an async memo (#3379). `notifyStatus` now assigns the node's optimistic lane before poking its companions, so a companion lane created by the poke is parented to the node's lane: the indicator effect flushes on the companion's child lane immediately instead of merging it into the held lane and waiting on the async it reports. +- 76230f9: Report `isPending()` true for a synchronous memo held by a downstream async memo. The memo's staged recompute only refreshed its verdict companion inside an active transition, but a plain flush can become a hold after that recompute (an async memo pends and the batch is adopted into a transaction), so the memo read not-pending while the signal it derived from read pending (#3413). +- 632e45c: Give the latest() shadow companion the `ownedWrite` flag its isPending companion already carries (#3378). A companion sync is internal plumbing that can run from inside a computation — a transition-held memo recompute pulled mid-tick by a reader creating or refreshing its latest() shadow — and the dev owned-scope write guard halted the app on the shadow write. Toggling a JSX branch that reads `latest(memo)` off while an action is pending and restoring it as the action resumes threw REACTIVE_WRITE_IN_OWNED_SCOPE. +- ca05917: `OBSERVE.exclude` now covers writes: a root write to an excluded subject (the observer's own store or signal) no longer counts toward the interaction that made it, and an interaction whose writes all went to excluded subjects with none of the app's work run — a click on a devtools panel's own button — is not recorded. Store nodes carry the owner their store was created under, so an excluded panel's store is an excluded subject like its signals. +- 7623ce1: Server diagnostics on `OBSERVE.diagnostics`; `OBSERVE.server` owned by `solid-js`'s server entry + + The server runtime now reports on the same structured channel as the client. **Findings** — facts about a render, present in observe and dev builds — `SSR_RENDER_ERROR_CONTAINED` (a render error a boundary routed; `data.handling` is `fallback`, `client`, or `failed` — the structured face of what `renderToStream`'s `onError` receives, on the process-wide channel), `SSR_SUBTREE_ABANDONED` (a failed fragment's pending descendants discarded), `SSR_STREAM_ABANDONED` (consumer cancelled or sink failed mid-render), `LATE_HEADER_WRITE` (recorded beside the existing dev throw / prod log), `SERVER_FN_ERROR_SANITIZED` (the original error the production wire replaced), and `FRAME_MARKER_CORRUPTED` from the frames client. **Checks** — dev-only guidance — convert every server `console.warn` to a code: `SERVER_WRITE`, `REVEAL_IN_RENDER_TO_STRING`, `LAZY_ASSET_UNMAPPED`, `PRELOAD_DESCRIPTOR_INVALID`, `HEAD_TAG_INVALID`, `BEHAVIOR_CLAIM_DROPPED`, and `UNRECOGNIZED_INSERT_VALUE` (now one code and a `render` kind on both platforms); `ASYNC_OUTSIDE_LOADING_BOUNDARY` on the server records with `data.side: "server"` before it throws. Server components are labelled for `ownerPath` (`createComponent` runs the body under a transparent `` owner in observe/dev — no hydration id consumed), so `in ` reads the same on both sides, and the server entry installs the same repair-guide console footer as the client. Prod artifacts carry none of it; `DiagnosticKind` gains `ssr`, `head`, `render`. + + `OBSERVE.server`'s objects (the invocation listener set, the trace-provider slot) are now created by `solid-js`'s server entry, once per process under `Symbol.for("solid-js/observe/server")` on `globalThis`, rather than by `@solidjs/web`'s module init: an observer's `init()` that imports only `solid-js` can subscribe and `provide` before the web runtime has loaded, and a host that bundles the runtime into its server build and instruments through a `--import`ed module finds one listener set and one provider across both copies. The core keeps `server: {}`; the client pays nothing. + +- af94f67: Server observe surface: `OBSERVE.server` and the invocation channel + + `OBSERVE` gains a `server` slot — an augmentable `ServerObserve` interface declared empty in `@solidjs/signals` (re-exported by `solid-js`), typed and emitted into by `@solidjs/web`'s server runtime, so server-side observability consumers subscribe on the one `OBSERVE` object they already know from the client. The first channel is `OBSERVE.server.invocations`: `subscribe("invocation", (event, live) => …)` delivers one `{ id, direct, at, durationMs, outcome, deferred? }` record per server-function execution — HTTP dispatch and direct SSR calls alike — when it settles, with the request event, `request`, `args`, and the result or the error as thrown beside it. Observers, not policy: any number of listeners, none able to alter the call; `wrapInvocation` remains the single policy hook. + + `@solidjs/web` now publishes observe-tier server artifacts (`dist/server.observe.js`, `server-functions/dist/server.observe.js`, `frames/dist/server.observe.js`) under the `observe` export condition, alongside the existing dev/prod pairs. The surface and every emit site fold out of the prod artifacts. + ## 2.0.0-rc.8 ### Patch Changes diff --git a/packages/signals/package.json b/packages/signals/package.json index 410c17506..029db5ee5 100644 --- a/packages/signals/package.json +++ b/packages/signals/package.json @@ -1,6 +1,6 @@ { "name": "@solidjs/signals", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "description": "Solid's reactive primitives: signals, memos, effects, stores, and async-aware computations.", "author": "Ryan Carniato", "license": "MIT", diff --git a/packages/solid/CHANGELOG.md b/packages/solid/CHANGELOG.md index 76eb3b3ba..06fc833d5 100644 --- a/packages/solid/CHANGELOG.md +++ b/packages/solid/CHANGELOG.md @@ -1,5 +1,43 @@ # solid-js +## 2.0.0-rc.9 + +### Patch Changes + +- 7623ce1: Server diagnostics on `OBSERVE.diagnostics`; `OBSERVE.server` owned by `solid-js`'s server entry + + The server runtime now reports on the same structured channel as the client. **Findings** — facts about a render, present in observe and dev builds — `SSR_RENDER_ERROR_CONTAINED` (a render error a boundary routed; `data.handling` is `fallback`, `client`, or `failed` — the structured face of what `renderToStream`'s `onError` receives, on the process-wide channel), `SSR_SUBTREE_ABANDONED` (a failed fragment's pending descendants discarded), `SSR_STREAM_ABANDONED` (consumer cancelled or sink failed mid-render), `LATE_HEADER_WRITE` (recorded beside the existing dev throw / prod log), `SERVER_FN_ERROR_SANITIZED` (the original error the production wire replaced), and `FRAME_MARKER_CORRUPTED` from the frames client. **Checks** — dev-only guidance — convert every server `console.warn` to a code: `SERVER_WRITE`, `REVEAL_IN_RENDER_TO_STRING`, `LAZY_ASSET_UNMAPPED`, `PRELOAD_DESCRIPTOR_INVALID`, `HEAD_TAG_INVALID`, `BEHAVIOR_CLAIM_DROPPED`, and `UNRECOGNIZED_INSERT_VALUE` (now one code and a `render` kind on both platforms); `ASYNC_OUTSIDE_LOADING_BOUNDARY` on the server records with `data.side: "server"` before it throws. Server components are labelled for `ownerPath` (`createComponent` runs the body under a transparent `` owner in observe/dev — no hydration id consumed), so `in ` reads the same on both sides, and the server entry installs the same repair-guide console footer as the client. Prod artifacts carry none of it; `DiagnosticKind` gains `ssr`, `head`, `render`. + + `OBSERVE.server`'s objects (the invocation listener set, the trace-provider slot) are now created by `solid-js`'s server entry, once per process under `Symbol.for("solid-js/observe/server")` on `globalThis`, rather than by `@solidjs/web`'s module init: an observer's `init()` that imports only `solid-js` can subscribe and `provide` before the web runtime has loaded, and a host that bundles the runtime into its server build and instruments through a `--import`ed module finds one listener set and one provider across both copies. The core keeps `server: {}`; the client pays nothing. + +- af94f67: Server observe surface: `OBSERVE.server` and the invocation channel + + `OBSERVE` gains a `server` slot — an augmentable `ServerObserve` interface declared empty in `@solidjs/signals` (re-exported by `solid-js`), typed and emitted into by `@solidjs/web`'s server runtime, so server-side observability consumers subscribe on the one `OBSERVE` object they already know from the client. The first channel is `OBSERVE.server.invocations`: `subscribe("invocation", (event, live) => …)` delivers one `{ id, direct, at, durationMs, outcome, deferred? }` record per server-function execution — HTTP dispatch and direct SSR calls alike — when it settles, with the request event, `request`, `args`, and the result or the error as thrown beside it. Observers, not policy: any number of listeners, none able to alter the call; `wrapInvocation` remains the single policy hook. + + `@solidjs/web` now publishes observe-tier server artifacts (`dist/server.observe.js`, `server-functions/dist/server.observe.js`, `frames/dist/server.observe.js`) under the `observe` export condition, alongside the existing dev/prod pairs. The surface and every emit site fold out of the prod artifacts. + +- 5426ffb: Fix a server-rendered `` fallback hydrating dead (#3414). When the boundary's children threw synchronously on the server and the fallback was a zero-arg thunk (`fallback={() => }`), the thunk was handed back unresolved and unwrapped by the enclosing boundary — the client does that inside the boundary's flatten computed, the server did it inline under the boundary owner — so the fallback's hydration keys disagreed, its root element failed to claim the server node, and its event handlers and effects never attached. The server `Errored` and `Loading` boundaries now resolve their children's result in a virtual id scope mirroring the client's second computed; the error record stays at the boundary id. +- 63560a1: `componentNames` now applies to SSR output. Under the option both compilers keep the `createComponent` call they otherwise inline to `Comp(props)` and pass the source tag name — `createComponent(Comp, props, "Comp")` — so the server runtime's observe/dev `createComponent` labels the owner and a server finding's `ownerPath` reads `` like the client's. Without the option (prod builds) SSR output is unchanged. `@solidjs/vite-plugin` already passes the option for its dev and observe postures, so app server builds pick this up with no config change. + + Fixes `ssrScope` under transparent owners: the virtual hole scope swapped the current owner's id counter, but content inside a hole resolves ids by walking past transparent owners, so with one in between (the server-component scope owner; now the labelled component owner) the hole's content took ids from the enclosing counter and disagreed with the client. The scope now swaps the nearest id-bearing owner. + +- Updated dependencies [50323b4] +- Updated dependencies [d7cb456] +- Updated dependencies [a0d6dd2] +- Updated dependencies [c3ae310] +- Updated dependencies [6095955] +- Updated dependencies [e80f241] +- Updated dependencies [14ded24] +- Updated dependencies [25c5064] +- Updated dependencies [1ce0f85] +- Updated dependencies [9da7f0a] +- Updated dependencies [76230f9] +- Updated dependencies [632e45c] +- Updated dependencies [ca05917] +- Updated dependencies [7623ce1] +- Updated dependencies [af94f67] + - @solidjs/signals@2.0.0-rc.9 + ## 2.0.0-rc.8 ### Patch Changes diff --git a/packages/solid/package.json b/packages/solid/package.json index dfbde2a2d..eec09b08f 100644 --- a/packages/solid/package.json +++ b/packages/solid/package.json @@ -1,7 +1,7 @@ { "name": "solid-js", "description": "Reactive JavaScript library for building user interfaces. Compiles JSX to real DOM with fine-grained signal-based updates — no virtual DOM.", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "author": "Ryan Carniato", "license": "MIT", "homepage": "https://solidjs.com", @@ -123,7 +123,7 @@ "performance" ], "dependencies": { - "@solidjs/signals": "^2.0.0-rc.8", + "@solidjs/signals": "^2.0.0-rc.9", "csstype": "^3.1.0", "seroval": "~1.6.7", "seroval-plugins": "~1.6.7" diff --git a/packages/test-integration/CHANGELOG.md b/packages/test-integration/CHANGELOG.md index a8605ba3c..b0d608bf7 100644 --- a/packages/test-integration/CHANGELOG.md +++ b/packages/test-integration/CHANGELOG.md @@ -1,5 +1,48 @@ # test-integration +## 2.0.0-rc.9 + +### Patch Changes + +- Updated dependencies [8d6de07] +- Updated dependencies [17b0bda] +- Updated dependencies [1af28a1] +- Updated dependencies [c452850] +- Updated dependencies [50323b4] +- Updated dependencies [d7cb456] +- Updated dependencies [a0d6dd2] +- Updated dependencies [c3ae310] +- Updated dependencies [6095955] +- Updated dependencies [e80f241] +- Updated dependencies [14ded24] +- Updated dependencies [25c5064] +- Updated dependencies [1ce0f85] +- Updated dependencies [9da7f0a] +- Updated dependencies [5b31076] +- Updated dependencies [084e621] +- Updated dependencies [76230f9] +- Updated dependencies [632e45c] +- Updated dependencies [ca05917] +- Updated dependencies [da6ed76] +- Updated dependencies [5f688a6] +- Updated dependencies [c66130d] +- Updated dependencies [36db287] +- Updated dependencies [7623ce1] +- Updated dependencies [af94f67] +- Updated dependencies [042b540] +- Updated dependencies [7f6332a] +- Updated dependencies [5426ffb] +- Updated dependencies [63560a1] +- Updated dependencies [40977c9] +- Updated dependencies [1643d2a] + - @solidjs/babel-plugin@2.0.0-rc.9 + - @solidjs/web@2.0.0-rc.9 + - @solidjs/h@2.0.0-rc.9 + - @solidjs/signals@2.0.0-rc.9 + - solid-js@2.0.0-rc.9 + - @solidjs/universal@2.0.0-rc.9 + - @solidjs/html@2.0.0-rc.9 + ## 2.0.0-rc.8 ### Patch Changes diff --git a/packages/test-integration/package.json b/packages/test-integration/package.json index 6b07ae503..323b41a93 100644 --- a/packages/test-integration/package.json +++ b/packages/test-integration/package.json @@ -21,5 +21,5 @@ "gitly": "^2.2.1", "shelljs": "^0.8.5" }, - "version": "2.0.0-rc.8" + "version": "2.0.0-rc.9" } diff --git a/packages/universal/CHANGELOG.md b/packages/universal/CHANGELOG.md index d4c8d3f86..4da91d791 100644 --- a/packages/universal/CHANGELOG.md +++ b/packages/universal/CHANGELOG.md @@ -1,5 +1,16 @@ # @solidjs/universal +## 2.0.0-rc.9 + +### Patch Changes + +- 1643d2a: The universal renderer's `spread()` follows the `@solidjs/web` contract (#3388): `ref` folds into the props effect and is re-applied only when its identity changes (refs run with no owner, so nothing they create is disposed by the fold); children keep their own owned `insert` — that effect owns the child subtree — but a plain object whose `children` is a data property inserts the value with no effect at all. Three reactive nodes become two when children flow through the spread, one when they don't. `spread` also resolves a lone function source inside its own tracking scopes and accepts an array of sources — `spread(node, [a, b], skipChildren)` — the union of their keys with later sources winning, only the winning source read, function sources called inline with no merge and no memo. Both compilers' universal output uses it: a lone spread passes straight through (reactive included, no more `mergeProps(() => …)`), and several sources compile to the array instead of a `mergeProps()` call. +- Updated dependencies [7623ce1] +- Updated dependencies [af94f67] +- Updated dependencies [5426ffb] +- Updated dependencies [63560a1] + - solid-js@2.0.0-rc.9 + ## 2.0.0-rc.8 ### Patch Changes diff --git a/packages/universal/package.json b/packages/universal/package.json index 025361629..baf3b2df3 100644 --- a/packages/universal/package.json +++ b/packages/universal/package.json @@ -1,7 +1,7 @@ { "name": "@solidjs/universal", "description": "Solid's universal runtime for creating custom renderers", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "author": "Ryan Carniato", "license": "MIT", "homepage": "https://solidjs.com", @@ -51,7 +51,7 @@ "test": "vitest run" }, "peerDependencies": { - "solid-js": "^2.0.0-rc.8" + "solid-js": "^2.0.0-rc.9" }, "devDependencies": { "solid-js": "workspace:*" diff --git a/packages/web/CHANGELOG.md b/packages/web/CHANGELOG.md index 43f91cff8..425949366 100644 --- a/packages/web/CHANGELOG.md +++ b/packages/web/CHANGELOG.md @@ -1,5 +1,65 @@ # @solidjs/web +## 2.0.0-rc.9 + +### Patch Changes + +- 17b0bda: Deprecate `` in favor of `dynamic()` + + `` is the same primitive as `dynamic()` with a worse shape: the tag travels in the props bag, so every instance merges `component` in at the call site, `omit`s it back out inside, and builds a fresh `dynamic()` factory (with its memo) because a JSX wrapper has nowhere to hoist one. Polymorphic-component libraries end up omitting `as`, handing the tag to ``, which merges it back in under `component` to omit it again. `dynamic()` has none of that for one extra line: + + ```tsx + // before + ; + + // after — hoist per component instance, or per module for a constant tag + const Field = dynamic(() => (multiline() ? RichTextEditor : "input")); + ; + ``` + + `Dynamic` and `DynamicProps` are marked `@deprecated` (editors strike them through; no runtime warning). They remain available in 2.0 — the RCs are past public API removals — but new code should use `dynamic()`. The migration guide and control-flow RFC are updated accordingly. + +- 1af28a1: Call `runHydrationEvents()` after `dynamic()` spreads props onto a string tag, so events the hydration script queued for a `` element are replayed instead of being dropped until `_$HY.done`. +- c452850: `dynamic()` / `Dynamic` with a tag-name source honor an `xmlns` prop when creating the element (#3386) + + The compiler resolves a tag's namespace from its parent at build time; the `dynamic()` runtime path creates the element before it has a parent, so a tag that exists in both HTML and SVG (`a`, `script`, `style`, `title`) was always created as an HTML element — `` with `Link = dynamic(() => "a")` produced an HTML anchor inside the SVG tree. The instance can now say which one it means with the same attribute compiled JSX uses for the same purpose: ``. Like `is`, `xmlns` is read once, untracked, at creation (the DOM can't re-namespace a node) and then applied as an ordinary attribute, so a client-rendered element carries the same attribute the server serializes. Without `xmlns` the namespace is still inferred from the tag name. Hydration is unaffected: it claims the parser-namespaced node. + + Types: `xmlns` is now accepted on the four tags that exist in both HTML and SVG (`a`, `script`, `style`, `title`) in addition to the SVG/MathML attribute sets that already had it — those are the only tags where the attribute changes what gets created, and the compiler has honored `` on them all along. Unambiguous HTML tags (`div`, `span`, …) still reject it. `dynamic()`'s tag-name components inherit it through their intrinsic attribute types. Also syncs `@solidjs/h`'s generated JSX types. + +- 5b31076: `ssrElement` no longer emits `style=""` / `class=""` for nullish values; they are omitted like every other attribute, matching the client. Skipped props also leave no stray whitespace in the opening tag (#3382). +- 084e621: SSR emits the `` text separator only between items that resolve to text. Adjacent memos and components that yield elements — every `Dynamic`, `Show`, or wrapper-library instance in a list — no longer carry a separator and a comment node each. Text that becomes adjacent through a nested array or a dropped nullish item is now separated, so it hydrates into distinct text nodes (#3383). +- da6ed76: SSR: fold the text-separator entry wrappers back into `tryResolveString` and `resolveSSRNode`. #3394 split each walker into an entry function that reset the separator state and a recursive body; the bodies are too large for V8 to inline, so every template hole paid an extra call. The recursion now passes a `nested` flag instead — one function each, same output — recovering the ~2% SSR throughput that split cost on element-heavy pages (up to 7% where holes are dense). +- 5f688a6: GET-encoded server function calls no longer send the `X-Server-Function-Instance` header (#3406). A `` is reused only by a fetch that matches it exactly, headers included, so the per-call header made browsers fetch every preloaded read twice. A read's identity is now its url alone; the instance id keeps riding the POST transport, where it still names the call to the handler's hooks as `context.instance` (null for reads, as for no-JS callers). `prepareRequest` validation adapts: on a GET call the method the transport set stands sentinel for a returned init that dropped the original. +- c66130d: Remove the `X-Server-Function-Instance` header from the server-function wire protocol. Since #3094 it decided nothing: the answer shape is the address (`/data/` for the scripted transport, bare for plain HTTP), no-JS gating is the address plus a form post, and #3416 had already dropped it from GET reads so preloads could match. What remained was a per-call id the handler copied into `context.instance` for `transformResult` / `transformFlightResult`, which nothing consumed; cross-wire correlation is the trace context's job (`traceparent`, #3402). Breaking, nominally: `context.instance` is gone from the hook contexts, and `INSTANCE_HEADER` is no longer exported from `@solidjs/web/server-functions/{client,server}`. A legacy header on an incoming request is ignored, as it already was. The `prepareRequest` validation (#3174) now uses the transport's method as its sentinel on every call shape, so a hook returning a fresh `{ headers }` instead of spreading is still refused before dispatch. Client-side `observeServerFunctionCalls` events keep their local `instance` id for pairing a request with its response. +- 36db287: `renderToString` now disposes its reactive root synchronously before returning instead of via `setTimeout`, so a synchronous loop of renders no longer retains every graph until the next macrotask (#3385). The request event's response head is committed right before that dispose — the same head-freeze point an awaited `renderToStream` already uses — so `httpStatus`/`httpHeader` declarations still reach `createSSRResponse`. A render that throws leaves the head uncommitted and retracts its declarations as before. +- 7623ce1: Server diagnostics on `OBSERVE.diagnostics`; `OBSERVE.server` owned by `solid-js`'s server entry + + The server runtime now reports on the same structured channel as the client. **Findings** — facts about a render, present in observe and dev builds — `SSR_RENDER_ERROR_CONTAINED` (a render error a boundary routed; `data.handling` is `fallback`, `client`, or `failed` — the structured face of what `renderToStream`'s `onError` receives, on the process-wide channel), `SSR_SUBTREE_ABANDONED` (a failed fragment's pending descendants discarded), `SSR_STREAM_ABANDONED` (consumer cancelled or sink failed mid-render), `LATE_HEADER_WRITE` (recorded beside the existing dev throw / prod log), `SERVER_FN_ERROR_SANITIZED` (the original error the production wire replaced), and `FRAME_MARKER_CORRUPTED` from the frames client. **Checks** — dev-only guidance — convert every server `console.warn` to a code: `SERVER_WRITE`, `REVEAL_IN_RENDER_TO_STRING`, `LAZY_ASSET_UNMAPPED`, `PRELOAD_DESCRIPTOR_INVALID`, `HEAD_TAG_INVALID`, `BEHAVIOR_CLAIM_DROPPED`, and `UNRECOGNIZED_INSERT_VALUE` (now one code and a `render` kind on both platforms); `ASYNC_OUTSIDE_LOADING_BOUNDARY` on the server records with `data.side: "server"` before it throws. Server components are labelled for `ownerPath` (`createComponent` runs the body under a transparent `` owner in observe/dev — no hydration id consumed), so `in ` reads the same on both sides, and the server entry installs the same repair-guide console footer as the client. Prod artifacts carry none of it; `DiagnosticKind` gains `ssr`, `head`, `render`. + + `OBSERVE.server`'s objects (the invocation listener set, the trace-provider slot) are now created by `solid-js`'s server entry, once per process under `Symbol.for("solid-js/observe/server")` on `globalThis`, rather than by `@solidjs/web`'s module init: an observer's `init()` that imports only `solid-js` can subscribe and `provide` before the web runtime has loaded, and a host that bundles the runtime into its server build and instruments through a `--import`ed module finds one listener set and one provider across both copies. The core keeps `server: {}`; the client pays nothing. + +- af94f67: Server observe surface: `OBSERVE.server` and the invocation channel + + `OBSERVE` gains a `server` slot — an augmentable `ServerObserve` interface declared empty in `@solidjs/signals` (re-exported by `solid-js`), typed and emitted into by `@solidjs/web`'s server runtime, so server-side observability consumers subscribe on the one `OBSERVE` object they already know from the client. The first channel is `OBSERVE.server.invocations`: `subscribe("invocation", (event, live) => …)` delivers one `{ id, direct, at, durationMs, outcome, deferred? }` record per server-function execution — HTTP dispatch and direct SSR calls alike — when it settles, with the request event, `request`, `args`, and the result or the error as thrown beside it. Observers, not policy: any number of listeners, none able to alter the call; `wrapInvocation` remains the single policy hook. + + `@solidjs/web` now publishes observe-tier server artifacts (`dist/server.observe.js`, `server-functions/dist/server.observe.js`, `frames/dist/server.observe.js`) under the `observe` export condition, alongside the existing dev/prod pairs. The surface and every emit site fold out of the prod artifacts. + +- 042b540: Trace context: `getTraceContext()`, W3C `traceparent` on the exchange, and the `OBSERVE.server.trace` provider slot + + The server runtime now reads the W3C Trace Context half of the HTTP exchange once per request — continuing an incoming `traceparent` (with `tracestate`/`baggage` beside it) or originating a trace when none came in — and exposes it through `getTraceContext()` from `@solidjs/web`: `{ traceId, spanId, parentId?, sampled?, state?, baggage?, entries }`, one object per request (direct SSR-time server-function calls included), the render's own for a render outside a request scope, `undefined` outside both and on the client. Application code forwards a trace downstream with `entries.traceparent`. This is core HTTP behavior in every build tier. + + The trace is also handed down to the browser: `entries` are emitted as `Server-Timing` metrics (`traceparent;desc="00-…"`) when the response head commits — `createSSRResponse`, `commitEventResponse` (now also for an event without a response stub, such as the server-function handler's default event), and `commitResponseStub` (which accepts the owning `event` in its options) — and as `` tags in the HTML shell head, delivered wherever the head content goes (`` splice, `onHead`). A `Server-Timing` name the application already wrote is respected; `Server-Timing` now folds entry by entry when a stub and a response/`responseInit` both carry one. The browser is told only when something is recording the trace — the incoming `traceparent` was sampled, or a provider answered — never for a trace the runtime originated alone or an unsampled upstream one (what load balancers and meshes stamp on every request), so an app with no APM sees zero wire change. + + In observe/dev builds, `OBSERVE.server.trace.provide(provider)` installs a single global provider whose answer merges over the derivation (fields replace, `entries` merge by name) — how an APM's server SDK contributes its active span and vendor entries (`sentry-trace`/`baggage`) once, with no per-request entry point into the host. + +- 7f6332a: `spread()` creates fewer reactive nodes per element (#3388): `ref` folds into the attribute effect and is re-applied only when its identity changes (refs run with no owner, so nothing they create is disposed by the fold); children keep their own owned `insert` — that effect owns the child subtree, and merging it would rebuild the children on every attribute change — but a plain object whose `children` is a data property inserts the value with no effect at all. Three nodes become two when children flow through the spread, one when they don't. `spread` also accepts an array of sources with an optional `skip` predicate — `spread(el, [a, b], skipChildren, skip)` — the union of own keys with later sources winning, only the winning source read, function sources called inline with no memo (and so no hydration id), matching the server `ssrElement` array form. +- 40977c9: `ssrElement` accepts an array of prop sources and an optional `skip` predicate: `ssrElement(tag, [a, b, c], children, needsId, skip)`. The array form serializes straight from the sources with the exact output of `ssrElement(tag, merge(a, b, c), ...)` — later sources win per key, attributes land in merged order, only the winning source's getter is read (once), and `skip(key)` drops a key from every source without reading it — so libraries and compilers spreading several sources no longer have to build an intermediate merged object that is walked once and discarded. The array (or a thunk yielding it) is resolved after the hydration key is taken; a function source is a plain thunk called once that creates no memo and consumes no hydration ids. Nullish sources are empty. The single-object form is unchanged. +- Updated dependencies [7623ce1] +- Updated dependencies [af94f67] +- Updated dependencies [5426ffb] +- Updated dependencies [63560a1] + - solid-js@2.0.0-rc.9 + ## 2.0.0-rc.8 ### Patch Changes diff --git a/packages/web/package.json b/packages/web/package.json index f37649378..16a8db17c 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@solidjs/web", "description": "Solid's web runtime: client rendering, hydration, SSR, and DOM-specific control flow (Portal, Dynamic).", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "author": "Ryan Carniato", "license": "MIT", "homepage": "https://solidjs.com", @@ -279,7 +279,7 @@ "seroval-plugins": "~1.6.7" }, "peerDependencies": { - "solid-js": "^2.0.0-rc.8" + "solid-js": "^2.0.0-rc.9" }, "devDependencies": { "@codspeed/vitest-plugin": "^5.4.0",