import type { ComponentRenderer, DynamicRenderContext, DynamicRendererGenerator, StaticRendererGenerator } from '../../@types/renderer'; /** Initialize Astro Component renderer for Static and Dynamic components */ export function createRenderer(renderer: ComponentRenderer) { const _static: StaticRendererGenerator = (Component) => renderer.renderStatic(Component); const _imports = (context: DynamicRenderContext) => { const values = Object.values(renderer.imports ?? {}) .reduce((acc, v) => { return [...acc, `{ ${v.join(', ')} }`]; }, []) .join(', '); const libs = Object.keys(renderer.imports ?? {}) .reduce((acc: string[], lib: string) => { return [...acc, `import("${context.frameworkUrls[lib as any]}")`]; }, []) .join(','); return `const [{${context.componentExport}: Component}, ${values}] = await Promise.all([import("${context.componentUrl}")${renderer.imports ? ', ' + libs : ''}]);`; }; const serializeProps = (props: Record) => JSON.stringify(props); const createContext = () => { const astroId = `${Math.floor(Math.random() * 1e16)}`; return { ['data-astro-id']: astroId, root: `document.querySelector('[data-astro-id="${astroId}"]')`, Component: 'Component' }; }; const createDynamicRender: DynamicRendererGenerator = (wrapperStart, wrapperEnd) => (Component, renderContext) => { const innerContext = createContext(); return async (props, ...children) => { let value: string; try { value = await _static(Component)(props, ...children); } catch (e) { value = ''; } value = `
${value}
`; return `${value}\n`; }; }; return { static: _static, load: createDynamicRender('(async () => {', '})()'), idle: createDynamicRender('requestIdleCallback(async () => {', '})'), visible: createDynamicRender( 'const o = new IntersectionObserver(async ([entry]) => { if (!entry.isIntersecting) { return; } o.disconnect();', ({ root }) => `}); o.observe(${root})` ), }; }