Skip to content

Commit 8ffc8fd

Browse files
author
Maximiliano Ruani
authored
[fix] Fix hydration duplicate svelte:head tag issue with @html expressions and nested components (#7745)
* Fix hydration duplicate `svelte:head` tag issue with `@html` and nested components #7444 #6463 * - Changed comment style to HEAD_${head_id}_START and HEAD_${head_id}_END - Improved claim logic - Changed tests accordingly
1 parent 7ac3854 commit 8ffc8fd

File tree

19 files changed

+110
-15
lines changed

19 files changed

+110
-15
lines changed

src/compiler/compile/render_dom/wrappers/Head.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export default class HeadWrapper extends Wrapper {
3636
let nodes;
3737
if (this.renderer.options.hydratable && this.fragment.nodes.length) {
3838
nodes = block.get_unique_name('head_nodes');
39-
block.chunks.claim.push(b`const ${nodes} = @query_selector_all('[data-svelte="${this.node.id}"]', @_document.head);`);
39+
block.chunks.claim.push(b`const ${nodes} = @head_selector('${this.node.id}', @_document.head);`);
4040
}
4141

4242
this.fragment.render(block, x`@_document.head` as unknown as Identifier, nodes);

src/compiler/compile/render_ssr/handlers/Element.ts

-4
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,6 @@ export default function (node: Element, renderer: Renderer, options: RenderOptio
157157
}
158158
});
159159

160-
if (options.hydratable && options.head_id) {
161-
renderer.add_string(` data-svelte="${options.head_id}"`);
162-
}
163-
164160
renderer.add_string('>');
165161

166162
if (node_contents !== undefined) {

src/compiler/compile/render_ssr/handlers/Head.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ export default function(node: Head, renderer: Renderer, options: RenderOptions)
1212
renderer.render(node.children, head_options);
1313
const result = renderer.pop();
1414

15-
renderer.add_expression(x`$$result.head += ${result}, ""`);
15+
renderer.add_expression(x`$$result.head += '<!-- HEAD_${node.id}_START -->' + ${result} + '<!-- HEAD_${node.id}_END -->', ""`);
1616
}

src/runtime/internal/dom.ts

+21
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,27 @@ export function query_selector_all(selector: string, parent: HTMLElement = docum
646646
return Array.from(parent.querySelectorAll(selector)) as ChildNodeArray;
647647
}
648648

