From 0f458d5abaafaeaaeb15009700e6f7747c8f4121 Mon Sep 17 00:00:00 2001 From: Bao Nguyen <39545125+giaBaoJS@users.noreply.github.com> Date: Tue, 25 Aug 2026 22:43:16 +0700 Subject: [PATCH] fix: report `derived_invalid_export` for `export let x = $derived(...)` (#18692) Fixes #15842 Run the more targeted validations first --------- Co-authored-by: Simon Holthausen --- .changeset/heavy-pumas-report.md | 5 +++++ .../visitors/ExportNamedDeclaration.js | 20 +++++++++---------- .../runes-export-let-derived/_config.js | 9 +++++++++ .../runes-export-let-derived/main.svelte | 4 ++++ 4 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 .changeset/heavy-pumas-report.md create mode 100644 packages/svelte/tests/compiler-errors/samples/runes-export-let-derived/_config.js create mode 100644 packages/svelte/tests/compiler-errors/samples/runes-export-let-derived/main.svelte diff --git a/.changeset/heavy-pumas-report.md b/.changeset/heavy-pumas-report.md new file mode 100644 index 0000000000..71a9422828 --- /dev/null +++ b/.changeset/heavy-pumas-report.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: report `derived_invalid_export` for `export let x = $derived(...)` in runes mode diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/ExportNamedDeclaration.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/ExportNamedDeclaration.js index 5b8d9ba053..dec6ebe2b4 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/ExportNamedDeclaration.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/ExportNamedDeclaration.js @@ -1,4 +1,4 @@ -/** @import { ExportNamedDeclaration, Identifier } from 'estree' */ +/** @import { ExportNamedDeclaration, Identifier, VariableDeclaration } from 'estree' */ /** @import { Context } from '../types' */ import * as e from '../../../errors.js'; import { extract_identifiers } from '../../../utils/ast.js'; @@ -23,15 +23,6 @@ export function ExportNamedDeclaration(node, context) { } if (node.declaration?.type === 'VariableDeclaration') { - // in runes mode, forbid `export let` - if ( - context.state.analysis.runes && - context.state.ast_type === 'instance' && - node.declaration.kind === 'let' - ) { - e.legacy_export_invalid(node); - } - for (const declarator of node.declaration.declarations) { for (const id of extract_identifiers(declarator.id)) { const binding = context.state.scope.get(id.name); @@ -46,6 +37,15 @@ export function ExportNamedDeclaration(node, context) { } } } + + // in runes mode, forbid `export let` + if ( + context.state.analysis.runes && + context.state.ast_type === 'instance' && + node.declaration.kind === 'let' + ) { + e.legacy_export_invalid(node); + } } if (context.state.analysis.runes) { diff --git a/packages/svelte/tests/compiler-errors/samples/runes-export-let-derived/_config.js b/packages/svelte/tests/compiler-errors/samples/runes-export-let-derived/_config.js new file mode 100644 index 0000000000..852f56ebcc --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/runes-export-let-derived/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + error: { + code: 'derived_invalid_export', + message: + 'Cannot export derived state from a module. To expose the current derived value, export a function returning its value' + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/runes-export-let-derived/main.svelte b/packages/svelte/tests/compiler-errors/samples/runes-export-let-derived/main.svelte new file mode 100644 index 0000000000..512caf75f8 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/runes-export-let-derived/main.svelte @@ -0,0 +1,4 @@ +