Skip to content

Commit

Permalink
Render Custom Element Tag (#2473)
Browse files Browse the repository at this point in the history
* Support rendering web components

* nit: remove addition of script
  • Loading branch information
Jonathan Neal committed Jan 28, 2022
1 parent 0a112e1 commit 9f27941
Showing 1 changed file with 32 additions and 1 deletion.
33 changes: 32 additions & 1 deletion packages/astro/src/runtime/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 9f27941

Please sign in to comment.