summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jonathan Neal <jonathantneal@hotmail.com> 2022-01-28 18:19:55 -0500
committerGravatar GitHub <noreply@github.com> 2022-01-28 18:19:55 -0500
commit9f27941b4f0d2fa823721970e5d9ea634ba4431d (patch)
tree61fad878373c004b0ced731d484d737e7ebf6034
parent0a112e1f564242280d8bb3f142b2a205d25832e8 (diff)
downloadastro-9f27941b4f0d2fa823721970e5d9ea634ba4431d.tar.gz
astro-9f27941b4f0d2fa823721970e5d9ea634ba4431d.tar.zst
astro-9f27941b4f0d2fa823721970e5d9ea634ba4431d.zip
Render Custom Element Tag (#2473)
* Support rendering web components * nit: remove addition of script
-rw-r--r--packages/astro/src/runtime/server/index.ts33
1 files changed, 32 insertions, 1 deletions
diff --git a/packages/astro/src/runtime/server/index.ts b/packages/astro/src/runtime/server/index.ts
index 633f41957..e94de7732 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<typeof AstroC
return template;
}
+export async function renderHTMLElement(result: SSRResult, constructor: typeof HTMLElement, props: any, children: any) {
+ const name = getHTMLElementName(constructor);
+
+ let attrHTML = '';
+
+ for (const attr in props) {
+ attrHTML += ` ${attr}="${toAttributeString(await props[attr])}"`;
+ }
+
+ children = await children;
+ children = children == null ? children : '';
+
+ const html = `<${name}${attrHTML}>${children}</${name}>`;
+
+ 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;