import { readFileSync } from 'node:fs'; import { createPinia } from 'pinia'; import { createSSRApp } from 'vue'; import { renderToString } from 'vue/server-renderer'; import { expandApplicationHtml } from '../../build/application-html.js'; import { APPLICATION_VIEWS } from '../ui/views/index.js'; const HOST = /
<\/div>/g; /** * Expand application markup as the browser shows it once views are mounted: * static templates inline, and each view rendered into its host. Markup tests * read this instead of the raw template expansion. * @param {string} html Document with `gev:template` markers. * @returns {Promise} */ export async function renderApplicationHtml(html) { let output = expandApplicationHtml(html); for (const [host, name] of [...output.matchAll(HOST)]) { const view = APPLICATION_VIEWS[name]; if (!view) throw new Error(`Unknown application view: ${name}`); const markup = (await renderToString(createSSRApp(view).use(createPinia()))) // Hydration markers, empty-attribute values and escaped apostrophes // are SSR detail; the DOM is the same as the template's. .replace(/||/g, '') .replace(/ ([\w:.-]+)=""/g, ' $1') .replaceAll(''', "'"); output = output.replace( host, () => `
${markup}
`, ); } return output; } /** The standalone page's markup with every view rendered. */ export function readApplicationHtml() { return renderApplicationHtml( readFileSync(new URL('../../index.html', import.meta.url), 'utf8'), ); }