diff --git a/packages/playground/src/App.svelte b/packages/playground/src/App.svelte
index b3c16eec67..156287852c 100644
--- a/packages/playground/src/App.svelte
+++ b/packages/playground/src/App.svelte
@@ -1,7 +1 @@
-
-
-
- Hello world!
-
\ No newline at end of file
+{@html false ? 'foo' : 'bar'}
diff --git a/packages/playground/start.js b/packages/playground/start.js
index af37a40e26..ace479ac9f 100644
--- a/packages/playground/start.js
+++ b/packages/playground/start.js
@@ -69,11 +69,12 @@ const watcher = watch([
async generateBundle(_, bundle) {
const result = bundle['entry-server.js'];
const mod = (0, eval)(result.code);
- const { html } = mod.render();
+ const { html, head } = mod.render();
writeFileSync(
'dist/index.html',
readFileSync('src/template.html', 'utf-8')
+ .replace('', head)
.replace('', html)
.replace('', svelte.VERSION)
);
diff --git a/packages/svelte/src/compiler/compile/render_dom/wrappers/RawMustacheTag.js b/packages/svelte/src/compiler/compile/render_dom/wrappers/RawMustacheTag.js
index cc382a9b0b..c381321dec 100644
--- a/packages/svelte/src/compiler/compile/render_dom/wrappers/RawMustacheTag.js
+++ b/packages/svelte/src/compiler/compile/render_dom/wrappers/RawMustacheTag.js
@@ -47,7 +47,7 @@ export default class RawMustacheTagWrapper extends Tag {
block.chunks.create.push(b`${html_tag} = new @HtmlTag(${is_svg ? 'true' : 'false'});`);
if (this.renderer.options.hydratable) {
block.chunks.claim.push(
- b`${html_tag} = @claim_html_tag(${_parent_nodes}, ${is_svg ? 'true' : 'false'});`
+ b`${html_tag} = @claim_html_tag(${_parent_nodes}, ${is_svg ? 'true' : 'false'}, ${init});`
);
}
block.chunks.hydrate.push(b`${html_tag}.a = ${update_anchor};`);
diff --git a/packages/svelte/src/compiler/compile/render_ssr/handlers/HtmlTag.js b/packages/svelte/src/compiler/compile/render_ssr/handlers/HtmlTag.js
index 1a210ec00d..094dc6d6bb 100644
--- a/packages/svelte/src/compiler/compile/render_ssr/handlers/HtmlTag.js
+++ b/packages/svelte/src/compiler/compile/render_ssr/handlers/HtmlTag.js
@@ -1,10 +1,19 @@
+import { x } from 'code-red';
+
/**
* @param {import('../../nodes/RawMustacheTag.js').default} node
* @param {import('../Renderer.js').default} renderer
* @param {import('../private.js').RenderOptions} options
*/
export default function (node, renderer, options) {
- if (options.hydratable) renderer.add_string('');
- renderer.add_expression(/** @type {import('estree').Expression} */ (node.expression.node));
- if (options.hydratable) renderer.add_string('');
+ if (!options.hydratable) {
+ renderer.add_expression(/** @type {import('estree').Expression} */ (node.expression.node));
+ } else {
+ renderer.add_expression(x`(() => {
+ const #html_string = ${node.expression.node} + '';
+ const #hash = /* @__PURE__ */ @hash(#html_string);
+
+ return \`\${#html_string}\`;
+ })()`);
+ }
}
diff --git a/packages/svelte/src/runtime/internal/dom.js b/packages/svelte/src/runtime/internal/dom.js
index 18a5d5d278..003a4578fd 100644
--- a/packages/svelte/src/runtime/internal/dom.js
+++ b/packages/svelte/src/runtime/internal/dom.js
@@ -1,5 +1,5 @@
import { ResizeObserverSingleton } from './ResizeObserverSingleton.js';
-import { contenteditable_truthy_values, has_prop } from './utils.js';
+import { contenteditable_truthy_values, has_prop, hash } from './utils.js';
// Track which nodes are claimed during hydration. Unclaimed nodes can then be removed from the DOM
// at the end of hydration without touching the remaining nodes.
let is_hydrating = false;
@@ -789,11 +789,13 @@ function get_comment_idx(nodes, text, start) {
* @param {boolean} is_svg
* @returns {HtmlTagHydration}
*/
-export function claim_html_tag(nodes, is_svg) {
+export function claim_html_tag(nodes, is_svg, content) {
// find html opening tag
- const start_index = get_comment_idx(nodes, 'HTML_TAG_START', 0);
- const end_index = get_comment_idx(nodes, 'HTML_TAG_END', start_index + 1);
- if (start_index === -1 || end_index === -1) {
+ const content_hash = hash(content + '');
+ const start_index = get_comment_idx(nodes, `HTML_${content_hash}_START`, 0);
+ const end_index = get_comment_idx(nodes, `HTML_${content_hash}_END`, start_index + 1);
+
+ if (start_index === -1 || end_index === -1) { // Content mismatch, recreate
return new HtmlTagHydration(is_svg);
}
diff --git a/packages/svelte/src/runtime/internal/style_manager.js b/packages/svelte/src/runtime/internal/style_manager.js
index a98984788f..c8c725599c 100644
--- a/packages/svelte/src/runtime/internal/style_manager.js
+++ b/packages/svelte/src/runtime/internal/style_manager.js
@@ -1,5 +1,6 @@
import { append_empty_stylesheet, detach, get_root_for_style } from './dom.js';
import { raf } from './environment.js';
+import { hash } from './utils.js';
// we need to store the information for multiple documents because a Svelte application could also contain iframes
// https://github.com/sveltejs/svelte/issues/3624
@@ -8,18 +9,6 @@ const managed_styles = new Map();
let active = 0;
-// https://github.com/darkskyapp/string-hash/blob/master/index.js
-/**
- * @param {string} str
- * @returns {number}
- */
-function hash(str) {
- let hash = 5381;
- let i = str.length;
- while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
- return hash >>> 0;
-}
-
/**
* @param {Document | ShadowRoot} doc
* @param {Element & ElementCSSInlineStyle} node
diff --git a/packages/svelte/src/runtime/internal/utils.js b/packages/svelte/src/runtime/internal/utils.js
index ec39c0d9e4..9c42d90377 100644
--- a/packages/svelte/src/runtime/internal/utils.js
+++ b/packages/svelte/src/runtime/internal/utils.js
@@ -289,3 +289,15 @@ export function split_css_unit(value) {
}
export const contenteditable_truthy_values = ['', true, 1, 'true', 'contenteditable'];
+
+// https://github.com/darkskyapp/string-hash/blob/master/index.js
+/**
+ * @param {string} str
+ * @returns {number}
+ */
+export function hash(str) {
+ let hash = 5381;
+ let i = str.length;
+ while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
+ return hash >>> 0;
+}
diff --git a/packages/svelte/test/hydration/samples/raw-repair/_before.html b/packages/svelte/test/hydration/samples/raw-repair/_before.html
index fe958bece5..8cf8b3e954 100644
--- a/packages/svelte/test/hydration/samples/raw-repair/_before.html
+++ b/packages/svelte/test/hydration/samples/raw-repair/_before.html
@@ -1,8 +1,8 @@
-
+
invalid
-
+
-
+
invalid
-
+
diff --git a/packages/svelte/test/hydration/samples/raw-svg/_before.html b/packages/svelte/test/hydration/samples/raw-svg/_before.html
index 2a1285938d..884540a056 100644
--- a/packages/svelte/test/hydration/samples/raw-svg/_before.html
+++ b/packages/svelte/test/hydration/samples/raw-svg/_before.html
@@ -1,5 +1,5 @@
diff --git a/packages/svelte/test/hydration/samples/raw/_before.html b/packages/svelte/test/hydration/samples/raw/_before.html
index de20b90f6c..8fec75a411 100644
--- a/packages/svelte/test/hydration/samples/raw/_before.html
+++ b/packages/svelte/test/hydration/samples/raw/_before.html
@@ -1,4 +1,4 @@
-
+
this is some html
and so is this
-
+