Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fair-geese-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: never use html optimization for mustache tags in hydration mode
8 changes: 3 additions & 5 deletions packages/svelte/src/compiler/compile/Component.js
Original file line number Diff line number Diff line change
Expand Up @@ -1632,11 +1632,9 @@ export default class Component {
unsorted_reactive_declarations.forEach(add_declaration);
}
check_if_tags_content_dynamic() {
this.tags.forEach(
/** @param {any} tag */ (tag) => {
tag.check_if_content_dynamic();
}
);
this.tags.forEach((tag) => {
tag.check_if_content_dynamic();
});
}

/**
Expand Down
9 changes: 9 additions & 0 deletions packages/svelte/src/compiler/compile/nodes/Element.js
Original file line number Diff line number Diff line change
Expand Up @@ -1464,6 +1464,15 @@ export default class Element extends Node {
this.children.length > 0
);
}
get can_optimise_hydration() {
// In contrast to normal html string optimization, we also bail in case of mustache tags even
// if they seem to contain static content. This is because we cannot know whether that static
// value is different between client and server builds, e.g. {browser ? 'hi' : 'bye'} which
// becomes {'hi'} and {'bye'} respectively.
const is_static_text_content =
this.is_static_content && this.children.every((node) => node.type === 'Text');
return this.can_optimise_to_html_string && (this.can_use_innerhtml || is_static_text_content);
}
hash() {
return `svelte-${hash(this.component.source.slice(this.start, this.end))}`;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,13 +458,13 @@ export default class ElementWrapper extends Wrapper {
block.add_variable(node);
const render_statement = this.get_render_statement(block);
block.chunks.create.push(b`${node} = ${render_statement};`);
const { can_use_textcontent, can_optimise_to_html_string } = this.node;
const { can_use_textcontent, can_optimise_to_html_string, can_optimise_hydration } = this.node;
if (hydratable) {
if (parent_nodes) {
block.chunks.claim.push(b`
${node} = ${this.get_claim_statement(block, parent_nodes, can_optimise_to_html_string)};
${node} = ${this.get_claim_statement(block, parent_nodes, can_optimise_hydration)};
`);
if (!can_optimise_to_html_string && !this.void && this.node.children.length > 0) {
if (!can_optimise_hydration && !this.void && this.node.children.length > 0) {
block.chunks.claim.push(b`
var ${nodes} = ${children};
`);
Expand Down Expand Up @@ -500,7 +500,7 @@ export default class ElementWrapper extends Wrapper {
}
// insert static children with textContent or innerHTML
// skip textcontent for <template>. append nodes to TemplateElement.content instead
if (can_optimise_to_html_string) {
if (can_optimise_to_html_string && (!hydratable || can_optimise_hydration)) {
if (this.fragment.nodes.length === 1 && this.fragment.nodes[0].node.type === 'Text') {
/** @type {import('estree').Node} */
let text = string_literal(
Expand Down Expand Up @@ -579,7 +579,7 @@ export default class ElementWrapper extends Wrapper {
this.add_classes(block);
this.add_styles(block);
this.add_manual_style_scoping(block);
if (nodes && hydratable && !this.void && !can_optimise_to_html_string) {
if (nodes && hydratable && !this.void && !can_optimise_hydration) {
block.chunks.claim.push(
b`${this.node.children.length > 0 ? nodes : children}.forEach(@detach);`
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export default function (node, renderer, options) {
}
});
if (options.hydratable) {
if (node.can_optimise_to_html_string && !options.has_added_svelte_hash) {
if (node.can_optimise_hydration && !options.has_added_svelte_hash) {
renderer.add_string(` data-svelte-h="${node.hash()}"`);
options = { ...options, has_added_svelte_hash: true };
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>Hello client!</h1>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1 data-svelte-h="svelte-1oz2hyi">Hello world!</h1>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default {
snapshot(target) {
return {
h1: target.querySelector('h1')
};
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>Hello {'client'}!</h1>