diff --git a/.changeset/clever-files-wash.md b/.changeset/clever-files-wash.md new file mode 100644 index 000000000..6a62c4864 --- /dev/null +++ b/.changeset/clever-files-wash.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixed memleak caused by project dir names containing '.md' or '.mdx' diff --git a/packages/astro/src/core/util.ts b/packages/astro/src/core/util.ts index 14c641de0..01ed44237 100644 --- a/packages/astro/src/core/util.ts +++ b/packages/astro/src/core/util.ts @@ -19,19 +19,10 @@ export function isURL(value: unknown): value is URL { return Object.prototype.toString.call(value) === '[object URL]'; } /** Check if a file is a markdown file based on its extension */ -export function isMarkdownFile( - fileId: string, - option: { criteria: 'endsWith' | 'includes'; suffix?: string } -): boolean { - const _suffix = option.suffix ?? ''; - if (option.criteria === 'endsWith') { - for (let markdownFileExtension of SUPPORTED_MARKDOWN_FILE_EXTENSIONS) { - if (fileId.endsWith(`${markdownFileExtension}${_suffix}`)) return true; - } - return false; - } +export function isMarkdownFile(fileId: string, option?: { suffix?: string }): boolean { + const _suffix = option?.suffix ?? ''; for (let markdownFileExtension of SUPPORTED_MARKDOWN_FILE_EXTENSIONS) { - if (fileId.includes(`${markdownFileExtension}${_suffix}`)) return true; + if (fileId.endsWith(`${markdownFileExtension}${_suffix}`)) return true; } return false; } diff --git a/packages/astro/src/vite-plugin-astro-postprocess/index.ts b/packages/astro/src/vite-plugin-astro-postprocess/index.ts index 514d6834d..c140ad72e 100644 --- a/packages/astro/src/vite-plugin-astro-postprocess/index.ts +++ b/packages/astro/src/vite-plugin-astro-postprocess/index.ts @@ -18,7 +18,7 @@ export default function astro(_opts: AstroPluginOptions): Plugin { name: 'astro:postprocess', async transform(code, id) { // Currently only supported in ".astro" and ".md" (or any alternative markdown file extension like `.markdown`) files - if (!id.endsWith('.astro') && !isMarkdownFile(id, { criteria: 'endsWith' })) { + if (!id.endsWith('.astro') && !isMarkdownFile(id)) { return null; } diff --git a/packages/astro/src/vite-plugin-jsx/index.ts b/packages/astro/src/vite-plugin-jsx/index.ts index bd4f0cde5..e00f2d11d 100644 --- a/packages/astro/src/vite-plugin-jsx/index.ts +++ b/packages/astro/src/vite-plugin-jsx/index.ts @@ -193,7 +193,7 @@ export default function jsx({ settings, logging }: AstroPluginJSXOptions): Plugi const { mode } = viteConfig; // Shortcut: only use Astro renderer for MD and MDX files - if (id.includes('.mdx') || isMarkdownFile(id, { criteria: 'includes' })) { + if (id.endsWith('.mdx')) { const { code: jsxCode } = await esbuild.transform(code, { loader: getEsbuildLoader(path.extname(id)) as esbuild.Loader, jsx: 'preserve', diff --git a/packages/astro/src/vite-plugin-markdown-legacy/index.ts b/packages/astro/src/vite-plugin-markdown-legacy/index.ts index 16b6e3e10..891e8bbea 100644 --- a/packages/astro/src/vite-plugin-markdown-legacy/index.ts +++ b/packages/astro/src/vite-plugin-markdown-legacy/index.ts @@ -90,7 +90,7 @@ export default function markdown({ settings }: AstroPluginOptions): Plugin { // Resolve any .md (or alternative extensions of markdown files like .markdown) files with the `?content` cache buster. This should only come from // an already-resolved JS module wrapper. Needed to prevent infinite loops in Vite. // Unclear if this is expected or if cache busting is just working around a Vite bug. - if (isMarkdownFile(id, { criteria: 'endsWith', suffix: MARKDOWN_CONTENT_FLAG })) { + if (isMarkdownFile(id, { suffix: MARKDOWN_CONTENT_FLAG })) { const resolvedId = await this.resolve(id, importer, { skipSelf: true, ...options }); return resolvedId?.id.replace(MARKDOWN_CONTENT_FLAG, ''); } @@ -98,7 +98,7 @@ export default function markdown({ settings }: AstroPluginOptions): Plugin { // that defers the markdown -> HTML rendering until it is needed. This is especially useful // when fetching and then filtering many markdown files, like with import.meta.glob() or Astro.glob(). // Otherwise, resolve directly to the actual component. - if (isMarkdownFile(id, { criteria: 'endsWith' }) && !isRootImport(importer)) { + if (isMarkdownFile(id) && !isRootImport(importer)) { const resolvedId = await this.resolve(id, importer, { skipSelf: true, ...options }); if (resolvedId) { return resolvedId.id + MARKDOWN_IMPORT_FLAG; @@ -111,7 +111,7 @@ export default function markdown({ settings }: AstroPluginOptions): Plugin { // A markdown file has been imported via ESM! // Return the file's JS representation, including all Markdown // frontmatter and a deferred `import() of the compiled markdown content. - if (isMarkdownFile(id, { criteria: 'endsWith', suffix: MARKDOWN_IMPORT_FLAG })) { + if (isMarkdownFile(id, { suffix: MARKDOWN_IMPORT_FLAG })) { const { fileId, fileUrl } = getFileInfo(id, config); const source = await fs.promises.readFile(fileId, 'utf8'); @@ -151,7 +151,7 @@ export default function markdown({ settings }: AstroPluginOptions): Plugin { // A markdown file is being rendered! This markdown file was either imported // directly as a page in Vite, or it was a deferred render from a JS module. // This returns the compiled markdown -> astro component that renders to HTML. - if (isMarkdownFile(id, { criteria: 'endsWith' })) { + if (isMarkdownFile(id)) { const filename = normalizeFilename(id); const source = await fs.promises.readFile(filename, 'utf8'); const renderOpts = config.markdown; diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts index 6a4e62b9f..c403d21ff 100644 --- a/packages/astro/src/vite-plugin-markdown/index.ts +++ b/packages/astro/src/vite-plugin-markdown/index.ts @@ -59,7 +59,7 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu // passing to the transform hook. This lets us get the truly raw value // to escape "import.meta.env" ourselves. async load(id) { - if (isMarkdownFile(id, { criteria: 'endsWith' })) { + if (isMarkdownFile(id)) { const { fileId, fileUrl } = getFileInfo(id, settings.config); const rawFile = await fs.promises.readFile(fileId, 'utf-8'); const raw = safeMatter(rawFile, id); diff --git a/packages/astro/test/fixtures/impostor-mdx-file/astro.config.mjs b/packages/astro/test/fixtures/impostor-mdx-file/astro.config.mjs new file mode 100644 index 000000000..f03a45258 --- /dev/null +++ b/packages/astro/test/fixtures/impostor-mdx-file/astro.config.mjs @@ -0,0 +1,7 @@ +import { defineConfig } from 'astro/config'; +import react from '@astrojs/react'; + +// https://astro.build/config +export default defineConfig({ + integrations: [react()], +}); \ No newline at end of file diff --git a/packages/astro/test/fixtures/impostor-mdx-file/package.json b/packages/astro/test/fixtures/impostor-mdx-file/package.json new file mode 100644 index 000000000..af59d3cd6 --- /dev/null +++ b/packages/astro/test/fixtures/impostor-mdx-file/package.json @@ -0,0 +1,11 @@ +{ + "name": "@test/impostor-md-file", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/react": "workspace:*", + "astro": "workspace:*", + "react": "^18.1.0", + "react-dom": "^18.1.0" + } +} diff --git a/packages/astro/test/fixtures/impostor-mdx-file/src/components/Foo.mdx.jsx b/packages/astro/test/fixtures/impostor-mdx-file/src/components/Foo.mdx.jsx new file mode 100644 index 000000000..8f935086d --- /dev/null +++ b/packages/astro/test/fixtures/impostor-mdx-file/src/components/Foo.mdx.jsx @@ -0,0 +1,6 @@ +import {useState} from "react"; + +export default function Foo() { + const [bar, setBar] = useState("Baz"); + return