Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/khaki-wolves-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/cloudflare': patch
---

Fixes an issue where existing KV namespace bindings were silently removed when session support was enabled.
8 changes: 3 additions & 5 deletions packages/astro/src/vite-plugin-astro/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { AstroLogger } from '../core/logger/core.js';
import type { AstroConfig } from '../types/public/config.js';
import { getFileInfo } from '../vite-plugin-utils/index.js';
import type { CompileMetadata } from './types.js';
import { frontmatterRE } from './utils.js';
import { frontmatterRE, replaceTopLevelReturns } from './utils.js';
import type { SourceMapInput } from 'rollup';

interface CompileAstroOption {
Expand Down Expand Up @@ -109,10 +109,8 @@ async function enhanceCompileError({
// If frontmatter is valid or cannot be parsed, then continue.
const scannedFrontmatter = frontmatterRE.exec(source);
if (scannedFrontmatter) {
// Top-level return is not supported, so replace `return` with throw
const frontmatter = scannedFrontmatter[1]
.replace(/\breturn\s*;/g, 'throw 0;')
.replace(/\breturn\b/g, 'throw ');
// Top-level return is not supported, so replace `return` with `throw`.
const frontmatter = replaceTopLevelReturns(scannedFrontmatter[1]);

// If frontmatter does not actually include the offending line, skip
if (lineText && !frontmatter.includes(lineText)) throw err;
Expand Down
13 changes: 13 additions & 0 deletions packages/astro/src/vite-plugin-astro/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ import type { PluginContainer } from 'vite';

export const frontmatterRE = /^---(.*?)^---/ms;

// Matches tokens to skip (strings, template literals, comments) OR a top-level `return`.
// The first alternative is preserved as-is; only the second is rewritten.
// Negative lookbehind `(?<!\.)` prevents matching member accesses like `gen.return()`.
const RETURN_REPLACE_RE =
/(\/\/[^\n]*|\/\*[\s\S]*?\*\/|`(?:[^`\\]|\\.)*`|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')|(?<!\.)\breturn(\s*;|\b)/g;

export function replaceTopLevelReturns(code: string): string {
return code.replace(RETURN_REPLACE_RE, (_match, skip: string | undefined, tail: string) => {
if (skip !== undefined) return skip;
return tail.trim() === ';' ? 'throw 0;' : 'throw ';
});
}

export async function loadId(pluginContainer: PluginContainer, id: string) {
const result = await pluginContainer.load(id, { ssr: true });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ import type { DepOptimizationConfig } from 'vite';

const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---/;

// Matches tokens to skip (strings, template literals, comments) OR a top-level `return`.
// The first alternative is preserved as-is; only the second is rewritten.
// Negative lookbehind `(?<!\.)` prevents matching member accesses like `gen.return()`.
const RETURN_REPLACE_RE =
/(\/\/[^\n]*|\/\*[\s\S]*?\*\/|`(?:[^`\\]|\\.)*`|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')|(?<!\.)\breturn(\s*;|\b)/g;

function replaceTopLevelReturns(code: string): string {
return code.replace(RETURN_REPLACE_RE, (_match, skip: string | undefined, tail: string) => {
if (skip !== undefined) return skip;
return tail.trim() === ';' ? 'throw 0;' : 'throw ';
});
}

// Not exposed as a type from Vite, so need to grab this way.
type ESBuildPlugin = NonNullable<
NonNullable<DepOptimizationConfig['esbuildOptions']>['plugins']
Expand All @@ -27,12 +40,7 @@ export function astroFrontmatterScanPlugin(): ESBuildPlugin {
// Replace `return` with `throw` to avoid esbuild's "Top-level return" error during scanning.
// This aligns with Astro's core compiler logic for frontmatter error handling.
// See: packages/astro/src/vite-plugin-astro/compile.ts
//
// Known Limitation: Using regex /\breturn\b/ will incorrectly match
// identifiers like `$return` or aliases like `import { return as ret }`.
const contents = frontmatterMatch[1]
.replace(/\breturn\s*;/g, 'throw 0;')
.replace(/\breturn\b/g, 'throw ');
const contents = replaceTopLevelReturns(frontmatterMatch[1]);

// Append `export default {}` so that default imports of .astro files
// (e.g. `import MyComponent from './MyComponent.astro'`) resolve correctly
Expand Down
Loading