From c75c42949b3364d74089f1912900a7901f4079b4 Mon Sep 17 00:00:00 2001
From: paoloricciuti <ricciutipaolo@gmail.com>
Date: Thu, 20 Mar 2025 14:45:32 +0100
Subject: [PATCH] chore: run test suite on both `functional` and `string`
 templating

---
 packages/svelte/package.json                  |   2 +-
 packages/svelte/src/internal/server/dev.js    |   2 +-
 packages/svelte/tests/helpers.js              |   9 +-
 packages/svelte/tests/hydration/test.ts       |  29 +-
 packages/svelte/tests/runtime-browser/test.ts |  44 ++-
 .../main.svelte                               |   5 +-
 .../main.svelte                               |   6 +-
 .../window-binding-scroll-store/_config.js    |   3 +-
 .../svelte/tests/runtime-legacy/shared.ts     |  53 +++-
 packages/svelte/tests/runtime-legacy/test.ts  |   3 +-
 .../custom-element-attributes/main.svelte     |  26 +-
 packages/svelte/tests/runtime-runes/test.ts   |   3 +-
 .../client-functional/index.svelte.js         |  52 ++++
 .../client-functional/index.svelte.js         |  45 +++
 .../client-functional/index.svelte.js         |   7 +
 .../client-functional/index.svelte.js         |  27 ++
 .../client-functional/index.svelte.js         |  16 +
 .../client-functional/main.svelte.js          |  53 ++++
 .../client-functional/index.svelte.js         |  19 ++
 .../client-functional/index.svelte.js         |   4 +
 .../client-functional/index.svelte.js         |  27 ++
 .../client-functional/index.svelte.js         |  21 ++
 .../client-functional/index.svelte.js         |  32 ++
 .../_expected/client-functional/export.js     |   1 +
 .../client-functional/index.svelte.js         |   8 +
 .../client-functional/module.svelte.js        |   5 +
 .../client-functional/index.svelte.js         |  54 ++++
 .../client-functional/index.svelte.js         |  17 ++
 .../client-functional/index.svelte.js         |  34 +++
 .../client-functional/index.svelte.js         | 283 ++++++++++++++++++
 .../client-functional/index.svelte.js         |  50 ++++
 .../client-functional/index.svelte.js         |  11 +
 .../client-functional/index.svelte.js         |  34 +++
 packages/svelte/tests/snapshot/test.ts        |  14 +-
 packages/svelte/tests/suite.ts                |  42 ++-
 pnpm-lock.yaml                                |   2 +-
 36 files changed, 975 insertions(+), 68 deletions(-)
 create mode 100644 packages/svelte/tests/snapshot/samples/await-block-scope/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/bind-this/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/destructured-assignments/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client-functional/main.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/each-string-template/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/export-state/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/hello-world/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/hmr/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client-functional/export.js
 create mode 100644 packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client-functional/module.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/props-identifier/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/purity/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/svelte-element/_expected/client-functional/index.svelte.js
 create mode 100644 packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client-functional/index.svelte.js