649+
export function head_selector(nodeId: string, head: HTMLElement) {
650+
const result = [];
651+
let started = 0;
652+
653+
for (const node of head.childNodes) {
654+
if (node.nodeType === 8 /* comment node */) {
655+
const comment = node.textContent.trim();
656+
if (comment === `HEAD_${nodeId}_END`) {
657+
started -= 1;
658+
result.push(node);
659+
} else if (comment === `HEAD_${nodeId}_START`) {
660+
started += 1;
661+
result.push(node);
662+
}
663+
} else if (started > 0) {
664+
result.push(node);
665+
}
666+
}
667+
return result;
668+
}
669+
649670
export class HtmlTag {
650671
private is_svg = false;
651672
// parent for creating node
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{@html '<meta name="head_nested_html" content="head_nested_html">'}
2+
<meta name="head_nested" content="head_nested">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
<svelte:head>
3+
{@html '<meta name="nested_html" content="nested_html">'}
4+
<meta name="nested" content="nested">
5+
</svelte:head>

test/hydration/samples/head-html-and-component/_after.html

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!-- HEAD_svelte-17ibcve_START -->
2+
<!-- HTML_TAG_START --><meta name="main_html" content="main_html"><!-- HTML_TAG_END -->
3+
<meta name="main" content="main">
4+
<!-- HTML_TAG_START --><meta name="head_nested_html" content="head_nested_html"><!-- HTML_TAG_END -->
5+
<meta name="head_nested" content="head_nested">
6+
<!-- HEAD_svelte-17ibcve_END -->
7+
8+
<!-- HEAD_svelte-1gqzvnn_START -->
9+
<!-- HTML_TAG_START --><meta name="nested_html" content="nested_html"><!-- HTML_TAG_END -->
10+
<meta name="nested" content="nested">
11+
<!-- HEAD_svelte-1gqzvnn_END -->
12+

test/hydration/samples/head-html-and-component/_before.html

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!-- HEAD_svelte-17ibcve_START -->
2+
<!-- HTML_TAG_START --><meta name="main_html" content="main_html"><!-- HTML_TAG_END -->
3+
<meta name="main" content="main">
4+
<!-- HTML_TAG_START --><meta name="head_nested_html" content="head_nested_html"><!-- HTML_TAG_END -->
5+
<meta name="head_nested" content="head_nested">
6+
<!-- HEAD_svelte-17ibcve_END -->
7+
8+
<!-- HEAD_svelte-1gqzvnn_START -->
9+
<!-- HTML_TAG_START --><meta name="nested_html" content="nested_html"><!-- HTML_TAG_END -->
10+
<meta name="nested" content="nested">
11+
<!-- HEAD_svelte-1gqzvnn_END -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script>
2+
import HeadNested from './HeadNested.svelte';
3+
import Nested from './Nested.svelte';
4+
</script>
5+
6+
<svelte:head>
7+
{@html '<meta name="main_html" content="main_html">'}
8+
<meta name="main" content="main">
9+
<HeadNested />
10+
</svelte:head>
11+
12+
<Nested/>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<title>Some Title</title>
2-
<link href="/" rel="canonical">
3-
<meta content="some description" name="description">
4-
<meta content="some keywords" name="keywords">
2+
<!-- HEAD_svelte-1s8aodm_START -->
3+
<link rel="canonical" href="/">
4+
<meta name="description" content="some description">
5+
<meta name="keywords" content="some keywords">
6+
<!-- HEAD_svelte-1s8aodm_END -->
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<title>Some Title</title>
2-
<link rel="canonical" href="/" data-svelte="svelte-1s8aodm">
3-
<meta name="description" content="some description" data-svelte="svelte-1s8aodm">
4-
<meta name="keywords" content="some keywords" data-svelte="svelte-1s8aodm">
2+
<!-- HEAD_svelte-1s8aodm_START -->
3+
<link rel="canonical" href="/">
4+
<meta name="description" content="some description">
5+
<meta name="keywords" content="some keywords">
6+
<!-- HEAD_svelte-1s8aodm_END -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{@html '<meta name="head_nested_html" content="head_nested_html">'}
2+
<meta name="head_nested" content="head_nested">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
<svelte:head>
3+
{@html '<meta name="nested_html" content="nested_html">'}
4+
<meta name="nested" content="nested">
5+
</svelte:head>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!-- HEAD_svelte-17ibcve_START -->
2+
<!-- HTML_TAG_START --><meta name="main_html" content="main_html"><!-- HTML_TAG_END -->
3+
<meta name="main" content="main">
4+
<!-- HTML_TAG_START --><meta name="head_nested_html" content="head_nested_html"><!-- HTML_TAG_END -->
5+
<meta name="head_nested" content="head_nested">
6+
<!-- HEAD_svelte-17ibcve_END -->
7+
8+
<!-- HEAD_svelte-1gqzvnn_START -->
9+
<!-- HTML_TAG_START --><meta name="nested_html" content="nested_html"><!-- HTML_TAG_END -->
10+
<meta name="nested" content="nested">
11+
<!-- HEAD_svelte-1gqzvnn_END -->

test/server-side-rendering/samples/head-html-and-component/_expected.html

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script>
2+
import HeadNested from './HeadNested.svelte';
3+
import Nested from './Nested.svelte';
4+
</script>
5+
6+
<svelte:head>
7+
{@html '<meta name="main_html" content="main_html">'}
8+
<meta name="main" content="main">
9+
<HeadNested />
10+
</svelte:head>
11+
12+
<Nested/>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<title>Some Title</title>
2-
<link rel="canonical" href="/" data-svelte="svelte-1s8aodm">
3-
<meta name="description" content="some description" data-svelte="svelte-1s8aodm">
4-
<meta name="keywords" content="some keywords" data-svelte="svelte-1s8aodm">
2+
<!-- HEAD_svelte-1s8aodm_START -->
3+
<link rel="canonical" href="/">
4+
<meta name="description" content="some description">
5+
<meta name="keywords" content="some keywords">
6+
<!-- HEAD_svelte-1s8aodm_END -->

0 commit comments

Comments
 (0)