From 9f27941b4f0d2fa823721970e5d9ea634ba4431d Mon Sep 17 00:00:00 2001 From: Jonathan Neal Date: Fri, 28 Jan 2022 18:19:55 -0500 Subject: [PATCH] Render Custom Element Tag (#2473) * Support rendering web components * nit: remove addition of script --- packages/astro/src/runtime/server/index.ts | 33 +++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/astro/src/runtime/server/index.ts b/packages/astro/src/runtime/server/index.ts index 633f41957b..e94de7732e 100644 --- a/packages/astro/src/runtime/server/index.ts +++ b/packages/astro/src/runtime/server/index.ts @@ -148,7 +148,7 @@ export async function renderComponent(result: SSRResult, displayName: string, Co } const probableRendererNames = guessRenderers(metadata.componentUrl); - if (Array.isArray(renderers) && renderers.length === 0 && typeof Component !== 'string') { + if (Array.isArray(renderers) && renderers.length === 0 && typeof Component !== 'string' && !HTMLElement.isPrototypeOf(Component as object)) { const message = `Unable to render ${metadata.displayName}! There are no \`renderers\` set in your \`astro.config.mjs\` file. @@ -165,6 +165,12 @@ Did you mean to enable ${formatList(probableRendererNames.map((r) => '`' + r + ' break; } } + + if (!renderer && HTMLElement.isPrototypeOf(Component as object)) { + const output = renderHTMLElement(result, Component as typeof HTMLElement, _props, slots); + + return output; + } } else { // Attempt: use explicitly passed renderer name if (metadata.hydrateArgs) { @@ -434,6 +440,31 @@ export async function renderAstroComponent(component: InstanceType${children}`; + + return html; +} + +function getHTMLElementName(constructor: typeof HTMLElement) { + const definedName = (customElements as CustomElementRegistry & { getName(_constructor: typeof HTMLElement): string }).getName(constructor); + if (definedName) return definedName + + const assignedName = constructor.name.replace(/^HTML|Element$/g, '').replace(/[A-Z]/g, '-$&').toLowerCase().replace(/^-/, 'html-') + return assignedName +} + function renderElement(name: string, { props: _props, children = '' }: SSRElement) { // Do not print `hoist`, `lang`, `global` const { lang: _, 'data-astro-id': astroId, 'define:vars': defineVars, ...props } = _props;