diff --git a/packages/svelte/package.json b/packages/svelte/package.json
index 6f10b2a9ea..9e9f5c8a8d 100644
--- a/packages/svelte/package.json
+++ b/packages/svelte/package.json
@@ -149,9 +149,9 @@
   "dependencies": {
     "@ampproject/remapping": "^2.3.0",
     "@jridgewell/sourcemap-codec": "^1.5.0",
+    "@sveltejs/acorn-typescript": "^1.0.5",
     "@types/estree": "^1.0.5",
     "acorn": "^8.12.1",
-    "@sveltejs/acorn-typescript": "^1.0.5",
     "aria-query": "^5.3.1",
     "axobject-query": "^4.1.0",
     "clsx": "^2.1.1",
diff --git a/packages/svelte/src/internal/server/dev.js b/packages/svelte/src/internal/server/dev.js
index ecf4e67429..6ff5426818 100644
--- a/packages/svelte/src/internal/server/dev.js
+++ b/packages/svelte/src/internal/server/dev.js
@@ -22,7 +22,7 @@ import { current_component } from './context.js';
 let parent = null;
 
 /** @type {Set<string>} */
-let seen;
+export let seen;
 
 /**
  * @param {Element} element
diff --git a/packages/svelte/tests/helpers.js b/packages/svelte/tests/helpers.js
index 87bcb473e7..164d855e89 100644
--- a/packages/svelte/tests/helpers.js
+++ b/packages/svelte/tests/helpers.js
@@ -58,15 +58,17 @@ export function create_deferred() {
  * @param {Partial<CompileOptions>} compileOptions
  * @param {boolean} [output_map]
  * @param {any} [preprocessor]
+ * @param {import('./suite').TemplatingMode} [templating_mode]
  */
 export async function compile_directory(
 	cwd,
 	generate,
 	compileOptions = {},
 	output_map = false,
-	preprocessor
+	preprocessor,
+	templating_mode
 ) {
-	const output_dir = `${cwd}/_output/${generate}`;
+	const output_dir = `${cwd}/_output/${generate}${templating_mode === 'functional' ? `-${templating_mode}` : ''}`;
 
 	fs.rmSync(output_dir, { recursive: true, force: true });
 
@@ -77,7 +79,8 @@ export async function compile_directory(
 		let opts = {
 			filename: path.join(cwd, file),
 			...compileOptions,
-			generate
+			generate,
+			preventTemplateCloning: templating_mode === 'functional'
 		};
 
 		if (file.endsWith('.js')) {
diff --git a/packages/svelte/tests/hydration/test.ts b/packages/svelte/tests/hydration/test.ts
index 266ac07bff..0fc5187733 100644
--- a/packages/svelte/tests/hydration/test.ts
+++ b/packages/svelte/tests/hydration/test.ts
@@ -41,10 +41,24 @@ function read(path: string): string | void {
 	return fs.existsSync(path) ? fs.readFileSync(path, 'utf-8') : undefined;
 }
 
-const { test, run } = suite<HydrationTest>(async (config, cwd) => {
+const { test, run } = suite<HydrationTest>(async (config, cwd, templating_mode) => {
 	if (!config.load_compiled) {
-		await compile_directory(cwd, 'client', { accessors: true, ...config.compileOptions });
-		await compile_directory(cwd, 'server', config.compileOptions);
+		await compile_directory(
+			cwd,
+			'client',
+			{ accessors: true, ...config.compileOptions },
+			undefined,
+			undefined,
+			templating_mode
+		);
+		await compile_directory(
+			cwd,
+			'server',
+			config.compileOptions,
+			undefined,
+			undefined,
+			templating_mode
+		);
 	}
 
 	const target = window.document.body;
@@ -102,7 +116,11 @@ const { test, run } = suite<HydrationTest>(async (config, cwd) => {
 		};
 
 		const component = createClassComponent({
-			component: (await import(`${cwd}/_output/client/main.svelte.js`)).default,
+			component: (
+				await import(
+					`${cwd}/_output/client${templating_mode === 'functional' ? '-functional' : ''}/main.svelte.js`
+				)
+			).default,
 			target,
 			hydrate: true,
 			props: config.props,
@@ -169,4 +187,5 @@ const { test, run } = suite<HydrationTest>(async (config, cwd) => {
 });
 export { test, assert_ok };
 
-await run(__dirname);
+await run(__dirname, 'string');
+await run(__dirname, 'functional');
diff --git a/packages/svelte/tests/runtime-browser/test.ts b/packages/svelte/tests/runtime-browser/test.ts
index 582a10edf7..0f7b259715 100644
--- a/packages/svelte/tests/runtime-browser/test.ts
+++ b/packages/svelte/tests/runtime-browser/test.ts
@@ -4,7 +4,7 @@ import * as fs from 'node:fs';
 import * as path from 'node:path';
 import { compile } from 'svelte/compiler';
 import { afterAll, assert, beforeAll, describe } from 'vitest';
-import { suite, suite_with_variants } from '../suite';
+import { suite, suite_with_variants, type TemplatingMode } from '../suite';
 import { write } from '../helpers';
 import type { Warning } from '#compiler';
 
@@ -35,27 +35,41 @@ const { run: run_browser_tests } = suite_with_variants<
 		return false;
 	},
 	() => {},
-	async (config, test_dir, variant) => {
-		await run_test(test_dir, config, variant === 'hydrate');
+	async (config, test_dir, variant, _, templating_mode) => {
+		await run_test(test_dir, config, variant === 'hydrate', templating_mode);
 	}
 );
 
 describe.concurrent(
 	'runtime-browser',
-	() => run_browser_tests(__dirname),
+	() => run_browser_tests(__dirname, 'string'),
+	// Browser tests are brittle and slow on CI
+	{ timeout: 20000, retry: process.env.CI ? 1 : 0 }
+);
+
+describe.concurrent(
+	'runtime-browser-functional',
+	() => run_browser_tests(__dirname, 'functional'),
 	// Browser tests are brittle and slow on CI
 	{ timeout: 20000, retry: process.env.CI ? 1 : 0 }
 );
 
 const { run: run_ce_tests } = suite<ReturnType<typeof import('./assert').test>>(
-	async (config, test_dir) => {
-		await run_test(test_dir, config, false);
+	async (config, test_dir, templating_mode) => {
+		await run_test(test_dir, config, false, templating_mode);
 	}
 );
 
 describe.concurrent(
 	'custom-elements',
-	() => run_ce_tests(__dirname, 'custom-elements-samples'),
+	() => run_ce_tests(__dirname, 'string', 'custom-elements-samples'),
+	// Browser tests are brittle and slow on CI
+	{ timeout: 20000, retry: process.env.CI ? 1 : 0 }
+);
+
+describe.concurrent(
+	'custom-elements',
+	() => run_ce_tests(__dirname, 'functional', 'custom-elements-samples'),
 	// Browser tests are brittle and slow on CI
 	{ timeout: 20000, retry: process.env.CI ? 1 : 0 }
 );
@@ -63,7 +77,8 @@ describe.concurrent(
 async function run_test(
 	test_dir: string,
 	config: ReturnType<typeof import('./assert').test>,
-	hydrate: boolean
+	hydrate: boolean,
+	templating_mode: TemplatingMode
 ) {
 	const warnings: any[] = [];
 
@@ -90,10 +105,14 @@ async function run_test(
 							...config.compileOptions,
 							immutable: config.immutable,
 							customElement: test_dir.includes('custom-elements-samples'),
-							accessors: 'accessors' in config ? config.accessors : true
+							accessors: 'accessors' in config ? config.accessors : true,
+							preventTemplateCloning: templating_mode === 'functional'
 						});
 
-						write(`${test_dir}/_output/client/${path.basename(args.path)}.js`, compiled.js.code);
+						write(
+							`${test_dir}/_output/client${templating_mode === 'functional' ? '-functional' : ''}/${path.basename(args.path)}.js`,
+							compiled.js.code
+						);
 
 						compiled.warnings.forEach((warning) => {
 							if (warning.code === 'options_deprecated_accessors') return;
@@ -103,7 +122,7 @@ async function run_test(
 						if (compiled.css !== null) {
 							compiled.js.code += `document.head.innerHTML += \`<style>${compiled.css.code}</style>\``;
 							write(
-								`${test_dir}/_output/client/${path.basename(args.path)}.css`,
+								`${test_dir}/_output/${templating_mode === 'functional' ? '-functional' : ''}/${path.basename(args.path)}.css`,
 								compiled.css.code
 							);
 						}
@@ -151,7 +170,8 @@ async function run_test(
 								...config.compileOptions,
 								immutable: config.immutable,
 								customElement: test_dir.includes('custom-elements-samples'),
-								accessors: 'accessors' in config ? config.accessors : true
+								accessors: 'accessors' in config ? config.accessors : true,
+								preventTemplateCloning: templating_mode === 'functional'
 							});
 
 							return {
diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-casing-custom-element/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-casing-custom-element/main.svelte
index 6433d0dc76..81c855676a 100644
--- a/packages/svelte/tests/runtime-legacy/samples/attribute-casing-custom-element/main.svelte
+++ b/packages/svelte/tests/runtime-legacy/samples/attribute-casing-custom-element/main.svelte
@@ -18,8 +18,9 @@
 			this.innerHTML = 'Hello ' + this._obj.text + '!';
 		}
 	}
-
-	window.customElements.define('my-custom-element', MyCustomElement);
+	if(!window.customElements.get('my-custom-element')) {
+		window.customElements.define('my-custom-element', MyCustomElement);
+	}
 </script>
 
 <my-custom-element camelCase={{ text: 'World' }} />
diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-custom-element-inheritance/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-custom-element-inheritance/main.svelte
index 1324bcc4b1..04ac58435a 100644
--- a/packages/svelte/tests/runtime-legacy/samples/attribute-custom-element-inheritance/main.svelte
+++ b/packages/svelte/tests/runtime-legacy/samples/attribute-custom-element-inheritance/main.svelte
@@ -26,8 +26,10 @@
 	}
 
 	class Extended extends MyCustomElement {}
-
-	window.customElements.define('my-custom-inheritance-element', Extended);
+	
+	if(!window.customElements.get('my-custom-inheritance-element')) {
+		window.customElements.define('my-custom-inheritance-element', Extended);
+	}
 </script>
 
 <my-custom-inheritance-element camelCase={{ text: 'World' }} text="!" />
diff --git a/packages/svelte/tests/runtime-legacy/samples/window-binding-scroll-store/_config.js b/packages/svelte/tests/runtime-legacy/samples/window-binding-scroll-store/_config.js
index 115c3cfd38..b9ea2fb27b 100644
--- a/packages/svelte/tests/runtime-legacy/samples/window-binding-scroll-store/_config.js
+++ b/packages/svelte/tests/runtime-legacy/samples/window-binding-scroll-store/_config.js
@@ -9,7 +9,8 @@ export default test({
 		Object.defineProperties(window, {
 			scrollY: {
 				value: 0,
-				configurable: true
+				configurable: true,
+				writable: true
 			}
 		});
 		original_scrollTo = window.scrollTo;
diff --git a/packages/svelte/tests/runtime-legacy/shared.ts b/packages/svelte/tests/runtime-legacy/shared.ts
index fc748ce6b2..8acac668f9 100644
--- a/packages/svelte/tests/runtime-legacy/shared.ts
+++ b/packages/svelte/tests/runtime-legacy/shared.ts
@@ -10,7 +10,8 @@ import { compile_directory } from '../helpers.js';
 import { setup_html_equal } from '../html_equal.js';
 import { raf } from '../animation-helpers.js';
 import type { CompileOptions } from '#compiler';
-import { suite_with_variants, type BaseTest } from '../suite.js';
+import { suite_with_variants, type BaseTest, type TemplatingMode } from '../suite.js';
+import { seen } from '../../src/internal/server/dev.js';
 
 type Assert = typeof import('vitest').assert & {
 	htmlEqual(a: string, b: string, description?: string): void;
@@ -141,16 +142,21 @@ export function runtime_suite(runes: boolean) {
 
 			return false;
 		},
-		(config, cwd) => {
-			return common_setup(cwd, runes, config);
+		(config, cwd, templating_mode) => {
+			return common_setup(cwd, runes, config, templating_mode);
 		},
-		async (config, cwd, variant, common) => {
-			await run_test_variant(cwd, config, variant, common, runes);
+		async (config, cwd, variant, common, templating_mode) => {
+			await run_test_variant(cwd, config, variant, common, runes, templating_mode);
 		}
 	);
 }
 
-async function common_setup(cwd: string, runes: boolean | undefined, config: RuntimeTest) {
+async function common_setup(
+	cwd: string,
+	runes: boolean | undefined,
+	config: RuntimeTest,
+	templating_mode: TemplatingMode
+) {
 	const force_hmr = process.env.HMR && config.compileOptions?.dev !== false && !config.error;
 
 	const compileOptions: CompileOptions = {
@@ -161,13 +167,14 @@ async function common_setup(cwd: string, runes: boolean | undefined, config: Run
 		...config.compileOptions,
 		immutable: config.immutable,
 		accessors: 'accessors' in config ? config.accessors : true,
-		runes
+		runes,
+		preventTemplateCloning: templating_mode === 'functional'
 	};
 
 	// load_compiled can be used for debugging a test. It means the compiler will not run on the input
 	// so you can manipulate the output manually to see what fixes it, adding console.logs etc.
 	if (!config.load_compiled) {
-		await compile_directory(cwd, 'client', compileOptions);
+		await compile_directory(cwd, 'client', compileOptions, undefined, undefined, templating_mode);
 		await compile_directory(cwd, 'server', compileOptions);
 	}
 
@@ -179,7 +186,8 @@ async function run_test_variant(
 	config: RuntimeTest,
 	variant: 'dom' | 'hydrate' | 'ssr',
 	compileOptions: CompileOptions,
-	runes: boolean
+	runes: boolean,
+	templating_mode: TemplatingMode
 ) {
 	let unintended_error = false;
 
@@ -257,8 +265,15 @@ async function run_test_variant(
 		raf.reset();
 
 		// Put things we need on window for testing
-		const styles = globSync('**/*.css', { cwd: `${cwd}/_output/client` })
-			.map((file) => fs.readFileSync(`${cwd}/_output/client/${file}`, 'utf-8'))
+		const styles = globSync('**/*.css', {
+			cwd: `${cwd}/_output/client${templating_mode === 'functional' ? '-functional' : ''}`
+		})
+			.map((file) =>
+				fs.readFileSync(
+					`${cwd}/_output/client${templating_mode === 'functional' ? '-functional' : ''}/${file}`,
+					'utf-8'
+				)
+			)
 			.join('\n')
 			.replace(/\/\*<\/?style>\*\//g, '');
 
@@ -274,7 +289,9 @@ async function run_test_variant(
 
 		globalThis.requestAnimationFrame = globalThis.setTimeout;
 
-		let mod = await import(`${cwd}/_output/client/main.svelte.js`);
+		let mod = await import(
+			`${cwd}/_output/client${templating_mode === 'functional' ? '-functional' : ''}/main.svelte.js`
+		);
 
 		const target = window.document.querySelector('main') as HTMLElement;
 
@@ -282,6 +299,8 @@ async function run_test_variant(
 
 		if (variant === 'hydrate' || variant === 'ssr') {
 			config.before_test?.();
+			// we need to clear the seen messages between tests
+			seen?.clear?.();
 			// ssr into target
 			const SsrSvelteComponent = (await import(`${cwd}/_output/server/main.svelte.js`)).default;
 			const { html, head } = render(SsrSvelteComponent, {
@@ -289,11 +308,17 @@ async function run_test_variant(
 				idPrefix: config.id_prefix
 			});
 
-			fs.writeFileSync(`${cwd}/_output/rendered.html`, html);
+			fs.writeFileSync(
+				`${cwd}/_output/rendered${templating_mode === 'functional' ? '-functional' : ''}.html`,
+				html
+			);
 			target.innerHTML = html;
 
 			if (head) {
-				fs.writeFileSync(`${cwd}/_output/rendered_head.html`, head);
+				fs.writeFileSync(
+					`${cwd}/_output/rendered_head${templating_mode === 'functional' ? '-functional' : ''}.html`,
+					head
+				);
 				window.document.head.innerHTML = window.document.head.innerHTML + head;
 			}
 
diff --git a/packages/svelte/tests/runtime-legacy/test.ts b/packages/svelte/tests/runtime-legacy/test.ts
index c4617a571c..d422d8a336 100644
--- a/packages/svelte/tests/runtime-legacy/test.ts
+++ b/packages/svelte/tests/runtime-legacy/test.ts
@@ -11,4 +11,5 @@ const { test, run } = runtime_suite(false);
 
 export { test, ok };
 
-await run(__dirname);
+await run(__dirname, 'string');
+await run(__dirname, 'functional');
diff --git a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte
index 4c98245e5b..82774f160d 100644
--- a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte
+++ b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte
@@ -1,18 +1,20 @@
 <script module>
-    customElements.define('value-element', class extends HTMLElement {
+	if(!customElements.get('value-element')) {
+		customElements.define('value-element', class extends HTMLElement {
 
-        constructor() {
-            super();
-            this.attachShadow({ mode: 'open' });
-        }
+			constructor() {
+				super();
+				this.attachShadow({ mode: 'open' });
+			}
 
-        set value(v) {
-            if (this.__value !== v) {
-                this.__value = v;
-                this.shadowRoot.innerHTML = `<span>${v}</span>`;
-            }
-        }
-    });
+			set value(v) {
+				if (this.__value !== v) {
+					this.__value = v;
+					this.shadowRoot.innerHTML = `<span>${v}</span>`;
+				}
+			}
+		});
+	}
 </script>
 
 <my-element string="test" object={{ test: true }}></my-element>
diff --git a/packages/svelte/tests/runtime-runes/test.ts b/packages/svelte/tests/runtime-runes/test.ts
index 0806864060..5dafe62ad2 100644
--- a/packages/svelte/tests/runtime-runes/test.ts
+++ b/packages/svelte/tests/runtime-runes/test.ts
@@ -5,4 +5,5 @@ const { test, run } = runtime_suite(true);
 
 export { test, ok };
 
-await run(__dirname);
+await run(__dirname, 'string');
+await run(__dirname, 'functional');
diff --git a/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..262454e9c3
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/client-functional/index.svelte.js
@@ -0,0 +1,52 @@
+import 'svelte/internal/disclose-version';
+import * as $ from 'svelte/internal/client';
+
+function increment(_, counter) {
+	counter.count += 1;
+}
+
+var root = $.template_fn(
+	() => {
+		var button = document.createElement('button');
+		var text = document.createTextNode(' ');
+
+		button.insertBefore(text, undefined)
+
+		var text_1 = document.createTextNode(' ');
+		var comment = document.createComment('');
+		var text_2 = document.createTextNode(' ');
+		var fragment = document.createDocumentFragment();
+
+		fragment.append(button, text_1, comment, text_2)
+		return fragment;
+	},
+	1
+);
+
+export default function Await_block_scope($$anchor) {
+	let counter = $.proxy({ count: 0 });
+	const promise = $.derived(() => Promise.resolve(counter));
+	var fragment = root();
+	var button = $.first_child(fragment);
+
+	button.__click = [increment, counter];
+
+	var text = $.child(button);
+
+	$.reset(button);
+
+	var node = $.sibling(button, 2);
+
+	$.await(node, () => $.get(promise), null, ($$anchor, counter) => {});
+
+	var text_1 = $.sibling(node);
+
+	$.template_effect(() => {
+		$.set_text(text, `clicks: ${counter.count ?? ''}`);
+		$.set_text(text_1, ` ${counter.count ?? ''}`);
+	});
+
+	$.append($$anchor, fragment);
+}
+
+$.delegate(['click']);
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..e4b1e2d1e0
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client-functional/index.svelte.js
@@ -0,0 +1,45 @@
+import 'svelte/internal/disclose-version';
+import * as $ from 'svelte/internal/client';
+import TextInput from './Child.svelte';
+
+const snippet = ($$anchor) => {
+	$.next();
+
+	var text = $.text('Something');
+
+	$.append($$anchor, text);
+};
+
+var root = $.template_fn(
+	() => {
+		var comment = document.createComment('');
+		var comment_1 = document.createComment('');
+		var text = document.createTextNode(' ');
+		var fragment = document.createDocumentFragment();
+
+		fragment.append(comment, comment_1, text)
+		return fragment;
+	},
+	1
+);
+
+export default function Bind_component_snippet($$anchor) {
+	let value = $.state('');
+	const _snippet = snippet;
+	var fragment = root();
+	var node = $.first_child(fragment);
+
+	TextInput(node, {
+		get value() {
+			return $.get(value);
+		},
+		set value($$value) {
+			$.set(value, $.proxy($$value));
+		}
+	});
+
+	var text_1 = $.sibling(node);
+
+	$.template_effect(() => $.set_text(text_1, ` value: ${$.get(value) ?? ''}`));
+	$.append($$anchor, fragment);
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/bind-this/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-this/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..dfd32a04e5
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/bind-this/_expected/client-functional/index.svelte.js
@@ -0,0 +1,7 @@
+import 'svelte/internal/disclose-version';
+import 'svelte/internal/flags/legacy';
+import * as $ from 'svelte/internal/client';
+
+export default function Bind_this($$anchor) {
+	$.bind_this(Foo($$anchor, { $$legacy: true }), ($$value) => foo = $$value, () => foo);
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..2898f31a6f
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/client-functional/index.svelte.js
@@ -0,0 +1,27 @@
+import 'svelte/internal/disclose-version';
+import * as $ from 'svelte/internal/client';
+
+export default function Class_state_field_constructor_assignment($$anchor, $$props) {
+	$.push($$props, true);
+
+	class Foo {
+		#a = $.state();
+
+		get a() {
+			return $.get(this.#a);
+		}
+
+		set a(value) {
+			$.set(this.#a, $.proxy(value));
+		}
+
+		#b = $.state();
+
+		constructor() {
+			this.a = 1;
+			this.#b.v = 2;
+		}
+	}
+
+	$.pop();
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/destructured-assignments/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/destructured-assignments/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..9651713c52
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/destructured-assignments/_expected/client-functional/index.svelte.js
@@ -0,0 +1,16 @@
+/* index.svelte.js generated by Svelte VERSION */
+import * as $ from 'svelte/internal/client';
+
+let a = $.state(1);
+let b = $.state(2);
+let c = 3;
+let d = 4;
+
+export function update(array) {
+	(
+		$.set(a, $.proxy(array[0])),
+		$.set(b, $.proxy(array[1]))
+	);
+
+	[c, d] = array;
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client-functional/main.svelte.js b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client-functional/main.svelte.js
new file mode 100644
index 0000000000..c05184f1f8
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client-functional/main.svelte.js
@@ -0,0 +1,53 @@
+import 'svelte/internal/disclose-version';
+import * as $ from 'svelte/internal/client';
+
+var root = $.template_fn(
+	() => {
+		var div = document.createElement('div');
+		var text = document.createTextNode(' ');
+		var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+		var text_1 = document.createTextNode(' ');
+		var custom_element = document.createElement('custom-element');
+		var text_2 = document.createTextNode(' ');
+		var div_1 = document.createElement('div');
+		var text_3 = document.createTextNode(' ');
+		var svg_1 = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+		var text_4 = document.createTextNode(' ');
+		var custom_element_1 = document.createElement('custom-element');
+		var fragment = document.createDocumentFragment();
+
+		fragment.append(div, text, svg, text_1, custom_element, text_2, div_1, text_3, svg_1, text_4, custom_element_1)
+		return fragment;
+	},
+	3
+);
+
+export default function Main($$anchor) {
+	// needs to be a snapshot test because jsdom does auto-correct the attribute casing
+	let x = 'test';
+	let y = () => 'test';
+	var fragment = root();
+	var div = $.first_child(fragment);
+	var svg = $.sibling(div, 2);
+	var custom_element = $.sibling(svg, 2);
+
+	$.template_effect(() => $.set_custom_element_data(custom_element, 'fooBar', x));
+
+	var div_1 = $.sibling(custom_element, 2);
+	var svg_1 = $.sibling(div_1, 2);
+	var custom_element_1 = $.sibling(svg_1, 2);
+
+	$.template_effect(() => $.set_custom_element_data(custom_element_1, 'fooBar', y()));
+
+	$.template_effect(
+		($0, $1) => {
+			$.set_attribute(div, 'foobar', x);
+			$.set_attribute(svg, 'viewBox', x);
+			$.set_attribute(div_1, 'foobar', $0);
+			$.set_attribute(svg_1, 'viewBox', $1);
+		},
+		[y, y]
+	);
+
+	$.append($$anchor, fragment);
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..c0626bd416
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client-functional/index.svelte.js
@@ -0,0 +1,19 @@
+import 'svelte/internal/disclose-version';
+import 'svelte/internal/flags/legacy';
+import * as $ from 'svelte/internal/client';
+
+export default function Each_string_template($$anchor) {
+	var fragment = $.comment();
+	var node = $.first_child(fragment);
+
+	$.each(node, 0, () => ['foo', 'bar', 'baz'], $.index, ($$anchor, thing) => {
+		$.next();
+
+		var text = $.text();
+
+		$.template_effect(() => $.set_text(text, `${thing ?? ''}, `));
+		$.append($$anchor, text);
+	});
+
+	$.append($$anchor, fragment);
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/export-state/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/export-state/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..c2a6054bc6
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/export-state/_expected/client-functional/index.svelte.js
@@ -0,0 +1,4 @@
+/* index.svelte.js generated by Svelte VERSION */
+import * as $ from 'svelte/internal/client';
+
+export const object = $.proxy({ ok: true });
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..c545608bca
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client-functional/index.svelte.js
@@ -0,0 +1,27 @@
+import 'svelte/internal/disclose-version';
+import * as $ from 'svelte/internal/client';
+
+export default function Function_prop_no_getter($$anchor) {
+	let count = $.state(0);
+
+	function onmouseup() {
+		$.set(count, $.get(count) + 2);
+	}
+
+	const plusOne = (num) => num + 1;
+
+	Button($$anchor, {
+		onmousedown: () => $.set(count, $.get(count) + 1),
+		onmouseup,
+		onmouseenter: () => $.set(count, $.proxy(plusOne($.get(count)))),
+		children: ($$anchor, $$slotProps) => {
+			$.next();
+
+			var text = $.text();
+
+			$.template_effect(() => $.set_text(text, `clicks: ${$.get(count) ?? ''}`));
+			$.append($$anchor, text);
+		},
+		$$slots: { default: true }
+	});
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/hello-world/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/hello-world/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..5f55a12c20
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/hello-world/_expected/client-functional/index.svelte.js
@@ -0,0 +1,21 @@
+import 'svelte/internal/disclose-version';
+import 'svelte/internal/flags/legacy';
+import * as $ from 'svelte/internal/client';
+
+var root = $.template_fn(() => {
+	var h1 = document.createElement('h1');
+	var text = document.createTextNode('hello world');
+
+	h1.insertBefore(text, undefined)
+
+	var fragment = document.createDocumentFragment();
+
+	fragment.append(h1)
+	return fragment;
+});
+
+export default function Hello_world($$anchor) {
+	var h1 = root();
+
+	$.append($$anchor, h1);
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/hmr/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/hmr/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..6196ed18bb
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/hmr/_expected/client-functional/index.svelte.js
@@ -0,0 +1,32 @@
+import 'svelte/internal/disclose-version';
+import 'svelte/internal/flags/legacy';
+import * as $ from 'svelte/internal/client';
+
+var root = $.template_fn(() => {
+	var h1 = document.createElement('h1');
+	var text = document.createTextNode('hello world');
+
+	h1.insertBefore(text, undefined)
+
+	var fragment = document.createDocumentFragment();
+
+	fragment.append(h1)
+	return fragment;
+});
+
+function Hmr($$anchor) {
+	var h1 = root();
+
+	$.append($$anchor, h1);
+}
+
+if (import.meta.hot) {
+	Hmr = $.hmr(Hmr, () => Hmr[$.HMR].source);
+
+	import.meta.hot.accept((module) => {
+		module.default[$.HMR].source = Hmr[$.HMR].source;
+		$.set(Hmr[$.HMR].source, module.default[$.HMR].original);
+	});
+}
+
+export default Hmr;
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client-functional/export.js b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client-functional/export.js
new file mode 100644
index 0000000000..b4bb7075da
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client-functional/export.js
@@ -0,0 +1 @@
+export * from '../../export.js';
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..ebbe191dcb
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client-functional/index.svelte.js
@@ -0,0 +1,8 @@
+import 'svelte/internal/disclose-version';
+import 'svelte/internal/flags/legacy';
+import * as $ from 'svelte/internal/client';
+import { random } from './module.svelte';
+
+export default function Imports_in_modules($$anchor) {
+	
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client-functional/module.svelte.js b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client-functional/module.svelte.js
new file mode 100644
index 0000000000..0d366e6258
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client-functional/module.svelte.js
@@ -0,0 +1,5 @@
+/* module.svelte.js generated by Svelte VERSION */
+import * as $ from 'svelte/internal/client';
+import { random } from './export';
+
+export { random };
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..6b48b03635
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/client-functional/index.svelte.js
@@ -0,0 +1,54 @@
+import 'svelte/internal/disclose-version';
+import * as $ from 'svelte/internal/client';
+
+var on_click = (_, count) => $.update(count);
+
+var root = $.template_fn(
+	() => {
+		var h1 = document.createElement('h1');
+		var text = document.createTextNode(' ');
+		var b = document.createElement('b');
+		var text_1 = document.createTextNode(' ');
+		var button = document.createElement('button');
+		var text_2 = document.createTextNode(' ');
+
+		button.insertBefore(text_2, undefined)
+
+		var text_3 = document.createTextNode(' ');
+		var h1_1 = document.createElement('h1');
+		var fragment = document.createDocumentFragment();
+
+		fragment.append(h1, text, b, text_1, button, text_3, h1_1)
+		return fragment;
+	},
+	1
+);
+
+export default function Nullish_coallescence_omittance($$anchor) {
+	let name = 'world';
+	let count = $.state(0);
+	var fragment = root();
+	var h1 = $.first_child(fragment);
+
+	h1.textContent = `Hello, ${name ?? ''}!`;
+
+	var b = $.sibling(h1, 2);
+
+	b.textContent = `${1 ?? 'stuff'}${2 ?? 'more stuff'}${3 ?? 'even more stuff'}`;
+
+	var button = $.sibling(b, 2);
+
+	button.__click = [on_click, count];
+
+	var text = $.child(button);
+
+	$.reset(button);
+
+	var h1_1 = $.sibling(button, 2);
+
+	h1_1.textContent = `Hello, ${name ?? 'earth' ?? ''}`;
+	$.template_effect(() => $.set_text(text, `Count is ${$.get(count) ?? ''}`));
+	$.append($$anchor, fragment);
+}
+
+$.delegate(['click']);
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/props-identifier/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/props-identifier/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..5a46b9bbef
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/props-identifier/_expected/client-functional/index.svelte.js
@@ -0,0 +1,17 @@
+import 'svelte/internal/disclose-version';
+import * as $ from 'svelte/internal/client';
+
+export default function Props_identifier($$anchor, $$props) {
+	$.push($$props, true);
+
+	let props = $.rest_props($$props, ['$$slots', '$$events', '$$legacy']);
+
+	$$props.a;
+	props[a];
+	$$props.a.b;
+	$$props.a.b = true;
+	props.a = true;
+	props[a] = true;
+	props;
+	$.pop();
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/purity/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/purity/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..409a0d93aa
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/purity/_expected/client-functional/index.svelte.js
@@ -0,0 +1,34 @@
+import 'svelte/internal/disclose-version';
+import 'svelte/internal/flags/legacy';
+import * as $ from 'svelte/internal/client';
+
+var root = $.template_fn(
+	() => {
+		var p = document.createElement('p');
+		var text = document.createTextNode(' ');
+		var p_1 = document.createElement('p');
+		var text_1 = document.createTextNode(' ');
+		var comment = document.createComment('');
+		var fragment = document.createDocumentFragment();
+
+		fragment.append(p, text, p_1, text_1, comment)
+		return fragment;
+	},
+	1
+);
+
+export default function Purity($$anchor) {
+	var fragment = root();
+	var p = $.first_child(fragment);
+
+	p.textContent = Math.max(0, Math.min(0, 100));
+
+	var p_1 = $.sibling(p, 2);
+
+	p_1.textContent = location.href;
+
+	var node = $.sibling(p_1, 2);
+
+	Child(node, { prop: encodeURIComponent('hello') });
+	$.append($$anchor, fragment);
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..8023738996
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/client-functional/index.svelte.js
@@ -0,0 +1,283 @@
+import 'svelte/internal/disclose-version';
+import * as $ from 'svelte/internal/client';
+
+var root = $.template_fn(
+	() => {
+		var header = document.createElement('header');
+		var nav = document.createElement('nav');
+
+		header.insertBefore(nav, undefined)
+
+		var a = document.createElement('a');
+
+		nav.insertBefore(a, undefined)
+		a.setAttribute('href', '/')
+
+		var text = document.createTextNode('Home');
+
+		a.insertBefore(text, undefined)
+
+		var text_1 = document.createTextNode(' ');
+
+		nav.insertBefore(text_1, undefined)
+
+		var a_1 = document.createElement('a');
+
+		nav.insertBefore(a_1, undefined)
+		a_1.setAttribute('href', '/away')
+
+		var text_2 = document.createTextNode('Away');
+
+		a_1.insertBefore(text_2, undefined)
+
+		var text_3 = document.createTextNode(' ');
+		var main = document.createElement('main');
+		var h1 = document.createElement('h1');
+
+		main.insertBefore(h1, undefined)
+
+		var text_4 = document.createTextNode(' ');
+
+		h1.insertBefore(text_4, undefined)
+
+		var text_5 = document.createTextNode(' ');
+
+		main.insertBefore(text_5, undefined)
+
+		var div = document.createElement('div');
+
+		main.insertBefore(div, undefined)
+		div.setAttribute('class', 'static')
+
+		var p = document.createElement('p');
+
+		div.insertBefore(p, undefined)
+
+		var text_6 = document.createTextNode('we don\'t need to traverse these nodes');
+
+		p.insertBefore(text_6, undefined)
+
+		var text_7 = document.createTextNode(' ');
+
+		main.insertBefore(text_7, undefined)
+
+		var p_1 = document.createElement('p');
+
+		main.insertBefore(p_1, undefined)
+
+		var text_8 = document.createTextNode('or');
+
+		p_1.insertBefore(text_8, undefined)
+
+		var text_9 = document.createTextNode(' ');
+
+		main.insertBefore(text_9, undefined)
+
+		var p_2 = document.createElement('p');
+
+		main.insertBefore(p_2, undefined)
+
+		var text_10 = document.createTextNode('these');
+
+		p_2.insertBefore(text_10, undefined)
+
+		var text_11 = document.createTextNode(' ');
+
+		main.insertBefore(text_11, undefined)
+
+		var p_3 = document.createElement('p');
+
+		main.insertBefore(p_3, undefined)
+
+		var text_12 = document.createTextNode('ones');
+
+		p_3.insertBefore(text_12, undefined)
+
+		var text_13 = document.createTextNode(' ');
+
+		main.insertBefore(text_13, undefined)
+
+		var comment = document.createComment('');
+
+		main.insertBefore(comment, undefined)
+
+		var text_14 = document.createTextNode(' ');
+
+		main.insertBefore(text_14, undefined)
+
+		var p_4 = document.createElement('p');
+
+		main.insertBefore(p_4, undefined)
+
+		var text_15 = document.createTextNode('these');
+
+		p_4.insertBefore(text_15, undefined)
+
+		var text_16 = document.createTextNode(' ');
+
+		main.insertBefore(text_16, undefined)
+
+		var p_5 = document.createElement('p');
+
+		main.insertBefore(p_5, undefined)
+
+		var text_17 = document.createTextNode('trailing');
+
+		p_5.insertBefore(text_17, undefined)
+
+		var text_18 = document.createTextNode(' ');
+
+		main.insertBefore(text_18, undefined)
+
+		var p_6 = document.createElement('p');
+
+		main.insertBefore(p_6, undefined)
+
+		var text_19 = document.createTextNode('nodes');
+
+		p_6.insertBefore(text_19, undefined)
+
+		var text_20 = document.createTextNode(' ');
+
+		main.insertBefore(text_20, undefined)
+
+		var p_7 = document.createElement('p');
+
+		main.insertBefore(p_7, undefined)
+
+		var text_21 = document.createTextNode('can');
+
+		p_7.insertBefore(text_21, undefined)
+
+		var text_22 = document.createTextNode(' ');
+
+		main.insertBefore(text_22, undefined)
+
+		var p_8 = document.createElement('p');
+
+		main.insertBefore(p_8, undefined)
+
+		var text_23 = document.createTextNode('be');
+
+		p_8.insertBefore(text_23, undefined)
+
+		var text_24 = document.createTextNode(' ');
+
+		main.insertBefore(text_24, undefined)
+
+		var p_9 = document.createElement('p');
+
+		main.insertBefore(p_9, undefined)
+
+		var text_25 = document.createTextNode('completely');
+
+		p_9.insertBefore(text_25, undefined)
+
+		var text_26 = document.createTextNode(' ');
+
+		main.insertBefore(text_26, undefined)
+
+		var p_10 = document.createElement('p');
+
+		main.insertBefore(p_10, undefined)
+
+		var text_27 = document.createTextNode('ignored');
+
+		p_10.insertBefore(text_27, undefined)
+
+		var text_28 = document.createTextNode(' ');
+		var cant_skip = document.createElement('cant-skip');
+		var custom_elements = document.createElement('custom-elements');
+
+		cant_skip.insertBefore(custom_elements, undefined)
+
+		var text_29 = document.createTextNode(' ');
+		var div_1 = document.createElement('div');
+		var input = document.createElement('input');
+
+		div_1.insertBefore(input, undefined)
+
+		var text_30 = document.createTextNode(' ');
+		var div_2 = document.createElement('div');
+		var source = document.createElement('source');
+
+		div_2.insertBefore(source, undefined)
+
+		var text_31 = document.createTextNode(' ');
+		var select = document.createElement('select');
+		var option = document.createElement('option');
+
+		select.insertBefore(option, undefined)
+
+		var text_32 = document.createTextNode('a');
+
+		option.insertBefore(text_32, undefined)
+
+		var text_33 = document.createTextNode(' ');
+		var img = document.createElement('img');
+
+		img.setAttribute('src', '...')
+		img.setAttribute('alt', '')
+		img.setAttribute('loading', 'lazy')
+
+		var text_34 = document.createTextNode(' ');
+		var div_3 = document.createElement('div');
+		var img_1 = document.createElement('img');
+
+		div_3.insertBefore(img_1, undefined)
+		img_1.setAttribute('src', '...')
+		img_1.setAttribute('alt', '')
+		img_1.setAttribute('loading', 'lazy')
+
+		var fragment = document.createDocumentFragment();
+
+		fragment.append(header, text_3, main, text_28, cant_skip, text_29, div_1, text_30, div_2, text_31, select, text_33, img, text_34, div_3)
+		return fragment;
+	},
+	3
+);
+
+export default function Skip_static_subtree($$anchor, $$props) {
+	var fragment = root();
+	var main = $.sibling($.first_child(fragment), 2);
+	var h1 = $.child(main);
+	var text = $.child(h1, true);
+
+	$.reset(h1);
+
+	var node = $.sibling(h1, 10);
+
+	$.html(node, () => $$props.content, false, false);
+	$.next(14);
+	$.reset(main);
+
+	var cant_skip = $.sibling(main, 2);
+	var custom_elements = $.child(cant_skip);
+
+	$.set_custom_element_data(custom_elements, 'with', 'attributes');
+	$.reset(cant_skip);
+
+	var div = $.sibling(cant_skip, 2);
+	var input = $.child(div);
+
+	$.autofocus(input, true);
+	$.reset(div);
+
+	var div_1 = $.sibling(div, 2);
+	var source = $.child(div_1);
+
+	source.muted = true;
+	$.reset(div_1);
+
+	var select = $.sibling(div_1, 2);
+	var option = $.child(select);
+
+	option.value = null == (option.__value = 'a') ? '' : 'a';
+	$.reset(select);
+
+	var img = $.sibling(select, 2);
+
+	$.next(2);
+	$.template_effect(() => $.set_text(text, $$props.title));
+	$.append($$anchor, fragment);
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..4247dcfda3
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client-functional/index.svelte.js
@@ -0,0 +1,50 @@
+import 'svelte/internal/disclose-version';
+import * as $ from 'svelte/internal/client';
+
+function reset(_, str, tpl) {
+	$.set(str, '');
+	$.set(str, ``);
+	$.set(tpl, '');
+	$.set(tpl, ``);
+}
+
+var root = $.template_fn(
+	() => {
+		var input = document.createElement('input');
+		var text = document.createTextNode(' ');
+		var input_1 = document.createElement('input');
+		var text_1 = document.createTextNode(' ');
+		var button = document.createElement('button');
+		var text_2 = document.createTextNode('reset');
+
+		button.insertBefore(text_2, undefined)
+
+		var fragment = document.createDocumentFragment();
+
+		fragment.append(input, text, input_1, text_1, button)
+		return fragment;
+	},
+	1
+);
+
+export default function State_proxy_literal($$anchor) {
+	let str = $.state('');
+	let tpl = $.state(``);
+	var fragment = root();
+	var input = $.first_child(fragment);
+
+	$.remove_input_defaults(input);
+
+	var input_1 = $.sibling(input, 2);
+
+	$.remove_input_defaults(input_1);
+
+	var button = $.sibling(input_1, 2);
+
+	button.__click = [reset, str, tpl];
+	$.bind_value(input, () => $.get(str), ($$value) => $.set(str, $$value));
+	$.bind_value(input_1, () => $.get(tpl), ($$value) => $.set(tpl, $$value));
+	$.append($$anchor, fragment);
+}
+
+$.delegate(['click']);
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..2270005ee0
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client-functional/index.svelte.js
@@ -0,0 +1,11 @@
+import 'svelte/internal/disclose-version';
+import * as $ from 'svelte/internal/client';
+
+export default function Svelte_element($$anchor, $$props) {
+	let tag = $.prop($$props, 'tag', 3, 'hr');
+	var fragment = $.comment();
+	var node = $.first_child(fragment);
+
+	$.element(node, tag, false);
+	$.append($$anchor, fragment);
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client-functional/index.svelte.js
new file mode 100644
index 0000000000..5163dc3509
--- /dev/null
+++ b/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client-functional/index.svelte.js
@@ -0,0 +1,34 @@
+import 'svelte/internal/disclose-version';
+import * as $ from 'svelte/internal/client';
+
+var root = $.template_fn(() => {
+	var p = document.createElement('p');
+	var text = document.createTextNode(' ');
+
+	p.insertBefore(text, undefined)
+
+	var fragment = document.createDocumentFragment();
+
+	fragment.append(p)
+	return fragment;
+});
+
+export default function Text_nodes_deriveds($$anchor) {
+	let count1 = 0;
+	let count2 = 0;
+
+	function text1() {
+		return count1;
+	}
+
+	function text2() {
+		return count2;
+	}
+
+	var p = root();
+	var text = $.child(p);
+
+	$.reset(p);
+	$.template_effect(($0, $1) => $.set_text(text, `${$0 ?? ''}${$1 ?? ''}`), [text1, text2]);
+	$.append($$anchor, p);
+}
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/test.ts b/packages/svelte/tests/snapshot/test.ts
index 0a591c6e2a..bbcee10d85 100644
--- a/packages/svelte/tests/snapshot/test.ts
+++ b/packages/svelte/tests/snapshot/test.ts
@@ -9,8 +9,15 @@ interface SnapshotTest extends BaseTest {
 	compileOptions?: Partial<import('#compiler').CompileOptions>;
 }
 
-const { test, run } = suite<SnapshotTest>(async (config, cwd) => {
-	await compile_directory(cwd, 'client', config.compileOptions);
+const { test, run } = suite<SnapshotTest>(async (config, cwd, templating_mode) => {
+	await compile_directory(
+		cwd,
+		'client',
+		config.compileOptions,
+		undefined,
+		undefined,
+		templating_mode
+	);
 	await compile_directory(cwd, 'server', config.compileOptions);
 
 	// run `UPDATE_SNAPSHOTS=true pnpm test snapshot` to update snapshot tests
@@ -41,4 +48,5 @@ const { test, run } = suite<SnapshotTest>(async (config, cwd) => {
 
 export { test };
 
-await run(__dirname);
+await run(__dirname, 'string');
+await run(__dirname, 'functional');
diff --git a/packages/svelte/tests/suite.ts b/packages/svelte/tests/suite.ts
index 0ae06e727f..c2e7743f2b 100644
--- a/packages/svelte/tests/suite.ts
+++ b/packages/svelte/tests/suite.ts
@@ -6,6 +6,8 @@ export interface BaseTest {
 	solo?: boolean;
 }
 
+export type TemplatingMode = 'string' | 'functional';
+
 /**
  * To filter tests, run one of these:
  *
@@ -20,14 +22,22 @@ const filter = process.env.FILTER
 		)
 	: /./;
 
-export function suite<Test extends BaseTest>(fn: (config: Test, test_dir: string) => void) {
+export function suite<Test extends BaseTest>(
+	fn: (config: Test, test_dir: string, templating_mode: TemplatingMode) => void
+) {
 	return {
 		test: (config: Test) => config,
-		run: async (cwd: string, samples_dir = 'samples') => {
+		run: async (
+			cwd: string,
+			templating_mode: TemplatingMode = 'string',
+			samples_dir = 'samples'
+		) => {
 			await for_each_dir<Test>(cwd, samples_dir, (config, dir) => {
 				let it_fn = config.skip ? it.skip : config.solo ? it.only : it;
 
-				it_fn(dir, () => fn(config, `${cwd}/${samples_dir}/${dir}`));
+				it_fn(`${dir} (${templating_mode})`, () =>
+					fn(config, `${cwd}/${samples_dir}/${dir}`, templating_mode)
+				);
 			});
 		}
 	};
@@ -36,12 +46,26 @@ export function suite<Test extends BaseTest>(fn: (config: Test, test_dir: string
 export function suite_with_variants<Test extends BaseTest, Variants extends string, Common>(
 	variants: Variants[],
 	should_skip_variant: (variant: Variants, config: Test) => boolean | 'no-test',
-	common_setup: (config: Test, test_dir: string) => Promise<Common> | Common,
-	fn: (config: Test, test_dir: string, variant: Variants, common: Common) => void
+	common_setup: (
+		config: Test,
+		test_dir: string,
+		templating_mode: TemplatingMode
+	) => Promise<Common> | Common,
+	fn: (
+		config: Test,
+		test_dir: string,
+		variant: Variants,
+		common: Common,
+		templating_mode: TemplatingMode
+	) => void
 ) {
 	return {
 		test: (config: Test) => config,
-		run: async (cwd: string, samples_dir = 'samples') => {
+		run: async (
+			cwd: string,
+			templating_mode: TemplatingMode = 'string',
+			samples_dir = 'samples'
+		) => {
 			await for_each_dir<Test>(cwd, samples_dir, (config, dir) => {
 				let called_common = false;
 				let common: any = undefined;
@@ -54,12 +78,12 @@ export function suite_with_variants<Test extends BaseTest, Variants extends stri
 					const solo = config.solo;
 					let it_fn = skip ? it.skip : solo ? it.only : it;
 
-					it_fn(`${dir} (${variant})`, async () => {
+					it_fn(`${dir} (${templating_mode}-${variant})`, async () => {
 						if (!called_common) {
 							called_common = true;
-							common = await common_setup(config, `${cwd}/${samples_dir}/${dir}`);
+							common = await common_setup(config, `${cwd}/${samples_dir}/${dir}`, templating_mode);
 						}
-						return fn(config, `${cwd}/${samples_dir}/${dir}`, variant, common);
+						return fn(config, `${cwd}/${samples_dir}/${dir}`, variant, common, templating_mode);
 					});
 				}
 			});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c687db12d4..420e0e90fd 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -916,7 +916,7 @@ packages:
     resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
 
   concat-map@0.0.1:
-    resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
+    resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
 
   cross-spawn@5.1.0:
     resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}