diff --git a/.changeset/dull-oranges-fry.md b/.changeset/dull-oranges-fry.md
new file mode 100644
index 0000000000..0efcc6fa2d
--- /dev/null
+++ b/.changeset/dull-oranges-fry.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: avoid declaration tag warning in event handlers
diff --git a/.changeset/tame-donkeys-jump.md b/.changeset/tame-donkeys-jump.md
new file mode 100644
index 0000000000..aae38910db
--- /dev/null
+++ b/.changeset/tame-donkeys-jump.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: chain preprocessor sourcemaps with an empty `sources[0]` instead of dropping them
diff --git a/.changeset/young-doodles-beam.md b/.changeset/young-doodles-beam.md
new file mode 100644
index 0000000000..b68f55d241
--- /dev/null
+++ b/.changeset/young-doodles-beam.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: don't treat declaration tags as parts inside each blocks
diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/function.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/function.js
index 7bdb2243f2..6b3d227eca 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/function.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/function.js
@@ -18,7 +18,9 @@ export function visit_function(node, context) {
context.next({
...context.state,
- function_depth: context.state.function_depth + 1,
+ // we generally want to use scope.function_depth unless we specifically increased
+ // that in state.function_depth (e.g. a derived)
+ function_depth: Math.max(context.state.scope.function_depth, context.state.function_depth) + 1,
expression: null
});
}
diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js
index 51c84dd01c..c305d53ea5 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js
@@ -8,7 +8,7 @@ import { sanitize_template_string } from '../../../../../utils/sanitize_template
import { regex_is_valid_identifier } from '../../../../patterns.js';
import is_reference from 'is-reference';
import { dev, is_ignored, locator, component_name } from '../../../../../state.js';
-import { build_getter } from '../../utils.js';
+import { build_getter, is_state_source } from '../../utils.js';
import { ExpressionMetadata } from '../../../../nodes.js';
/**
@@ -272,6 +272,10 @@ export function build_bind_this(expression, value, { state, visit }) {
const binding = state.scope.get(node.name);
if (!binding) return;
+ // if it is a state or a derived it means is a declaration tag...in that case we don't want to pass the
+ // value but the signal itself or assignment will break
+ if (is_state_source(binding, state.analysis) || binding.kind === 'derived') return;
+
for (const [owner, scope] of state.scopes) {
if (owner.type === 'EachBlock' && scope === binding.scope) {
ids.push(node);
diff --git a/packages/svelte/src/compiler/utils/mapped_code.js b/packages/svelte/src/compiler/utils/mapped_code.js
index 7686ba59c6..635743c0c4 100644
--- a/packages/svelte/src/compiler/utils/mapped_code.js
+++ b/packages/svelte/src/compiler/utils/mapped_code.js
@@ -311,6 +311,13 @@ function apply_preprocessor_sourcemap(filename, svelte_map, preprocessor_map_inp
typeof preprocessor_map_input === 'string'
? JSON.parse(preprocessor_map_input)
: preprocessor_map_input;
+ // A preprocessor map with a missing/empty `sources[0]` (e.g. from a MagicString transform
+ // created without a `source` option) can't be matched against `filename` during combination,
+ // which silently drops the chain instead of erroring. Normalize it to `filename` first, the
+ // same way Vite treats an empty `sources[0]` as referring to the file being transformed.
+ if (preprocessor_map.sources?.length === 1 && !preprocessor_map.sources[0]) {
+ preprocessor_map.sources = [filename];
+ }
const result_map = combine_sourcemaps(filename, [svelte_map, preprocessor_map]);
// Svelte expects a SourceMap which includes toUrl and toString. Instead of wrapping our output in a class,
// we just tack on the extra properties.
diff --git a/packages/svelte/tests/runtime-runes/samples/declaration-tags-each/_config.js b/packages/svelte/tests/runtime-runes/samples/declaration-tags-each/_config.js
new file mode 100644
index 0000000000..d5cdd103b5
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/declaration-tags-each/_config.js
@@ -0,0 +1,10 @@
+import { flushSync } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ async test({ target, assert }) {
+ const [btn1, btn2] = target.querySelectorAll('button');
+ flushSync(() => btn2.click());
+ assert.equal(btn1.textContent, '1');
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/declaration-tags-each/main.svelte b/packages/svelte/tests/runtime-runes/samples/declaration-tags-each/main.svelte
new file mode 100644
index 0000000000..04d55913b4
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/declaration-tags-each/main.svelte
@@ -0,0 +1,6 @@
+{#each Array(1)}
+ {let ref = $state()}
+ {let count = $state(0)}
+
+
+{/each}
\ No newline at end of file
diff --git a/packages/svelte/tests/sourcemaps/samples/sourcemap-empty-source/_config.js b/packages/svelte/tests/sourcemaps/samples/sourcemap-empty-source/_config.js
new file mode 100644
index 0000000000..43a2a4c16a
--- /dev/null
+++ b/packages/svelte/tests/sourcemaps/samples/sourcemap-empty-source/_config.js
@@ -0,0 +1,29 @@
+import * as fs from 'node:fs';
+import MagicString from 'magic-string';
+import { test } from '../../test';
+
+// Simulates a bundler plugin (e.g. a Vite plugin using `magic-string`) that transforms
+// the Svelte source *before* it reaches `compile()`, and hands its own sourcemap to
+// `compileOptions.sourcemap` — the documented way to let svelte chain an upstream map
+// into its own output map. Crucially, the upstream map is generated *without* a `source`
+// option, exactly like `new MagicString(code).generateMap()` — this yields a sourcemap
+// whose `sources` is `['']`, which previously broke the chain entirely (see #18491)
+// instead of being treated as "this file", causing every mapping through it to resolve
+// to `{ source: null, line: null, column: null }`.
+const input = fs.readFileSync(new URL('./input.svelte', import.meta.url), 'utf-8');
+const src = new MagicString(input);
+src.overwrite(
+ src.original.indexOf('count * 2'),
+ src.original.indexOf('count * 2') + 'count * 2'.length,
+ 'count * 2',
+ {
+ storeName: false
+ }
+);
+
+export default test({
+ compileOptions: {
+ sourcemap: src.generateMap({ hires: true })
+ },
+ client: [{ str: 'let doubled' }]
+});
diff --git a/packages/svelte/tests/sourcemaps/samples/sourcemap-empty-source/input.svelte b/packages/svelte/tests/sourcemaps/samples/sourcemap-empty-source/input.svelte
new file mode 100644
index 0000000000..b4e0b50bdb
--- /dev/null
+++ b/packages/svelte/tests/sourcemaps/samples/sourcemap-empty-source/input.svelte
@@ -0,0 +1,6 @@
+
+
+
diff --git a/packages/svelte/tests/validator/samples/declaration-tag-state-referenced-locally/input.svelte b/packages/svelte/tests/validator/samples/declaration-tag-state-referenced-locally/input.svelte
index 90cc208e72..f422be9622 100644
--- a/packages/svelte/tests/validator/samples/declaration-tag-state-referenced-locally/input.svelte
+++ b/packages/svelte/tests/validator/samples/declaration-tag-state-referenced-locally/input.svelte
@@ -7,3 +7,7 @@
{let e = $state(0), f = e}
{a}{b}{c}{d}{e}{f}
+
+
\ No newline at end of file