Allow using the Fragment built-in in Astro components (#793)

* Allow using the Fragment built-in in Astro components

* Adds a changeset
This commit is contained in:
Matthew Phillips 2021-07-21 12:26:52 -04:00 committed by GitHub
parent ac64d198e4
commit 4a601adbf2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 2 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Restores the ability to use Fragment in astro components

View file

@ -517,6 +517,17 @@ function dedent(str: string) {
const FALSY_EXPRESSIONS = new Set(['false', 'null', 'undefined', 'void 0']);
function isFrontmatterDefinedComponent(componentName: string, componentInfo: ComponentInfo | undefined, state: CodegenState) {
let hasVariableDeclaration = state.declarations.has(componentName);
let isNotImported = !componentInfo;
return hasVariableDeclaration && isNotImported;
}
function isFragmentComponent(componentName: string) {
return componentName === 'Fragment';
}
/** Compile page markup */
async function compileHtml(enterNode: TemplateNode, state: CodegenState, compileOptions: CompileOptions): Promise<string> {
return new Promise((resolve) => {
@ -658,7 +669,12 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
const [componentNamespace] = componentName.split('.');
componentInfo = components.get(componentNamespace);
}
if (state.declarations.has(componentName) && !componentInfo && !isCustomElementTag(componentName)) {
if (
(
isFrontmatterDefinedComponent(componentName, componentInfo, state) &&
!isCustomElementTag(componentName)
) || isFragmentComponent(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.`
@ -681,7 +697,10 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
buffers[curr] += `h(${componentName}, ${attributes ? generateAttributes(attributes) : 'null'}`;
paren++;
return;
} else if (!state.declarations.has(componentName) && !componentInfo && !isCustomElementTag(componentName)) {
} else if (
!componentInfo &&
!isCustomElementTag(componentName)
) {
throw new Error(`Unable to render "${componentName}" because it is undefined\n ${state.filename}`);
}
if (componentName === 'Markdown') {

View file

@ -95,4 +95,12 @@ Basics('Allows spread attributes with TypeScript (#521)', async ({ runtime }) =>
assert.equal($('#spread-ts').attr('c'), '2');
});
Basics('Allows using the Fragment element to be used', async ({ runtime }) => {
const result = await runtime.load('/fragment');
assert.ok(!result.error, 'No errors thrown');
const html = result.contents;
const $ = doc(html);
assert.equal($('#one').length, 1, 'Element in a fragment rendered');
});
Basics.run();

View file

@ -0,0 +1,12 @@
<html lang="en">
<head>
<title>Fragment test</title>
</head>
<body>
<ul>
<Fragment>
<li id="one">One</li>
</Fragment>
</ul>
</body>
</html>