diff --git a/.changeset/wild-mice-battle.md b/.changeset/wild-mice-battle.md new file mode 100644 index 0000000000000..a20c38cd2ba5c --- /dev/null +++ b/.changeset/wild-mice-battle.md @@ -0,0 +1,5 @@ +--- +"@astrojs/mdx": patch +--- + +Omitting compiler-internal symbol from user components to fix breaking error messages diff --git a/packages/astro/src/runtime/server/jsx.ts b/packages/astro/src/runtime/server/jsx.ts index 81bae422f09a7..b035d2b12c0b5 100644 --- a/packages/astro/src/runtime/server/jsx.ts +++ b/packages/astro/src/runtime/server/jsx.ts @@ -84,6 +84,8 @@ Did you forget to import the component or is it possible there is a typo?`); } if (typeof vnode.type === 'function') { if (vnode.props[hasTriedRenderComponentSymbol]) { + // omitting compiler-internals from user components + delete vnode.props[hasTriedRenderComponentSymbol]; const output = await vnode.type(vnode.props ?? {}); if (output?.[AstroJSX] || !output) { return await renderJSXVNode(result, output); diff --git a/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/astro.config.mjs b/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/astro.config.mjs new file mode 100644 index 0000000000000..2905fe4766ea0 --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/astro.config.mjs @@ -0,0 +1,6 @@ +import mdx from '@astrojs/mdx'; +import react from '@astrojs/react'; + +export default { + integrations: [mdx(), react()], +} diff --git a/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/package.json b/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/package.json new file mode 100644 index 0000000000000..d506c067d1881 --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/package.json @@ -0,0 +1,11 @@ +{ + "name": "@test/mdx-plus-react-errors", + "private": true, + "dependencies": { + "@astrojs/mdx": "workspace:*", + "@astrojs/react": "workspace:*", + "astro": "workspace:*", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } +} diff --git a/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/src/components/BrokenComponent.jsx b/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/src/components/BrokenComponent.jsx new file mode 100644 index 0000000000000..f9091c825fb66 --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/src/components/BrokenComponent.jsx @@ -0,0 +1,8 @@ +import { useState } from "react"; + +export default function BrokenComponent() { + useState(0); + a; + + return

Whoops!

; +}; diff --git a/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/src/content/config.js b/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/src/content/config.js new file mode 100644 index 0000000000000..6250d13c81881 --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/src/content/config.js @@ -0,0 +1,12 @@ +import { z, defineCollection } from "astro:content"; + +const filesSchema = () => { + return z.object({}); +}; + +const filesCollection = defineCollection({ + type: "content", + schema: filesSchema(), +}); + +export const collections = { files: filesCollection, }; diff --git a/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/src/content/files/file.mdx b/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/src/content/files/file.mdx new file mode 100644 index 0000000000000..9c536e9fff1b3 --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/src/content/files/file.mdx @@ -0,0 +1,4 @@ + +import BrokenComponent from '../../components/BrokenComponent' + + diff --git a/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/src/pages/broken.astro b/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/src/pages/broken.astro new file mode 100644 index 0000000000000..bee4c85b53311 --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/mdx-plus-react-errors/src/pages/broken.astro @@ -0,0 +1,9 @@ +--- +import { getCollection } from "astro:content"; +const files = await getCollection("files"); + +const { Content } = await files[0].render(); +--- + + + diff --git a/packages/integrations/mdx/test/mdx-plus-react-errors.test.js b/packages/integrations/mdx/test/mdx-plus-react-errors.test.js new file mode 100644 index 0000000000000..9d87fa8a0045f --- /dev/null +++ b/packages/integrations/mdx/test/mdx-plus-react-errors.test.js @@ -0,0 +1,33 @@ +import * as assert from 'node:assert/strict'; +import { describe, it } from 'node:test'; +import { loadFixture } from '../../../astro/test/test-utils.js'; + +function hookError() { + const error = console.error; + const errors = []; + console.error = function (...args) { + errors.push(args); + }; + return () => { + console.error = error; + return errors; + }; +} + +describe('MDX and React with build errors', () => { + let fixture; + let unhook; + + it('shows correct error messages on build error', async () => { + try { + fixture = await loadFixture({ + root: new URL('./fixtures/mdx-plus-react-errors/', import.meta.url), + }); + unhook = hookError(); + await fixture.build(); + } catch (err) { + assert.equal(err.message, 'a is not defined'); + } + unhook(); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b6cc11abef61..0a2cf217d52c1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4613,6 +4613,24 @@ importers: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) + packages/integrations/mdx/test/fixtures/mdx-plus-react-errors: + dependencies: + '@astrojs/mdx': + specifier: workspace:* + version: link:../../.. + '@astrojs/react': + specifier: workspace:* + version: link:../../../../react + astro: + specifier: workspace:* + version: link:../../../../../astro + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + packages/integrations/mdx/test/fixtures/mdx-vite-env-vars: dependencies: '@astrojs/mdx':