import { createHash } from 'node:crypto'; import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; const frontendRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const outputDirectory = path.join(frontendRoot, 'dist'); mkdirSync(outputDirectory, { recursive: true }); function copyEntry(source, destination) { const entries = readdirSync(source, { withFileTypes: true }); mkdirSync(destination, { recursive: true }); for (const entry of entries) { const sourcePath = path.join(source, entry.name); const destinationPath = path.join(destination, entry.name); if (entry.isDirectory()) { copyEntry(sourcePath, destinationPath); } else if (entry.isFile()) { copyFileSync(sourcePath, destinationPath); } } } for (const entry of ['libs', 'favicon.ico']) { const source = path.join(frontendRoot, entry); if (existsSync(source)) { const destination = path.join(outputDirectory, entry); if (entry.includes('.')) { copyFileSync(source, destination); } else { copyEntry(source, destination); } } } // Vite hoists linked stylesheets into , ahead of legacy inline styles in // app.html. Re-emit the workspace layer after those styles so production and // development use the same cascade order. const workspaceSourcePath = path.join(frontendRoot, 'workspace.css'); const workspaceContents = readFileSync(workspaceSourcePath); const workspaceHash = createHash('sha256').update(workspaceContents).digest('hex').slice(0, 12); const workspaceFileName = `workspace-${workspaceHash}.css`; copyFileSync(workspaceSourcePath, path.join(outputDirectory, workspaceFileName)); const builtAppPath = path.join(outputDirectory, 'app.html'); const builtAppHtml = readFileSync(builtAppPath, 'utf8'); const runtimeStylesheet = ` \n`; const nextBuiltAppHtml = builtAppHtml.includes('data-workspace-runtime') ? builtAppHtml.replace(/\s*]+data-workspace-runtime[^>]*>\s*/u, `\n${runtimeStylesheet}`) : builtAppHtml.replace('', `${runtimeStylesheet}`); if (!nextBuiltAppHtml.includes('data-workspace-runtime')) { throw new Error('Unable to inject the runtime workspace stylesheet into dist/app.html'); } writeFileSync(builtAppPath, nextBuiltAppHtml, 'utf8'); console.log(`Injected runtime workspace stylesheet: ${workspaceFileName}`);