import { withLeadingSlash } from 'ufo'; function createRendererContext({ manifest, buildAssetsURL }) { const ctx = { // Manifest buildAssetsURL: buildAssetsURL || withLeadingSlash, manifest: void 0, updateManifest, // Internal cache _dependencies: void 0, _dependencySets: void 0, _entrypoints: void 0 }; function updateManifest(manifest2) { const manifestEntries = Object.entries(manifest2); ctx.manifest = manifest2; ctx._dependencies = {}; ctx._dependencySets = {}; ctx._entrypoints = manifestEntries.filter((e) => e[1].isEntry).map(([module]) => module); } updateManifest(manifest); return ctx; } function getModuleDependencies(id, rendererContext) { if (rendererContext._dependencies[id]) { return rendererContext._dependencies[id]; } const dependencies = rendererContext._dependencies[id] = { scripts: {}, styles: {}, preload: {}, prefetch: {} }; const meta = rendererContext.manifest[id]; if (!meta) { return dependencies; } if (meta.file) { dependencies.preload[id] = meta; if (meta.isEntry || meta.sideEffects) { dependencies.scripts[id] = meta; } } for (const css of meta.css || []) { dependencies.styles[css] = dependencies.preload[css] = dependencies.prefetch[css] = rendererContext.manifest[css]; } for (const asset of meta.assets || []) { dependencies.preload[asset] = dependencies.prefetch[asset] = rendererContext.manifest[asset]; } for (const depId of meta.imports || []) { const depDeps = getModuleDependencies(depId, rendererContext); Object.assign(dependencies.styles, depDeps.styles); Object.assign(dependencies.preload, depDeps.preload); Object.assign(dependencies.prefetch, depDeps.prefetch); } const filteredPreload = {}; for (const id2 in dependencies.preload) { const dep = dependencies.preload[id2]; if (dep.preload) { filteredPreload[id2] = dep; } } dependencies.preload = filteredPreload; return dependencies; } function getAllDependencies(ids, rendererContext) { const cacheKey = Array.from(ids).sort().join(","); if (rendererContext._dependencySets[cacheKey]) { return rendererContext._dependencySets[cacheKey]; } const allDeps = { scripts: {}, styles: {}, preload: {}, prefetch: {} }; for (const id of ids) { const deps = getModuleDependencies(id, rendererContext); Object.assign(allDeps.scripts, deps.scripts); Object.assign(allDeps.styles, deps.styles); Object.assign(allDeps.preload, deps.preload); Object.assign(allDeps.prefetch, deps.prefetch); for (const dynamicDepId of rendererContext.manifest[id]?.dynamicImports || []) { const dynamicDeps = getModuleDependencies(dynamicDepId, rendererContext); Object.assign(allDeps.prefetch, dynamicDeps.scripts); Object.assign(allDeps.prefetch, dynamicDeps.styles); Object.assign(allDeps.prefetch, dynamicDeps.preload); } } const filteredPrefetch = {}; for (const id in allDeps.prefetch) { const dep = allDeps.prefetch[id]; if (dep.prefetch) { filteredPrefetch[id] = dep; } } allDeps.prefetch = filteredPrefetch; for (const id in allDeps.preload) { delete allDeps.prefetch[id]; } for (const style in allDeps.styles) { delete allDeps.preload[style]; delete allDeps.prefetch[style]; } rendererContext._dependencySets[cacheKey] = allDeps; return allDeps; } function getRequestDependencies(ssrContext, rendererContext) { if (ssrContext._requestDependencies) { return ssrContext._requestDependencies; } const ids = new Set(Array.from([ ...rendererContext._entrypoints, ...ssrContext.modules || ssrContext._registeredComponents || [] ])); const deps = getAllDependencies(ids, rendererContext); ssrContext._requestDependencies = deps; return deps; } function renderStyles(ssrContext, rendererContext) { const { styles } = getRequestDependencies(ssrContext, rendererContext); return Object.values(styles).map( (resource) => renderLinkToString({ rel: "stylesheet", href: rendererContext.buildAssetsURL(resource.file) }) ).join(""); } function getResources(ssrContext, rendererContext) { return [...getPreloadLinks(ssrContext, rendererContext), ...getPrefetchLinks(ssrContext, rendererContext)]; } function renderResourceHints(ssrContext, rendererContext) { return getResources(ssrContext, rendererContext).map(renderLinkToString).join(""); } function renderResourceHeaders(ssrContext, rendererContext) { return { link: getResources(ssrContext, rendererContext).map(renderLinkToHeader).join(", ") }; } function getPreloadLinks(ssrContext, rendererContext) { const { preload } = getRequestDependencies(ssrContext, rendererContext); return Object.values(preload).map((resource) => ({ rel: resource.module ? "modulepreload" : "preload", as: resource.resourceType, type: resource.mimeType ?? null, crossorigin: resource.resourceType === "font" || resource.resourceType === "script" || resource.module ? "" : null, href: rendererContext.buildAssetsURL(resource.file) })); } function getPrefetchLinks(ssrContext, rendererContext) { const { prefetch } = getRequestDependencies(ssrContext, rendererContext); return Object.values(prefetch).map((resource) => ({ rel: "prefetch", as: resource.resourceType, type: resource.mimeType ?? null, crossorigin: resource.resourceType === "font" || resource.resourceType === "script" || resource.module ? "" : null, href: rendererContext.buildAssetsURL(resource.file) })); } function renderScripts(ssrContext, rendererContext) { const { scripts } = getRequestDependencies(ssrContext, rendererContext); return Object.values(scripts).map((resource) => renderScriptToString({ type: resource.module ? "module" : null, src: rendererContext.buildAssetsURL(resource.file), defer: resource.module ? null : "", crossorigin: "" })).join(""); } function createRenderer(createApp, renderOptions) { const rendererContext = createRendererContext(renderOptions); return { rendererContext, async renderToString(ssrContext) { ssrContext._registeredComponents = ssrContext._registeredComponents || /* @__PURE__ */ new Set(); const _createApp = await Promise.resolve(createApp).then((r) => r.default || r); const app = await _createApp(ssrContext); const html = await renderOptions.renderToString(app, ssrContext); const wrap = (fn) => () => fn(ssrContext, rendererContext); return { html, renderResourceHeaders: wrap(renderResourceHeaders), renderResourceHints: wrap(renderResourceHints), renderStyles: wrap(renderStyles), renderScripts: wrap(renderScripts) }; } }; } function renderScriptToString(attrs) { return ` value === null ? "" : value ? ` ${key}="${value}"` : " " + key).join("")}><\/script>`; } function renderLinkToString(attrs) { return ` value === null ? "" : value ? ` ${key}="${value}"` : " " + key).join("")}>`; } function renderLinkToHeader(attrs) { return `<${attrs.href}>${Object.entries(attrs).map(([key, value]) => key === "href" || value === null ? "" : value ? `; ${key}="${value}"` : `; ${key}`).join("")}`; } export { createRenderer, createRendererContext, getAllDependencies, getModuleDependencies, getPrefetchLinks, getPreloadLinks, getRequestDependencies, getResources, renderResourceHeaders, renderResourceHints, renderScripts, renderStyles };