From 9efe672df2540c51c2cfa817fd32e7667d5712ec Mon Sep 17 00:00:00 2001
From: Justin Paige <77657745+jhpaige@users.noreply.github.com>
Date: Wed, 6 Aug 2025 14:16:35 -0400
Subject: [PATCH 1/8] Update 18-class.md (#16558)
Rest of doc references 5.16 but this is from 5.19 so added the clarification.
---
documentation/docs/03-template-syntax/18-class.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/documentation/docs/03-template-syntax/18-class.md b/documentation/docs/03-template-syntax/18-class.md
index 1ea4a208dfdc..db85db4b37f4 100644
--- a/documentation/docs/03-template-syntax/18-class.md
+++ b/documentation/docs/03-template-syntax/18-class.md
@@ -71,7 +71,7 @@ The user of this component has the same flexibility to use a mixture of objects,
```
-Svelte also exposes the `ClassValue` type, which is the type of value that the `class` attribute on elements accept. This is useful if you want to use a type-safe class name in component props:
+Since Svelte 5.19, Svelte also exposes the `ClassValue` type, which is the type of value that the `class` attribute on elements accept. This is useful if you want to use a type-safe class name in component props:
```svelte
+
+{der}
+
+
\ No newline at end of file
From f00b364d5b5380f430ed6ba0c1b0be7de0a5a2c1 Mon Sep 17 00:00:00 2001
From: Ben McCann <322311+benmccann@users.noreply.github.com>
Date: Sat, 9 Aug 2025 09:24:44 -0700
Subject: [PATCH 4/8] chore: switch to jrdigewell version of remapping library
(#16587)
---
packages/svelte/package.json | 2 +-
packages/svelte/src/compiler/preprocess/index.js | 4 ++--
.../svelte/src/compiler/preprocess/private.d.ts | 2 +-
packages/svelte/src/compiler/utils/mapped_code.js | 4 ++--
pnpm-lock.yaml | 14 +++++++++++---
5 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/packages/svelte/package.json b/packages/svelte/package.json
index 0b14ab4b40c7..2269d5603f2a 100644
--- a/packages/svelte/package.json
+++ b/packages/svelte/package.json
@@ -166,7 +166,7 @@
"vitest": "^2.1.9"
},
"dependencies": {
- "@ampproject/remapping": "^2.3.0",
+ "@jridgewell/remapping": "^2.3.4",
"@jridgewell/sourcemap-codec": "^1.5.0",
"@sveltejs/acorn-typescript": "^1.0.5",
"@types/estree": "^1.0.5",
diff --git a/packages/svelte/src/compiler/preprocess/index.js b/packages/svelte/src/compiler/preprocess/index.js
index afef898471c6..429c2dcff150 100644
--- a/packages/svelte/src/compiler/preprocess/index.js
+++ b/packages/svelte/src/compiler/preprocess/index.js
@@ -1,6 +1,6 @@
/** @import { Processed, Preprocessor, MarkupPreprocessor, PreprocessorGroup } from './public.js' */
/** @import { SourceUpdate, Source } from './private.js' */
-/** @import { DecodedSourceMap, RawSourceMap } from '@ampproject/remapping' */
+/** @import { DecodedSourceMap, RawSourceMap } from '@jridgewell/remapping' */
import { getLocator } from 'locate-character';
import {
MappedCode,
@@ -25,7 +25,7 @@ class PreprocessResult {
// sourcemap_list is sorted in reverse order from last map (index 0) to first map (index -1)
// so we use sourcemap_list.unshift() to add new maps
- // https://github.com/ampproject/remapping#multiple-transformations-of-a-file
+ // https://github.com/jridgewell/sourcemaps/tree/main/packages/remapping#multiple-transformations-of-a-file
/**
* @default []
diff --git a/packages/svelte/src/compiler/preprocess/private.d.ts b/packages/svelte/src/compiler/preprocess/private.d.ts
index 5d8c5ed44eff..2c331cee1267 100644
--- a/packages/svelte/src/compiler/preprocess/private.d.ts
+++ b/packages/svelte/src/compiler/preprocess/private.d.ts
@@ -1,4 +1,4 @@
-import { DecodedSourceMap } from '@ampproject/remapping';
+import { DecodedSourceMap } from '@jridgewell/remapping';
import { Location } from 'locate-character';
import { MappedCode } from '../utils/mapped_code.js';
diff --git a/packages/svelte/src/compiler/utils/mapped_code.js b/packages/svelte/src/compiler/utils/mapped_code.js
index f23e3be24519..7686ba59c672 100644
--- a/packages/svelte/src/compiler/utils/mapped_code.js
+++ b/packages/svelte/src/compiler/utils/mapped_code.js
@@ -2,8 +2,8 @@
/** @import { Processed } from '../preprocess/public.js' */
/** @import { SourceMap } from 'magic-string' */
/** @import { Source } from '../preprocess/private.js' */
-/** @import { DecodedSourceMap, SourceMapSegment, RawSourceMap } from '@ampproject/remapping' */
-import remapping from '@ampproject/remapping';
+/** @import { DecodedSourceMap, SourceMapSegment, RawSourceMap } from '@jridgewell/remapping' */
+import remapping from '@jridgewell/remapping';
import { push_array } from './push_array.js';
/**
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 315d699e25ac..cad5fefdf8c6 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -62,9 +62,9 @@ importers:
packages/svelte:
dependencies:
- '@ampproject/remapping':
- specifier: ^2.3.0
- version: 2.3.0
+ '@jridgewell/remapping':
+ specifier: ^2.3.4
+ version: 2.3.4
'@jridgewell/sourcemap-codec':
specifier: ^1.5.0
version: 1.5.0
@@ -457,6 +457,9 @@ packages:
resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
engines: {node: '>=6.0.0'}
+ '@jridgewell/remapping@2.3.4':
+ resolution: {integrity: sha512-aG+WvAz17rhbzhKNkSeMLgbkPPK82ovXdONvmucbGhUqcroRFLLVhoGAk4xEI17gHpXgNX3sr0/B1ybRUsbEWw==}
+
'@jridgewell/resolve-uri@3.1.1':
resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==}
engines: {node: '>=6.0.0'}
@@ -2777,6 +2780,11 @@ snapshots:
'@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/trace-mapping': 0.3.25
+ '@jridgewell/remapping@2.3.4':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
+
'@jridgewell/resolve-uri@3.1.1': {}
'@jridgewell/set-array@1.2.1': {}
From d2ba2589fee2ec6985c0fe0fbd800ab34518378e Mon Sep 17 00:00:00 2001
From: shamokit <91047157+shamokit@users.noreply.github.com>
Date: Sun, 10 Aug 2025 01:26:16 +0900
Subject: [PATCH 5/8] fix: add hint popover (#16581)
* fix: add hint popover
* changeset
---------
Co-authored-by: Rich Harris
---
.changeset/metal-months-fail.md | 5 +++++
packages/svelte/elements.d.ts | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
create mode 100644 .changeset/metal-months-fail.md
diff --git a/.changeset/metal-months-fail.md b/.changeset/metal-months-fail.md
new file mode 100644
index 000000000000..555ec2c0e8d9
--- /dev/null
+++ b/.changeset/metal-months-fail.md
@@ -0,0 +1,5 @@
+---
+"svelte": patch
+---
+
+fix: add `hint` as a possible value for `popover` attribute
diff --git a/packages/svelte/elements.d.ts b/packages/svelte/elements.d.ts
index b3d44d9ed6b4..f63a31a96bd3 100644
--- a/packages/svelte/elements.d.ts
+++ b/packages/svelte/elements.d.ts
@@ -781,7 +781,7 @@ export interface HTMLAttributes extends AriaAttributes, D
title?: string | undefined | null;
translate?: 'yes' | 'no' | '' | undefined | null;
inert?: boolean | undefined | null;
- popover?: 'auto' | 'manual' | '' | undefined | null;
+ popover?: 'auto' | 'manual' | 'hint' | '' | undefined | null;
writingsuggestions?: Booleanish | undefined | null;
// Unknown
From 0480f040c0f220dc090a263e81cfcd4a8db9737f Mon Sep 17 00:00:00 2001
From: Simon H <5968653+dummdidumm@users.noreply.github.com>
Date: Mon, 11 Aug 2025 20:41:34 +0200
Subject: [PATCH 6/8] fix: skip effects inside dynamic component that is about
to be destroyed (#16601)
* fix: skip effects inside dynamic component that is about to be destroyed
When a dynamic component was updated to a different instance and its props were updated at the same time, effects inside the component were still called with the already-changed props.
The fix is to mark the branch as skipped to never got to those effects.
Fixes #16387
* undo accidental commit
---
.changeset/neat-files-do.md | 5 +++++
.../client/dom/blocks/svelte-component.js | 4 +++-
.../svelte-component-props-update/Comp-1.svelte | 7 +++++++
.../svelte-component-props-update/Comp-2.svelte | 1 +
.../svelte-component-props-update/_config.js | 11 +++++++++++
.../svelte-component-props-update/main.svelte | 16 ++++++++++++++++
6 files changed, 43 insertions(+), 1 deletion(-)
create mode 100644 .changeset/neat-files-do.md
create mode 100644 packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-1.svelte
create mode 100644 packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-2.svelte
create mode 100644 packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/_config.js
create mode 100644 packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/main.svelte
diff --git a/.changeset/neat-files-do.md b/.changeset/neat-files-do.md
new file mode 100644
index 000000000000..ddba170c78d1
--- /dev/null
+++ b/.changeset/neat-files-do.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: skip effects inside dynamic component that is about to be destroyed
diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-component.js b/packages/svelte/src/internal/client/dom/blocks/svelte-component.js
index f16da9c42703..2697722b3953 100644
--- a/packages/svelte/src/internal/client/dom/blocks/svelte-component.js
+++ b/packages/svelte/src/internal/client/dom/blocks/svelte-component.js
@@ -62,8 +62,10 @@ export function component(node, get_component, render_fn) {
if (defer) {
offscreen_fragment = document.createDocumentFragment();
offscreen_fragment.append((target = create_text()));
+ if (effect) {
+ /** @type {Batch} */ (current_batch).skipped_effects.add(effect);
+ }
}
-
pending_effect = branch(() => render_fn(target, component));
}
diff --git a/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-1.svelte b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-1.svelte
new file mode 100644
index 000000000000..fdafa27c3cd0
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-1.svelte
@@ -0,0 +1,7 @@
+
+
+{#each data.obj.arr as i}
+
{i}
+{/each}
\ No newline at end of file
diff --git a/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-2.svelte b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-2.svelte
new file mode 100644
index 000000000000..e345a7697c6e
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-2.svelte
@@ -0,0 +1 @@
+
Comp 2
\ No newline at end of file
diff --git a/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/_config.js b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/_config.js
new file mode 100644
index 000000000000..ff5ca12dbf75
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/_config.js
@@ -0,0 +1,11 @@
+import { flushSync } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ async test({ assert, target }) {
+ const [btn] = target.querySelectorAll('button');
+ btn.click();
+ flushSync();
+ assert.htmlEqual(target.innerHTML, `
Comp 2
`);
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/main.svelte b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/main.svelte
new file mode 100644
index 000000000000..abd785fff376
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/main.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+
From ca442e4f54c5335dbe65e51e0a4293f6d7e712a7 Mon Sep 17 00:00:00 2001
From: Simon H <5968653+dummdidumm@users.noreply.github.com>
Date: Mon, 11 Aug 2025 21:18:55 +0200
Subject: [PATCH 7/8] chore: add script to generate test from playground
(#16602)
* chore: add script to generate test from playground
I often play around with stuff locally and then turn it into a test, this automates the last mile of that
* ask if should override
---
playgrounds/sandbox/package.json | 3 +-
playgrounds/sandbox/scripts/create-test.js | 155 +++++++++++++++++++++
2 files changed, 157 insertions(+), 1 deletion(-)
create mode 100644 playgrounds/sandbox/scripts/create-test.js
diff --git a/playgrounds/sandbox/package.json b/playgrounds/sandbox/package.json
index 3ab65ac4b50f..f11da983f60e 100644
--- a/playgrounds/sandbox/package.json
+++ b/playgrounds/sandbox/package.json
@@ -11,7 +11,8 @@
"prod": "npm run build && node dist/server/ssr-prod",
"preview": "vite preview",
"download": "node scripts/download.js",
- "hash": "node scripts/hash.js"
+ "hash": "node scripts/hash.js",
+ "create-test": "node scripts/create-test.js"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^4.0.0-next.6",
diff --git a/playgrounds/sandbox/scripts/create-test.js b/playgrounds/sandbox/scripts/create-test.js
new file mode 100644
index 000000000000..c733f194195b
--- /dev/null
+++ b/playgrounds/sandbox/scripts/create-test.js
@@ -0,0 +1,155 @@
+// Creates a test from the existing playground. cwd needs to be playground/sandbox
+import fs from 'fs';
+import path from 'path';
+
+// Get target folder from command line arguments
+let target_folder = process.argv[2];
+if (!target_folder) {
+ console.error(
+ 'Please provide a target folder as an argument. Example: node create-test.js runtime-runes/my-test'
+ );
+ process.exit(1);
+}
+if (!target_folder.includes('/')) {
+ target_folder = 'runtime-runes/' + target_folder;
+}
+if (!target_folder.startsWith('runtime-')) {
+ console.error(
+ 'Target folder must start with "runtime-" (can only convert to these kinds of tests)'
+ );
+ process.exit(1);
+}
+target_folder = path.join(
+ path.resolve('../../packages/svelte/tests', target_folder.split('/')[0]),
+ 'samples',
+ target_folder.split('/')[1]
+);
+
+const exists = fs.existsSync(target_folder);
+
+// Check if target folder already exists and ask for confirmation
+if (exists) {
+ console.log(`Target folder "${target_folder}" already exists.`);
+ process.stdout.write('Do you want to override the existing test? (Y/n): ');
+
+ // Read user input synchronously
+ const stdin = process.stdin;
+ stdin.setRawMode(true);
+ stdin.resume();
+ stdin.setEncoding('utf8');
+
+ const response = await new Promise((resolve) => {
+ stdin.on('data', (key) => {
+ stdin.setRawMode(false);
+ stdin.pause();
+ process.stdout.write('\n');
+ resolve(key);
+ });
+ });
+
+ if (response.toLowerCase() === 'n') {
+ console.log('Operation cancelled.');
+ process.exit(0);
+ }
+
+ // Clear the existing target folder except for _config.js
+ const files = fs.readdirSync(target_folder);
+ for (const file of files) {
+ if (file !== '_config.js') {
+ const filePath = path.join(target_folder, file);
+ fs.rmSync(filePath, { recursive: true, force: true });
+ }
+ }
+} else {
+ fs.mkdirSync(target_folder, { recursive: true });
+}
+
+// Starting file
+const app_svelte_path = path.resolve('./src/App.svelte');
+const collected_files = new Set();
+const processed_files = new Set();
+
+function collect_imports(file_path) {
+ if (processed_files.has(file_path) || !fs.existsSync(file_path)) {
+ return;
+ }
+
+ processed_files.add(file_path);
+ collected_files.add(file_path);
+
+ const content = fs.readFileSync(file_path, 'utf8');
+
+ // Regex to match import statements
+ const import_regex = /import\s+(?:[^'"]*\s+from\s+)?['"]([^'"]+)['"]/g;
+ let match;
+
+ while ((match = import_regex.exec(content)) !== null) {
+ const import_path = match[1];
+
+ // Skip node_modules imports
+ if (!import_path.startsWith('.')) {
+ continue;
+ }
+
+ // Resolve relative import path
+ const resolved_path = path.resolve(path.dirname(file_path), import_path);
+
+ // Try different extensions if file doesn't exist
+ const extensions = ['', '.svelte', '.js', '.ts'];
+ let actual_path = null;
+
+ for (const ext of extensions) {
+ const test_path = resolved_path + ext;
+ if (fs.existsSync(test_path)) {
+ actual_path = test_path;
+ break;
+ }
+ }
+
+ if (actual_path) {
+ collect_imports(actual_path);
+ }
+ }
+}
+
+// Start collecting from App.svelte
+collect_imports(app_svelte_path);
+
+// Copy collected files to target folder
+for (const file_path of collected_files) {
+ const relative_path = path.relative(path.resolve('./src'), file_path);
+ let target_path = path.join(target_folder, relative_path);
+
+ // Rename App.svelte to main.svelte
+ if (path.basename(file_path) === 'App.svelte') {
+ target_path = path.join(target_folder, path.dirname(relative_path), 'main.svelte');
+ }
+
+ // Ensure target directory exists
+ const target_dir = path.dirname(target_path);
+ if (!fs.existsSync(target_dir)) {
+ fs.mkdirSync(target_dir, { recursive: true });
+ }
+
+ // Copy file
+ fs.copyFileSync(file_path, target_path);
+ console.log(`Copied: ${file_path} -> ${target_path}`);
+}
+
+// Create empty _config.js
+if (!exists) {
+ const config_path = path.join(target_folder, '_config.js');
+ fs.writeFileSync(
+ config_path,
+ `import { test } from '../../test';
+
+export default test({
+ async test({ assert, target }) {
+ }
+});
+`
+ );
+ console.log(`Created: ${config_path}`);
+}
+
+console.log(`\nTest files created in: ${target_folder}`);
From 2e02868ef1d97fd11ed9c13346543f4a8d941953 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Mon, 11 Aug 2025 15:21:31 -0400
Subject: [PATCH 8/8] Version Packages (#16573)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
---
.changeset/khaki-feet-teach.md | 5 -----
.changeset/metal-months-fail.md | 5 -----
.changeset/neat-files-do.md | 5 -----
packages/svelte/CHANGELOG.md | 10 ++++++++++
packages/svelte/package.json | 2 +-
packages/svelte/src/version.js | 2 +-
6 files changed, 12 insertions(+), 17 deletions(-)
delete mode 100644 .changeset/khaki-feet-teach.md
delete mode 100644 .changeset/metal-months-fail.md
delete mode 100644 .changeset/neat-files-do.md
diff --git a/.changeset/khaki-feet-teach.md b/.changeset/khaki-feet-teach.md
deleted file mode 100644
index 51b724428f0a..000000000000
--- a/.changeset/khaki-feet-teach.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'svelte': patch
----
-
-fix: wrap `abort` in `without_reactive_context`
diff --git a/.changeset/metal-months-fail.md b/.changeset/metal-months-fail.md
deleted file mode 100644
index 555ec2c0e8d9..000000000000
--- a/.changeset/metal-months-fail.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"svelte": patch
----
-
-fix: add `hint` as a possible value for `popover` attribute
diff --git a/.changeset/neat-files-do.md b/.changeset/neat-files-do.md
deleted file mode 100644
index ddba170c78d1..000000000000
--- a/.changeset/neat-files-do.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'svelte': patch
----
-
-fix: skip effects inside dynamic component that is about to be destroyed
diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md
index 77f97a1c1192..bb61b50dd559 100644
--- a/packages/svelte/CHANGELOG.md
+++ b/packages/svelte/CHANGELOG.md
@@ -1,5 +1,15 @@
# svelte
+## 5.38.1
+
+### Patch Changes
+
+- fix: wrap `abort` in `without_reactive_context` ([#16570](https://github.com/sveltejs/svelte/pull/16570))
+
+- fix: add `hint` as a possible value for `popover` attribute ([#16581](https://github.com/sveltejs/svelte/pull/16581))
+
+- fix: skip effects inside dynamic component that is about to be destroyed ([#16601](https://github.com/sveltejs/svelte/pull/16601))
+
## 5.38.0
### Minor Changes
diff --git a/packages/svelte/package.json b/packages/svelte/package.json
index 2269d5603f2a..8904c103e31a 100644
--- a/packages/svelte/package.json
+++ b/packages/svelte/package.json
@@ -2,7 +2,7 @@
"name": "svelte",
"description": "Cybernetically enhanced web apps",
"license": "MIT",
- "version": "5.38.0",
+ "version": "5.38.1",
"type": "module",
"types": "./types/index.d.ts",
"engines": {
diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js
index 0bba536c1d72..cf71ae709a5b 100644
--- a/packages/svelte/src/version.js
+++ b/packages/svelte/src/version.js
@@ -4,5 +4,5 @@
* The current version, as set in package.json.
* @type {string}
*/
-export const VERSION = '5.38.0';
+export const VERSION = '5.38.1';
export const PUBLIC_VERSION = '5';