fix(compiler): preserve server-only component props during hydration
This commit is contained in:
1 parent
bfa72d5679
commit
26af30cfe6
4 files changed
+14
-4
No files matched your search
@@ -320,7 +320,7 @@
|
|||||||
},
|
},
|
||||||
"packages/compiler": {
|
"packages/compiler": {
|
||||||
"name": "@wrnexus/compiler",
|
"name": "@wrnexus/compiler",
|
||||||
"version": "0.8.24",
|
"version": "0.8.25",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/csr": "workspace:*",
|
"@wrnexus/csr": "workspace:*",
|
||||||
"@wrnexus/store": "workspace:*",
|
"@wrnexus/store": "workspace:*",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/compiler",
|
"name": "@wrnexus/compiler",
|
||||||
"version": "0.8.24",
|
"version": "0.8.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -3196,7 +3196,7 @@ function __wrnProp(v: unknown): string {
|
|||||||
function renderPageComponentAttr(
|
function renderPageComponentAttr(
|
||||||
attr: Attr,
|
attr: Attr,
|
||||||
dynamicExpressions: string[],
|
dynamicExpressions: string[],
|
||||||
_reactive: PageReactive | null,
|
reactive: PageReactive | null,
|
||||||
): string {
|
): string {
|
||||||
if (attr.event) {
|
if (attr.event) {
|
||||||
return ` ${componentEventAttribute(attr.name)}="${attrEscape(attr.value)}"`;
|
return ` ${componentEventAttribute(attr.name)}="${attrEscape(attr.value)}"`;
|
||||||
@@ -3215,6 +3215,13 @@ function renderPageComponentAttr(
|
|||||||
dynamicExpressions.push(`\${__wrnexusPropAttr(${expression})}`);
|
dynamicExpressions.push(`\${__wrnexusPropAttr(${expression})}`);
|
||||||
|
|
||||||
const marker = `\x00WRNEACH${dynamicExpressions.length - 1}\x00`;
|
const marker = `\x00WRNEACH${dynamicExpressions.length - 1}\x00`;
|
||||||
|
if (
|
||||||
|
reactive &&
|
||||||
|
exprRefsState(expression, reactive.runtimeStateNames) &&
|
||||||
|
!exprRefsState(expression, reactive.stateNames)
|
||||||
|
) {
|
||||||
|
return ` ${attr.name}="${marker}"`;
|
||||||
|
}
|
||||||
// The mount disappears during SSR. Preserve every dynamic component prop
|
// The mount disappears during SSR. Preserve every dynamic component prop
|
||||||
// as a parent-owned binding; server-only expressions simply fail closed in
|
// as a parent-owned binding; server-only expressions simply fail closed in
|
||||||
// the browser, while page state can continue driving the mounted child.
|
// the browser, while page state can continue driving the mounted child.
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ import { generate, parse } from "../src/index.ts";
|
|||||||
|
|
||||||
test("server-only loader data renders native input attributes without client state", async () => {
|
test("server-only loader data renders native input attributes without client state", async () => {
|
||||||
const code = generate(
|
const code = generate(
|
||||||
parse(`page Profile {
|
parse(`import UserSelect from "./UserSelect.wrn"
|
||||||
|
page Profile {
|
||||||
load server account { return {} }
|
load server account { return {} }
|
||||||
view {
|
view {
|
||||||
<h1>{account.name}</h1>
|
<h1>{account.name}</h1>
|
||||||
|
<UserSelect value="{account.name}" options="{account.items}" />
|
||||||
{#if account.readonly}<p>Read only</p>{:else}<p>Editable</p>{/if}
|
{#if account.readonly}<p>Read only</p>{:else}<p>Editable</p>{/if}
|
||||||
{#each account.items as item}<strong>{item}</strong>{/each}
|
{#each account.items as item}<strong>{item}</strong>{/each}
|
||||||
<input value="{account.name}" readonly="{account.readonly}" />
|
<input value="{account.name}" readonly="{account.readonly}" />
|
||||||
@@ -34,6 +36,7 @@ test("server-only loader data renders native input attributes without client sta
|
|||||||
expect(html).toContain('<option value="dark" selected>Dark</option>');
|
expect(html).toContain('<option value="dark" selected>Dark</option>');
|
||||||
expect(html).toContain('identity="{"name":"Alice"}"');
|
expect(html).toContain('identity="{"name":"Alice"}"');
|
||||||
expect(html).not.toContain("data-wrn-bind");
|
expect(html).not.toContain("data-wrn-bind");
|
||||||
|
expect(html).not.toContain("data-wrn-prop-bind");
|
||||||
expect(html).not.toContain("{account.");
|
expect(html).not.toContain("{account.");
|
||||||
expect(html).toContain("<h1>A "<User>"</h1>");
|
expect(html).toContain("<h1>A "<User>"</h1>");
|
||||||
expect(html).toContain("<p>Editable</p>");
|
expect(html).toContain("<p>Editable</p>");
|
||||||
|
|||||||
Reference in new issue
Block a user