feat: improve handling of undefined components (#650)
This commit is contained in:
parent
fb78b76cc6
commit
5077ff2e11
5 changed files with 41 additions and 11 deletions
|
@ -309,6 +309,7 @@ interface CodegenState {
|
|||
markers: {
|
||||
insideMarkdown: boolean | Record<string, any>;
|
||||
};
|
||||
declarations: Set<string>;
|
||||
exportStatements: Set<string>;
|
||||
importStatements: Set<string>;
|
||||
customElementCandidates: Map<string, string>;
|
||||
|
@ -375,6 +376,9 @@ function compileModule(ast: Ast, module: Script, state: CodegenState, compileOpt
|
|||
break;
|
||||
}
|
||||
case 'FunctionDeclaration': {
|
||||
if (node.id?.name) {
|
||||
state.declarations.add(node.id?.name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'ImportDeclaration': {
|
||||
|
@ -384,8 +388,14 @@ function compileModule(ast: Ast, module: Script, state: CodegenState, compileOpt
|
|||
}
|
||||
case 'VariableDeclaration': {
|
||||
for (const declaration of node.declarations) {
|
||||
// only select Astro.fetchContent() calls here. this utility filters those out for us.
|
||||
if (!isFetchContent(declaration)) continue;
|
||||
// only select Astro.fetchContent() calls for more processing,
|
||||
// otherwise just push name to declarations
|
||||
if (!isFetchContent(declaration)) {
|
||||
if (declaration.id.type === 'Identifier') {
|
||||
state.declarations.add(declaration.id.name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// remove node
|
||||
body.splice(i, 1);
|
||||
|
@ -687,7 +697,7 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
|
|||
const [componentNamespace] = componentName.split('.');
|
||||
componentInfo = components.get(componentNamespace);
|
||||
}
|
||||
if (!componentInfo && !isCustomElementTag(componentName)) {
|
||||
if (state.declarations.has(componentName) && !componentInfo && !isCustomElementTag(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.`
|
||||
|
@ -705,6 +715,8 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
|
|||
paren++;
|
||||
buffers[curr] += `h(${componentName}, ${attributes ? generateAttributes(attributes) : 'null'}`;
|
||||
return;
|
||||
} else if (!state.declarations.has(componentName) && !componentInfo && !isCustomElementTag(componentName)) {
|
||||
throw new Error(`Unable to render "${componentName}" because it is undefined\n ${state.filename}`)
|
||||
}
|
||||
if (componentName === 'Markdown') {
|
||||
const { $scope } = attributes ?? {};
|
||||
|
@ -870,6 +882,7 @@ export async function codegen(ast: Ast, { compileOptions, filename, fileID }: Co
|
|||
markers: {
|
||||
insideMarkdown: false,
|
||||
},
|
||||
declarations: new Set(),
|
||||
importStatements: new Set(),
|
||||
exportStatements: new Set(),
|
||||
customElementCandidates: new Map(),
|
||||
|
|
|
@ -95,12 +95,4 @@ 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();
|
||||
|
|
|
@ -26,4 +26,18 @@ Components('Astro components are able to render framework components', async ({
|
|||
assert.not.type($svelte, 'undefined', 'Renders Svelte component');
|
||||
});
|
||||
|
||||
|
||||
Components('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);
|
||||
});
|
||||
|
||||
Components('Still throws an error for undefined components', async ({ runtime }) => {
|
||||
const result = await runtime.load('/undefined-component');
|
||||
assert.equal(result.statusCode, 500);
|
||||
});
|
||||
|
||||
Components.run();
|
||||
|
|
11
packages/astro/test/fixtures/astro-components/src/pages/undefined-component.astro
vendored
Normal file
11
packages/astro/test/fixtures/astro-components/src/pages/undefined-component.astro
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
function FnComponent() {
|
||||
const lame = 'ugh';
|
||||
return <h2>Hey</h2>
|
||||
}
|
||||
const Defined = 'h1'
|
||||
---
|
||||
|
||||
<FnComponent />
|
||||
<Defined>Hello world!</Defined>
|
||||
<Undefined />
|
Loading…
Reference in a new issue