diff --git a/.changeset/eight-adults-guess.md b/.changeset/eight-adults-guess.md new file mode 100644 index 000000000..8b73fb442 --- /dev/null +++ b/.changeset/eight-adults-guess.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Warn hydration directive for Astro components in JSX diff --git a/packages/astro/src/jsx/babel.ts b/packages/astro/src/jsx/babel.ts index 925e26380..338464b26 100644 --- a/packages/astro/src/jsx/babel.ts +++ b/packages/astro/src/jsx/babel.ts @@ -1,6 +1,7 @@ import type { PluginObj } from '@babel/core'; import * as t from '@babel/types'; import { pathToFileURL } from 'node:url'; +import { HydrationDirectiveProps } from '../runtime/server/hydration.js'; import type { PluginMetadata } from '../vite-plugin-astro/types'; const ClientOnlyPlaceholder = 'astro-client-only'; @@ -280,6 +281,22 @@ export default function astroJSX(): PluginObj { const meta = path.getData('import'); if (meta) { + // If JSX is importing an Astro component, e.g. using MDX for templating, + // check Astro node's props and make sure they are valid for an Astro component + if (meta.path.endsWith('.astro')) { + const displayName = getTagName(parentNode); + for (const attr of parentNode.openingElement.attributes) { + if (t.isJSXAttribute(attr)) { + const name = jsxAttributeToString(attr); + if (HydrationDirectiveProps.has(name)) { + // eslint-disable-next-line + console.warn( + `You are attempting to render <${displayName} ${name} />, but ${displayName} is an Astro component. Astro components do not render in the client and should not have a hydration directive. Please use a framework component for client rendering.` + ); + } + } + } + } let resolvedPath: string; if (meta.path.startsWith('.')) { const fileURL = pathToFileURL(state.filename!);