Skip to content

Commit 9f062d0

Browse files
fix
1 parent 3999296 commit 9f062d0

9 files changed

Lines changed: 163 additions & 10 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,
@@ -412,3 +416,31 @@ Deno.test({
412416
sanitizeOps: false,
413417
sanitizeResources: false,
414418
});
419+
420+
Deno.test({
421+
name: "vite build - client side <Head>",
422+
fn: async () => {
423+
await launchProd(
424+
{ cwd: viteResult.tmp },
425+
async (address) => {
426+
await withBrowser(async (page) => {
427+
await page.goto(`${address}/tests/head_counter`, {
428+
waitUntil: "networkidle2",
429+
});
430+
431+
await page.locator(".ready").wait();
432+
await page.locator("button").click();
433+
await waitForText(page, ".result", "Count: 1");
434+
435+
await waitFor(async () => {
436+
const title = await page.evaluate(() => document.title);
437+
expect(title).toEqual("Count: 1");
438+
return true;
439+
});
440+
});
441+
},
442+
);
443+
},
444+
sanitizeOps: false,
445+
sanitizeResources: false,
446+
});

packages/plugin-vite/tests/dev_server_test.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import * as path from "@std/path";
22
import { expect } from "@std/expect";
3-
import { waitForText, withBrowser } from "../../fresh/tests/test_utils.tsx";
3+
import {
4+
waitFor,
5+
waitForText,
6+
withBrowser,
7+
} from "../../fresh/tests/test_utils.tsx";
48
import {
59
DEMO_DIR,
610
FIXTURE_DIR,
@@ -350,3 +354,50 @@ Deno.test({
350354
sanitizeOps: false,
351355
sanitizeResources: false,
352356
});
357+
358+
Deno.test({
359+
name: "vite dev - client side <Head>",
360+
fn: async () => {
361+
await launchDevServer(DEMO_DIR, async (address) => {
362+
await withBrowser(async (page) => {
363+
await page.goto(`${address}/tests/head_counter`, {
364+
waitUntil: "networkidle2",
365+
});
366+
367+
await page.locator(".ready").wait();
368+
await page.locator("button").click();
369+
await waitForText(page, ".result", "Count: 1");
370+
371+
await waitFor(async () => {
372+
const title = await page.evaluate(() => document.title);
373+
expect(title).toEqual("Count: 1");
374+
return true;
375+
});
376+
377+
await page.goto(`${address}/tests/head_meta`, {
378+
waitUntil: "networkidle2",
379+
});
380+
381+
await page.locator(".ready").wait();
382+
383+
// await new Promise((r) => setTimeout(r, 200000));
384+
await waitFor(async () => {
385+
const custom = await page
386+
.locator("meta[name='custom']")
387+
// deno-lint-ignore no-explicit-any
388+
.evaluate((el: any) => el.content);
389+
expect(custom).toEqual("ok");
390+
391+
const custom2 = await page
392+
.locator("meta[name='custom-new']")
393+
// deno-lint-ignore no-explicit-any
394+
.evaluate((el: any) => el.content);
395+
expect(custom2).toEqual("ok");
396+
return true;
397+
});
398+
});
399+
});
400+
},
401+
sanitizeOps: false,
402+
sanitizeResources: false,
403+
});

0 commit comments

Comments
 (0)