From 228c267a181112b9924c4077b9ba5bc8b7f84a98 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Fri, 16 Jun 2023 17:15:46 +0200 Subject: [PATCH 1/3] fix: never use html optimization for mustache tags in hydration mode --- .changeset/fair-geese-repeat.md | 5 +++++ packages/svelte/src/compiler/compile/Component.js | 8 +++----- packages/svelte/src/compiler/compile/nodes/Element.js | 9 +++++++++ .../compile/render_dom/wrappers/Element/index.js | 10 +++++----- .../compiler/compile/render_ssr/handlers/Element.js | 2 +- 5 files changed, 23 insertions(+), 11 deletions(-) create mode 100644 .changeset/fair-geese-repeat.md diff --git a/.changeset/fair-geese-repeat.md b/.changeset/fair-geese-repeat.md new file mode 100644 index 000000000000..f99f912e0d17 --- /dev/null +++ b/.changeset/fair-geese-repeat.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: never use html optimization for mustache tags in hydration mode diff --git a/packages/svelte/src/compiler/compile/Component.js b/packages/svelte/src/compiler/compile/Component.js index 894cb9b787b9..7a7a1ba17e74 100644 --- a/packages/svelte/src/compiler/compile/Component.js +++ b/packages/svelte/src/compiler/compile/Component.js @@ -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(); + }); } /** diff --git a/packages/svelte/src/compiler/compile/nodes/Element.js b/packages/svelte/src/compiler/compile/nodes/Element.js index 3f67615e06b3..3b18ce0e9416 100644 --- a/packages/svelte/src/compiler/compile/nodes/Element.js +++ b/packages/svelte/src/compiler/compile/nodes/Element.js @@ -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))}`; } diff --git a/packages/svelte/src/compiler/compile/render_dom/wrappers/Element/index.js b/packages/svelte/src/compiler/compile/render_dom/wrappers/Element/index.js index 687741d21afe..eca5f09fc5fe 100644 --- a/packages/svelte/src/compiler/compile/render_dom/wrappers/Element/index.js +++ b/packages/svelte/src/compiler/compile/render_dom/wrappers/Element/index.js @@ -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}; `); @@ -500,7 +500,7 @@ export default class ElementWrapper extends Wrapper { } // insert static children with textContent or innerHTML // skip textcontent for