Skip to content

Commit 607b240

Browse files
fix
1 parent c3072be commit 607b240

9 files changed

Lines changed: 158 additions & 9 deletions

File tree

packages/fresh/src/runtime/client/preact_hooks_client.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ import { HeadContext } from "../head.ts";
1313
// deno-lint-ignore no-explicit-any
1414
const options: InternalPreactOptions = preactOptions as any;
1515

16-
const PATCHED = new WeakSet<VNode>();
17-
1816
function WrappedHead(
1917
// deno-lint-ignore no-explicit-any
2018
{ originalType, props, key }: { originalType: string; props: any; key: any },
@@ -40,7 +38,7 @@ function WrappedHead(
4038

4139
if (matched === null && props.id) {
4240
matched = document.head.querySelector(
43-
`#${props.name}`,
41+
`#${props.id}`,
4442
) as HTMLElement ??
4543
null;
4644
}
@@ -68,11 +66,9 @@ function WrappedHead(
6866

6967
if (enabled) {
7068
return null;
71-
} else {
72-
const inner = h(originalType, props);
73-
PATCHED.add(inner);
74-
return inner;
7569
}
70+
71+
return h(originalType, { ...props, _freshPatched: true });
7672
}
7773

7874
const oldVNodeHook = options.vnode;
@@ -86,7 +82,8 @@ options.vnode = (vnode) => {
8682
if (typeof value === "boolean") {
8783
vnode.props[CLIENT_NAV_ATTR] = String(value);
8884
}
89-
} else if (!PATCHED.has(vnode)) {
85+
// deno-lint-ignore no-explicit-any
86+
} else if (!(vnode.props as any)._freshPatched) {
9087
switch (originalType) {
9188
case "title":
9289
case "meta":
@@ -99,6 +96,9 @@ options.vnode = (vnode) => {
9996
// deno-lint-ignore no-explicit-any
10097
const v = vnode as VNode<any>;
10198
const props = vnode.props;
99+
// deno-lint-ignore no-explicit-any
100+
delete (props as any)._freshPatched;
101+
102102
const key = vnode.key;
103103
v.type = WrappedHead;
104104
v.props = {

packages/fresh/tests/partials_test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ Deno.test({
197197

198198
// See https://github.com/denoland/fresh/issues/2254
199199
Deno.test({
200+
only: true,
200201
name: "partials - should not be able to override __FRSH_STATE",
201202
fn: async () => {
202203
const app = testApp()
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { useEffect, useState } from "preact/hooks";
2+
import { Head } from "fresh/runtime";
3+
4+
export function HeadCounter() {
5+
const [ready, setReady] = useState(false);
6+
const [v, set] = useState(0);
7+
8+
useEffect(() => {
9+
setReady(true);
10+
}, []);
11+
12+
return (
13+
<div class={ready ? "ready" : "not-ready"}>
14+
<Head>
15+
<title>Count: {v}</title>
16+
</Head>
17+
<p class="result">Count: {v}</p>
18+
<button type="button" onClick={() => set((v) => v + 1)}>
19+
update
20+
</button>
21+
</div>
22+
);
23+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { useEffect, useState } from "preact/hooks";
2+
import { Head } from "fresh/runtime";
3+
4+
export function HeadMeta() {
5+
const [ready, setReady] = useState(false);
6+
7+
useEffect(() => {
8+
setReady(true);
9+
}, []);
10+
11+
return (
12+
<div class={ready ? "ready" : "not-ready"}>
13+
<Head>
14+
<meta name="custom" content="ok" />
15+
<meta name="custom-new" content="ok" />
16+
</Head>
17+
<h1>check meta</h1>
18+
</div>
19+
);
20+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { PageProps } from "fresh";
2+
3+
export default function App({ Component }: PageProps) {
4+
return (
5+
<html lang="en">
6+
<head>
7+
<meta charset="utf-8" />
8+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
9+
<meta name="custom" content="foo" />
10+
</head>
11+
<body>
12+
<Component />
13+
</body>
14+
</html>
15+
);
16+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { HeadCounter } from "../../islands/tests/HeadCounter.tsx";
2+
3+
export default function Page() {
4+
return <HeadCounter />;
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { HeadMeta } from "../../islands/tests/HeadMeta.tsx";
2+
3+
export default function Page() {
4+
return <HeadMeta />;
5+
}

packages/plugin-vite/tests/build_test.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { expect } from "@std/expect";
2-
import { waitForText, withBrowser } from "../../fresh/tests/test_utils.tsx";
2+
import {
3+
waitFor,
4+
waitForText,
5+
withBrowser,
6+
} from "../../fresh/tests/test_utils.tsx";
37
import {
48
buildVite,
59
DEMO_DIR,
@@ -431,3 +435,31 @@ Deno.test({
431435
sanitizeOps: false,
432436
sanitizeResources: false,
433437
});
438+
439+
Deno.test({
440+
name: "vite build - client side <Head>",
441+
fn: async () => {
442+
await launchProd(
443+
{ cwd: viteResult.tmp },
444+
async (address) => {
445+
await withBrowser(async (page) => {
446+
await page.goto(`${address}/tests/head_counter`, {
447+
waitUntil: "networkidle2",
448+
});
449+
450+
await page.locator(".ready").wait();
451+
await page.locator("button").click();
452+
await waitForText(page, ".result", "Count: 1");
453+
454+
await waitFor(async () => {
455+
const title = await page.evaluate(() => document.title);
456+
expect(title).toEqual("Count: 1");
457+
return true;
458+
});
459+
});
460+
},
461+
);
462+
},
463+
sanitizeOps: false,
464+
sanitizeResources: false,
465+
});

packages/plugin-vite/tests/dev_server_test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,3 +392,50 @@ Deno.test({
392392
sanitizeOps: false,
393393
sanitizeResources: false,
394394
});
395+
396+
Deno.test({
397+
name: "vite dev - client side <Head>",
398+
fn: async () => {
399+
await launchDevServer(DEMO_DIR, async (address) => {
400+
await withBrowser(async (page) => {
401+
await page.goto(`${address}/tests/head_counter`, {
402+
waitUntil: "networkidle2",
403+
});
404+
405+
await page.locator(".ready").wait();
406+
await page.locator("button").click();
407+
await waitForText(page, ".result", "Count: 1");
408+
409+
await waitFor(async () => {
410+
const title = await page.evaluate(() => document.title);
411+
expect(title).toEqual("Count: 1");
412+
return true;
413+
});
414+
415+
await page.goto(`${address}/tests/head_meta`, {
416+
waitUntil: "networkidle2",
417+
});
418+
419+
await page.locator(".ready").wait();
420+
421+
// await new Promise((r) => setTimeout(r, 200000));
422+
await waitFor(async () => {
423+
const custom = await page
424+
.locator("meta[name='custom']")
425+
// deno-lint-ignore no-explicit-any
426+
.evaluate((el: any) => el.content);
427+
expect(custom).toEqual("ok");
428+
429+
const custom2 = await page
430+
.locator("meta[name='custom-new']")
431+
// deno-lint-ignore no-explicit-any
432+
.evaluate((el: any) => el.content);
433+
expect(custom2).toEqual("ok");
434+
return true;
435+
});
436+
});
437+
});
438+
},
439+
sanitizeOps: false,
440+
sanitizeResources: false,
441+
});

0 commit comments

Comments
 (0)