Fable clean up

This commit is contained in:
Andras Schmelczer 2026-06-11 21:35:45 +01:00
parent 3441a7e4af
commit 4ce8a4f41d
46 changed files with 642 additions and 911 deletions

View file

@ -1,11 +1,16 @@
import { spawn } from 'node:child_process';
import { once } from 'node:events';
import { mkdir, readdir, rm, stat, writeFile } from 'node:fs/promises';
import { mkdir, writeFile } from 'node:fs/promises';
import { createServer as createNetServer } from 'node:net';
import path from 'node:path';
import { chromium } from 'playwright';
import {
cleanupBrowserTmp,
openBrowser,
safeCloseBrowser,
setupBrowserTmp,
} from './lib/browser.mjs';
import { discoverRoutes, requireDist } from './lib/dist.mjs';
const dist = path.resolve('dist');
const browserTmp = path.resolve('.astro', 'playwright-astro-audit-tmp');
const outputJson = path.resolve(
process.env.ASTRO_AUDIT_OUTPUT_JSON ?? '.astro/astro-audit-results.json'
@ -19,7 +24,6 @@ const astroBin = path.resolve(
process.platform === 'win32' ? 'astro.cmd' : 'astro'
);
const HOST = '127.0.0.1';
const INDEX_FILE = 'index.html';
const SERVER_START_TIMEOUT_MS = 60000;
const CLOSE_TIMEOUT_MS = 3000;
const NAV_TIMEOUT_MS = 20000;
@ -51,21 +55,7 @@ function parseViewports(raw = process.env.ASTRO_AUDIT_VIEWPORTS ?? DEFAULT_VIEWP
});
}
async function walk(dir) {
const entries = await readdir(dir, { withFileTypes: true });
const files = [];
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
files.push(...(await walk(fullPath)));
} else {
files.push(fullPath);
}
}
return files;
}
async function discoverRoutes() {
async function discoverAuditRoutes() {
if (process.env.ASTRO_AUDIT_ROUTES) {
return process.env.ASTRO_AUDIT_ROUTES.split(',')
.map((route) => route.trim())
@ -73,29 +63,8 @@ async function discoverRoutes() {
.map((route) => (route.startsWith('/') ? route : `/${route}`));
}
try {
await stat(dist);
} catch {
throw new Error('dist/ does not exist. Run npm run build first.');
}
const files = await walk(dist);
const routes = new Set();
for (const file of files) {
if (!file.endsWith('.html')) continue;
const rel = path.relative(dist, file).replaceAll(path.sep, '/');
if (rel === '404.html') continue;
if (rel === INDEX_FILE) {
routes.add('/');
} else if (rel.endsWith(`/${INDEX_FILE}`)) {
routes.add('/' + rel.slice(0, -INDEX_FILE.length));
} else {
routes.add('/' + rel.replace(/\.html$/, '/'));
}
}
return [...routes].sort();
await requireDist();
return discoverRoutes();
}
async function getFreePort() {
@ -169,20 +138,6 @@ async function stopProcess(child) {
}
}
async function safeCloseBrowser(browser) {
const childProcess = browser?.process?.();
try {
await Promise.race([
browser.close(),
sleep(CLOSE_TIMEOUT_MS).then(() => {
throw new Error('Timed out while closing Chromium');
}),
]);
} catch {
childProcess?.kill('SIGKILL');
}
}
function viewportLabel(viewport) {
return `${viewport.width}x${viewport.height}`;
}
@ -385,19 +340,15 @@ function renderMarkdown(report) {
}
const viewports = parseViewports();
const routes = await discoverRoutes();
const routes = await discoverAuditRoutes();
if (routes.length === 0) {
throw new Error('No HTML routes found to audit.');
}
await rm(browserTmp, { recursive: true, force: true });
await mkdir(browserTmp, { recursive: true });
await setupBrowserTmp(browserTmp);
await mkdir(path.dirname(outputJson), { recursive: true });
await mkdir(path.dirname(outputMarkdown), { recursive: true });
process.env.TMPDIR = browserTmp;
process.env.TMP = browserTmp;
process.env.TEMP = browserTmp;
const port = await getFreePort();
const baseUrl = `http://${HOST}:${port}/`;
@ -409,16 +360,7 @@ try {
devServer = startAstroDev(port);
await waitForDevServer(baseUrl, devServer);
browser = await chromium.launch({
headless: true,
env: {
...process.env,
TMPDIR: browserTmp,
TMP: browserTmp,
TEMP: browserTmp,
},
args: ['--disable-dev-shm-usage', '--disable-gpu', '--no-sandbox'],
});
browser = await openBrowser(browserTmp);
for (const viewport of viewports) {
const context = await browser.newContext({
@ -480,5 +422,5 @@ try {
} finally {
if (browser) await safeCloseBrowser(browser);
if (devServer) await stopProcess(devServer);
await rm(browserTmp, { recursive: true, force: true }).catch(() => {});
await cleanupBrowserTmp(browserTmp);
}