import assert from 'node:assert/strict'; import { existsSync, readFileSync, readdirSync } 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'); const htmlFiles = readdirSync(frontendRoot).filter((fileName) => fileName.endsWith('.html')); assert.ok(existsSync(path.join(outputDirectory, 'index.html')), 'dist/index.html is missing'); assert.ok(existsSync(path.join(outputDirectory, 'favicon.ico')), 'dist/favicon.ico is missing'); assert.strictEqual(existsSync(path.join(outputDirectory, 'downloads')), false, 'runtime installers must stay outside dist'); for (const fileName of htmlFiles) { const sourceHtml = readFileSync(path.join(frontendRoot, fileName), 'utf8'); const builtHtmlPath = path.join(outputDirectory, fileName); assert.strictEqual(/\?v=\d+/.test(sourceHtml), false, `${fileName} still uses a manual cache version`); assert.ok(existsSync(builtHtmlPath), `${fileName} was not emitted`); const builtHtml = readFileSync(builtHtmlPath, 'utf8'); const assetUrls = [...builtHtml.matchAll(/(?:src|href)="(\/(?:assets|libs)\/[^"?#]+)"/g)] .map((match) => match[1]); for (const assetUrl of assetUrls) { const assetPath = path.join(outputDirectory, ...assetUrl.split('/').filter(Boolean)); assert.ok(existsSync(assetPath), `${fileName} references missing asset ${assetUrl}`); } } for (const fileName of ['app.html', 'share.html']) { const html = readFileSync(path.join(outputDirectory, fileName), 'utf8'); assert.ok(/\/assets\/[^"']+\.js/.test(html), `${fileName} is not using a bundled module`); assert.strictEqual(/vue\.global(?:\.prod)?\.js|axios\.min\.js/.test(html), false, `${fileName} still loads global Vue/Axios`); } console.log(`Verified ${htmlFiles.length} HTML entries and their emitted assets.`);