diff --git a/.changeset/twelve-lions-tie.md b/.changeset/twelve-lions-tie.md new file mode 100644 index 000000000..2010637ca --- /dev/null +++ b/.changeset/twelve-lions-tie.md @@ -0,0 +1,14 @@ +--- +'astro': patch +--- + +Add support for components defined in Frontmatter. Previously, the following code would throw an error. Now it is officially supported! + +```astro +--- +const { level = 1 } = Astro.props; +const Element = `h${level}`; +--- + +Hello world! +``` diff --git a/packages/astro/src/compiler/codegen/index.ts b/packages/astro/src/compiler/codegen/index.ts index 7bfb55f53..6a5b5e546 100644 --- a/packages/astro/src/compiler/codegen/index.ts +++ b/packages/astro/src/compiler/codegen/index.ts @@ -688,7 +688,21 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile componentInfo = components.get(componentNamespace); } if (!componentInfo && !isCustomElementTag(componentName)) { - throw new Error(`Unknown Component: ${componentName}`); + if (hydrationAttributes.method) { + throw new Error(`Unable to hydrate "${componentName}" because it is statically defined in the frontmatter script. Hydration directives may only be used on imported components.`); + } + + // Previously we would throw here, but this is valid! + // If the frontmatter script defines `const Element = 'h1'`, + // you should be able to statically render `` + + if (curr === 'markdown') { + await pushMarkdownToBuffer(); + } + + paren++; + buffers[curr] += `h(${componentName}, ${attributes ? generateAttributes(attributes) : 'null'}`; + return; } if (componentName === 'Markdown') { const { $scope } = attributes ?? {}; diff --git a/packages/astro/test/astro-basic.test.js b/packages/astro/test/astro-basic.test.js index 38f62085e..c2051b3eb 100644 --- a/packages/astro/test/astro-basic.test.js +++ b/packages/astro/test/astro-basic.test.js @@ -95,4 +95,12 @@ Basics('Allows spread attributes with TypeScript (#521)', async ({ runtime }) => assert.equal($('#spread-ts').attr('c'), '2'); }); +Basics('Allows Components defined in frontmatter', async ({ runtime }) => { + const result = await runtime.load('/frontmatter-component'); + const html = result.contents; + const $ = doc(html); + + assert.equal($('h1').length, 1); +}); + Basics.run(); diff --git a/packages/astro/test/fixtures/astro-basic/src/pages/frontmatter-component.astro b/packages/astro/test/fixtures/astro-basic/src/pages/frontmatter-component.astro new file mode 100644 index 000000000..69f708505 --- /dev/null +++ b/packages/astro/test/fixtures/astro-basic/src/pages/frontmatter-component.astro @@ -0,0 +1,6 @@ +--- +const { level = 1 } = Astro.props; +const Element = `h${level}`; +--- + +Hello world!