UNPKG

astro

Version:

Astro is a modern site builder with web best practices, performance, and DX front-of-mind.

147 lines (146 loc) 5.21 kB
import { isVNode } from "../../../../jsx-runtime/index.js"; import { HTMLString, markHTMLString, spreadAttributes, voidElementNames } from "../../index.js"; import { isAstroComponentFactory } from "../astro/factory.js"; import { createAstroComponentInstance } from "../astro/instance.js"; import { renderJSX } from "../../jsx.js"; const ClientOnlyPlaceholder = "astro-client-only"; let jsxQueueStats = { vnodeCount: 0, elementCount: 0, componentCount: 0, hasLogged: false }; function getJSXQueueStats() { return { ...jsxQueueStats }; } function resetJSXQueueStats() { jsxQueueStats = { vnodeCount: 0, elementCount: 0, componentCount: 0, hasLogged: false }; } function renderJSXToQueue(vnode, result, queue, pool, stack, parent, metadata) { jsxQueueStats.vnodeCount = jsxQueueStats.vnodeCount + 1; if (vnode instanceof HTMLString) { const html = vnode.toString(); if (html.trim() === "") return; const node = pool.acquire("html-string", html); node.html = html; queue.nodes.push(node); return; } if (typeof vnode === "string") { const node = pool.acquire("text", vnode); node.content = vnode; queue.nodes.push(node); return; } if (typeof vnode === "number" || typeof vnode === "boolean") { const str = String(vnode); const node = pool.acquire("text", str); node.content = str; queue.nodes.push(node); return; } if (vnode == null || vnode === false) { return; } if (Array.isArray(vnode)) { for (let i = vnode.length - 1; i >= 0; i = i - 1) { stack.push({ node: vnode[i], parent, metadata }); } return; } if (!isVNode(vnode)) { const str = String(vnode); const node = pool.acquire("text", str); node.content = str; queue.nodes.push(node); return; } handleVNode(vnode, result, queue, pool, stack, parent, metadata); } function handleVNode(vnode, result, queue, pool, stack, parent, metadata) { if (!vnode.type) { throw new Error( `Unable to render ${result.pathname} because it contains an undefined Component! Did you forget to import the component or is it possible there is a typo?` ); } if (vnode.type === /* @__PURE__ */ Symbol.for("astro:fragment")) { stack.push({ node: vnode.props?.children, parent, metadata }); return; } if (isAstroComponentFactory(vnode.type)) { jsxQueueStats.componentCount = jsxQueueStats.componentCount + 1; const factory = vnode.type; let props = {}; let slots = {}; for (const [key, value] of Object.entries(vnode.props ?? {})) { if (key === "children" || value && typeof value === "object" && value["$$slot"]) { slots[key === "children" ? "default" : key] = () => renderJSX(result, value); } else { props[key] = value; } } const displayName = metadata?.displayName || factory.name || "Anonymous"; const instance = createAstroComponentInstance(result, displayName, factory, props, slots); const queueNode = pool.acquire("component"); queueNode.instance = instance; queue.nodes.push(queueNode); return; } if (typeof vnode.type === "string" && vnode.type !== ClientOnlyPlaceholder) { jsxQueueStats.elementCount = jsxQueueStats.elementCount + 1; renderHTMLElement(vnode, result, queue, pool, stack, parent, metadata); return; } if (typeof vnode.type === "function") { if (vnode.props?.["server:root"]) { const output3 = vnode.type(vnode.props ?? {}); stack.push({ node: output3, parent, metadata }); return; } const output2 = vnode.type(vnode.props ?? {}); stack.push({ node: output2, parent, metadata }); return; } const output = renderJSX(result, vnode); stack.push({ node: output, parent, metadata }); } function renderHTMLElement(vnode, _result, queue, pool, stack, parent, metadata) { const tag = vnode.type; const { children, ...props } = vnode.props ?? {}; const attrs = spreadAttributes(props); const isVoidElement = (children == null || children === "") && voidElementNames.test(tag); if (isVoidElement) { const html = `<${tag}${attrs}/>`; const node = pool.acquire("html-string", html); node.html = html; queue.nodes.push(node); return; } const openTag = `<${tag}${attrs}>`; const openTagHtml = queue.htmlStringCache ? queue.htmlStringCache.getOrCreate(openTag) : markHTMLString(openTag); stack.push({ node: openTagHtml, parent, metadata }); if (children != null && children !== "") { const processedChildren = prerenderElementChildren(tag, children, queue.htmlStringCache); stack.push({ node: processedChildren, parent, metadata }); } const closeTag = `</${tag}>`; const closeTagHtml = queue.htmlStringCache ? queue.htmlStringCache.getOrCreate(closeTag) : markHTMLString(closeTag); stack.push({ node: closeTagHtml, parent, metadata }); } function prerenderElementChildren(tag, children, htmlStringCache) { if (typeof children === "string" && (tag === "style" || tag === "script")) { return htmlStringCache ? htmlStringCache.getOrCreate(children) : markHTMLString(children); } return children; } export { getJSXQueueStats, renderJSXToQueue, resetJSXQueueStats };