From 4947283fa5547691adcb129e145eed77c38f39fc Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 16 Jul 2025 12:08:45 -0400 Subject: [PATCH 1/3] fix: avoid microtask in flushSync (#16394) * fix: avoid microtask in flushSync * fix/simplify * on second thoughts * changeset --- .changeset/soft-moles-work.md | 5 +++++ .../src/internal/client/reactivity/batch.js | 20 ++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 .changeset/soft-moles-work.md diff --git a/.changeset/soft-moles-work.md b/.changeset/soft-moles-work.md new file mode 100644 index 000000000000..c3573e4bc5bb --- /dev/null +++ b/.changeset/soft-moles-work.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: avoid microtask in flushSync diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index f881330e90df..1d08b5c3d82b 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -416,19 +416,21 @@ export class Batch { return (this.#deferred ??= deferred()).promise; } - static ensure() { + static ensure(autoflush = true) { if (current_batch === null) { const batch = (current_batch = new Batch()); batches.add(current_batch); - queueMicrotask(() => { - if (current_batch !== batch) { - // a flushSync happened in the meantime - return; - } + if (autoflush) { + queueMicrotask(() => { + if (current_batch !== batch) { + // a flushSync happened in the meantime + return; + } - batch.flush(); - }); + batch.flush(); + }); + } } return current_batch; @@ -449,7 +451,7 @@ export function flushSync(fn) { var result; - const batch = Batch.ensure(); + const batch = Batch.ensure(false); if (fn) { batch.flush_effects(); From ee1ef6083ad9fad44c677192d3dafefb4d731f1e Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Wed, 16 Jul 2025 18:20:44 +0200 Subject: [PATCH 2/3] fix: ensure compiler state is reset before compilation (#16396) #16268 introduced a slight regression where the state is not reset completely upon compilation. It did reset warnings but not other state, which meant if file A succeeds but file B fails in the parsing state (before the state was reset for real) it would get wrong filename info. This fixes it by setting the filename at the very beginning. --- .changeset/two-terms-draw.md | 5 +++ packages/svelte/src/compiler/index.js | 6 +-- packages/svelte/src/compiler/migrate/index.js | 6 +-- .../src/compiler/phases/2-analyze/index.js | 8 ++-- .../phases/2-analyze/visitors/SvelteSelf.js | 6 +-- packages/svelte/src/compiler/state.js | 37 ++++++++++++------- .../src/compiler/utils/compile_diagnostic.js | 2 +- packages/svelte/tests/compiler-errors/test.ts | 14 ++++++- 8 files changed, 55 insertions(+), 29 deletions(-) create mode 100644 .changeset/two-terms-draw.md diff --git a/.changeset/two-terms-draw.md b/.changeset/two-terms-draw.md new file mode 100644 index 000000000000..88ef4be86e6e --- /dev/null +++ b/.changeset/two-terms-draw.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure compiler state is reset before compilation diff --git a/packages/svelte/src/compiler/index.js b/packages/svelte/src/compiler/index.js index 9ba23c148595..a378af34eedc 100644 --- a/packages/svelte/src/compiler/index.js +++ b/packages/svelte/src/compiler/index.js @@ -20,7 +20,7 @@ export { default as preprocess } from './preprocess/index.js'; */ export function compile(source, options) { source = remove_bom(source); - state.reset_warnings(options.warningFilter); + state.reset({ warning: options.warningFilter, filename: options.filename }); const validated = validate_component_options(options, ''); let parsed = _parse(source); @@ -63,7 +63,7 @@ export function compile(source, options) { */ export function compileModule(source, options) { source = remove_bom(source); - state.reset_warnings(options.warningFilter); + state.reset({ warning: options.warningFilter, filename: options.filename }); const validated = validate_module_options(options, ''); const analysis = analyze_module(source, validated); @@ -111,7 +111,7 @@ export function compileModule(source, options) { */ export function parse(source, { modern, loose } = {}) { source = remove_bom(source); - state.reset_warnings(() => false); + state.reset({ warning: () => false, filename: undefined }); const ast = _parse(source, loose); return to_public_ast(source, ast, modern); diff --git a/packages/svelte/src/compiler/migrate/index.js b/packages/svelte/src/compiler/migrate/index.js index 0e2fe019ed34..6b2e6cda70a4 100644 --- a/packages/svelte/src/compiler/migrate/index.js +++ b/packages/svelte/src/compiler/migrate/index.js @@ -9,7 +9,7 @@ import { parse } from '../phases/1-parse/index.js'; import { regex_valid_component_name } from '../phases/1-parse/state/element.js'; import { analyze_component } from '../phases/2-analyze/index.js'; import { get_rune } from '../phases/scope.js'; -import { reset, reset_warnings } from '../state.js'; +import { reset, UNKNOWN_FILENAME } from '../state.js'; import { extract_identifiers, extract_all_identifiers_from_expression, @@ -134,7 +134,7 @@ export function migrate(source, { filename, use_ts } = {}) { return start + style_placeholder + end; }); - reset_warnings(() => false); + reset({ warning: () => false, filename }); let parsed = parse(source); @@ -145,7 +145,7 @@ export function migrate(source, { filename, use_ts } = {}) { ...validate_component_options({}, ''), ...parsed_options, customElementOptions, - filename: filename ?? '(unknown)', + filename: filename ?? UNKNOWN_FILENAME, experimental: { async: true } diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 258b59018a6c..d407b4455639 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -279,9 +279,8 @@ export function analyze_module(source, options) { classes: new Map() }; - state.reset({ + state.adjust({ dev: options.dev, - filename: options.filename, rootDir: options.rootDir, runes: true }); @@ -531,12 +530,11 @@ export function analyze_component(root, source, options) { async_deriveds: new Set() }; - state.reset({ + state.adjust({ component_name: analysis.name, dev: options.dev, - filename: options.filename, rootDir: options.rootDir, - runes: true + runes }); if (!runes) { diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/SvelteSelf.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/SvelteSelf.js index b87f082de0ea..652a447165c8 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/SvelteSelf.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/SvelteSelf.js @@ -3,7 +3,7 @@ import { visit_component } from './shared/component.js'; import * as e from '../../../errors.js'; import * as w from '../../../warnings.js'; -import { filename } from '../../../state.js'; +import { filename, UNKNOWN_FILENAME } from '../../../state.js'; /** * @param {AST.SvelteSelf} node @@ -23,9 +23,9 @@ export function SvelteSelf(node, context) { } if (context.state.analysis.runes) { - const name = filename === '(unknown)' ? 'Self' : context.state.analysis.name; + const name = filename === UNKNOWN_FILENAME ? 'Self' : context.state.analysis.name; const basename = - filename === '(unknown)' + filename === UNKNOWN_FILENAME ? 'Self.svelte' : /** @type {string} */ (filename.split(/[/\\]/).pop()); diff --git a/packages/svelte/src/compiler/state.js b/packages/svelte/src/compiler/state.js index 5eb25dd6bb15..725d03b802de 100644 --- a/packages/svelte/src/compiler/state.js +++ b/packages/svelte/src/compiler/state.js @@ -16,6 +16,11 @@ export let warnings = []; */ export let filename; +/** + * This is the fallback used when no filename is specified. + */ +export const UNKNOWN_FILENAME = '(unknown)'; + /** * The name of the component that is used in the `export default function ...` statement. */ @@ -80,15 +85,6 @@ export function pop_ignore() { ignore_stack.pop(); } -/** - * - * @param {(warning: Warning) => boolean} fn - */ -export function reset_warnings(fn = () => true) { - warning_filter = fn; - warnings = []; -} - /** * @param {AST.SvelteNode | NodeLike} node * @param {import('../constants.js').IGNORABLE_RUNTIME_WARNINGS[number]} code @@ -99,21 +95,36 @@ export function is_ignored(node, code) { } /** + * Call this to reset the compiler state. Should be called before each compilation. + * @param {{ warning?: (warning: Warning) => boolean; filename: string | undefined }} state + */ +export function reset(state) { + dev = false; + runes = false; + component_name = UNKNOWN_FILENAME; + source = ''; + locator = () => undefined; + filename = (state.filename ?? UNKNOWN_FILENAME).replace(/\\/g, '/'); + warning_filter = state.warning ?? (() => true); + warnings = []; +} + +/** + * Adjust the compiler state based on the provided state object. + * Call this after parsing and basic analysis happened. * @param {{ * dev: boolean; - * filename: string; * component_name?: string; * rootDir?: string; * runes: boolean; * }} state */ -export function reset(state) { +export function adjust(state) { const root_dir = state.rootDir?.replace(/\\/g, '/'); - filename = state.filename.replace(/\\/g, '/'); dev = state.dev; runes = state.runes; - component_name = state.component_name ?? '(unknown)'; + component_name = state.component_name ?? UNKNOWN_FILENAME; if (typeof root_dir === 'string' && filename.startsWith(root_dir)) { // make filename relative to rootDir diff --git a/packages/svelte/src/compiler/utils/compile_diagnostic.js b/packages/svelte/src/compiler/utils/compile_diagnostic.js index db938cf2bdb3..c5df49e01cee 100644 --- a/packages/svelte/src/compiler/utils/compile_diagnostic.js +++ b/packages/svelte/src/compiler/utils/compile_diagnostic.js @@ -61,7 +61,7 @@ export class CompileDiagnostic { this.code = code; this.message = message; - if (state.filename) { + if (state.filename !== state.UNKNOWN_FILENAME) { this.filename = state.filename; } diff --git a/packages/svelte/tests/compiler-errors/test.ts b/packages/svelte/tests/compiler-errors/test.ts index 5e57a3a03286..13b9280dde4f 100644 --- a/packages/svelte/tests/compiler-errors/test.ts +++ b/packages/svelte/tests/compiler-errors/test.ts @@ -1,5 +1,5 @@ import * as fs from 'node:fs'; -import { assert, expect } from 'vitest'; +import { assert, expect, it } from 'vitest'; import { compile, compileModule, type CompileError } from 'svelte/compiler'; import { suite, type BaseTest } from '../suite'; import { read_file } from '../helpers.js'; @@ -78,3 +78,15 @@ const { test, run } = suite((config, cwd) => { export { test }; await run(__dirname); + +it('resets the compiler state including filename', () => { + // start with something that succeeds + compile('
hello
', { filename: 'foo.svelte' }); + // then try something that fails in the parsing stage + try { + compile('

hello

invalid

', { filename: 'bar.svelte' }); + expect.fail('Expected an error'); + } catch (e: any) { + expect(e.toString()).toContain('bar.svelte'); + } +}); From 58788db27b33f2c86a649d603bc328fa330e8f6b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Jul 2025 12:42:25 -0400 Subject: [PATCH 3/3] Version Packages (#16397) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/soft-moles-work.md | 5 ----- .changeset/two-terms-draw.md | 5 ----- packages/svelte/CHANGELOG.md | 8 ++++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 5 files changed, 10 insertions(+), 12 deletions(-) delete mode 100644 .changeset/soft-moles-work.md delete mode 100644 .changeset/two-terms-draw.md diff --git a/.changeset/soft-moles-work.md b/.changeset/soft-moles-work.md deleted file mode 100644 index c3573e4bc5bb..000000000000 --- a/.changeset/soft-moles-work.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: avoid microtask in flushSync diff --git a/.changeset/two-terms-draw.md b/.changeset/two-terms-draw.md deleted file mode 100644 index 88ef4be86e6e..000000000000 --- a/.changeset/two-terms-draw.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: ensure compiler state is reset before compilation diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 2ea2f58de85b..6d4f31480d6e 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,13 @@ # svelte +## 5.36.4 + +### Patch Changes + +- fix: avoid microtask in flushSync ([#16394](https://github.com/sveltejs/svelte/pull/16394)) + +- fix: ensure compiler state is reset before compilation ([#16396](https://github.com/sveltejs/svelte/pull/16396)) + ## 5.36.3 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 119c4142cfda..3e9022a0910f 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.36.3", + "version": "5.36.4", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index e8b0e6f1ee71..f8d23b44b1e5 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.36.3'; +export const VERSION = '5.36.4'; export const PUBLIC_VERSION = '5'; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy