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: {
|
markers: {
|
||||||
insideMarkdown: boolean | Record<string, any>;
|
insideMarkdown: boolean | Record<string, any>;
|
||||||
};
|
};
|
||||||
|
declarations: Set<string>;
|
||||||
exportStatements: Set<string>;
|
exportStatements: Set<string>;
|
||||||
importStatements: Set<string>;
|
importStatements: Set<string>;
|
||||||
customElementCandidates: Map<string, string>;
|
customElementCandidates: Map<string, string>;
|
||||||
|
@ -375,6 +376,9 @@ function compileModule(ast: Ast, module: Script, state: CodegenState, compileOpt
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'FunctionDeclaration': {
|
case 'FunctionDeclaration': {
|
||||||
|
if (node.id?.name) {
|
||||||
|
state.declarations.add(node.id?.name);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ImportDeclaration': {
|
case 'ImportDeclaration': {
|
||||||
|
@ -384,8 +388,14 @@ function compileModule(ast: Ast, module: Script, state: CodegenState, compileOpt
|
||||||
}
|
}
|
||||||
case 'VariableDeclaration': {
|
case 'VariableDeclaration': {
|
||||||
for (const declaration of node.declarations) {
|
for (const declaration of node.declarations) {
|
||||||
// only select Astro.fetchContent() calls here. this utility filters those out for us.
|
// only select Astro.fetchContent() calls for more processing,
|
||||||
if (!isFetchContent(declaration)) continue;
|
// otherwise just push name to declarations
|
||||||
|
if (!isFetchContent(declaration)) {
|
||||||
|
if (declaration.id.type === 'Identifier') {
|
||||||
|
state.declarations.add(declaration.id.name);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// remove node
|
// remove node
|
||||||
body.splice(i, 1);
|
body.splice(i, 1);
|
||||||
|
@ -687,7 +697,7 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
|
||||||
const [componentNamespace] = componentName.split('.');
|
const [componentNamespace] = componentName.split('.');
|
||||||
componentInfo = components.get(componentNamespace);
|
componentInfo = components.get(componentNamespace);
|
||||||
}
|
}
|
||||||
if (!componentInfo && !isCustomElementTag(componentName)) {
|
if (state.declarations.has(componentName) && !componentInfo && !isCustomElementTag(componentName)) {
|
||||||
if (hydrationAttributes.method) {
|
if (hydrationAttributes.method) {
|
||||||
throw new Error(
|
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.`
|
`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++;
|
paren++;
|
||||||
buffers[curr] += `h(${componentName}, ${attributes ? generateAttributes(attributes) : 'null'}`;
|
buffers[curr] += `h(${componentName}, ${attributes ? generateAttributes(attributes) : 'null'}`;
|
||||||
return;
|
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') {
|
if (componentName === 'Markdown') {
|
||||||
const { $scope } = attributes ?? {};
|
const { $scope } = attributes ?? {};
|
||||||
|
@ -870,6 +882,7 @@ export async function codegen(ast: Ast, { compileOptions, filename, fileID }: Co
|
||||||
markers: {
|
markers: {
|
||||||
insideMarkdown: false,
|
insideMarkdown: false,
|
||||||
},
|
},
|
||||||
|
declarations: new Set(),
|
||||||
importStatements: new Set(),
|
importStatements: new Set(),
|
||||||
exportStatements: new Set(),
|
exportStatements: new Set(),
|
||||||
customElementCandidates: new Map(),
|
customElementCandidates: new Map(),
|
||||||
|
|
|
@ -95,12 +95,4 @@ Basics('Allows spread attributes with TypeScript (#521)', async ({ runtime }) =>
|
||||||
assert.equal($('#spread-ts').attr('c'), '2');
|
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();
|
Basics.run();
|
||||||
|
|
|
@ -26,4 +26,18 @@ Components('Astro components are able to render framework components', async ({
|
||||||
assert.not.type($svelte, 'undefined', 'Renders Svelte component');
|
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();
|
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