import { chromium } from 'playwright' import { createServer } from 'http' import { stat, readFile } from 'fs/promises' import { extname, join, normalize } from 'path' const ROOT = process.argv[2] if (!ROOT) { console.error('用法: node render-check.mjs '); process.exit(1) } const MIME = { '.html':'text/html', '.js':'text/javascript', '.css':'text/css', '.svg':'image/svg+xml', '.png':'image/png', '.jpg':'image/jpeg', '.json':'application/json', '.woff2':'font/woff2', '.woff':'font/woff', '.ico':'image/x-icon' } const server = createServer(async (req, res) => { try { let p = decodeURIComponent(req.url.split('?')[0]) if (!p.startsWith('/')) p = '/' + p let fp = normalize(join(ROOT, p)) try { await stat(fp) } catch { try { await stat(fp + '.html'); fp = fp + '.html' } catch { try { await stat(join(fp, 'index.html')); fp = join(fp, 'index.html') } catch { fp = join(ROOT, '404.html') } } } if ((await stat(fp)).isDirectory()) fp = join(fp, 'index.html') const buf = await readFile(fp) res.writeHead(200, { 'content-type': MIME[extname(fp)] || 'application/octet-stream' }) res.end(buf) } catch { res.writeHead(404); res.end('nf') } }) await new Promise(r => server.listen(0, r)) const port = server.address().port const browser = await chromium.launch({ channel: 'chrome', args: ['--no-sandbox'] }) const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 }, javaScriptEnabled: false }) const page = await ctx.newPage() const pages = ['', 'demo', 'about', 'projects/', 'projects/iotlcm/', 'projects/xiu-dtu/', 'projects/xiu-admin/', 'guide/portal-deploy', 'projects/iotlcm/compare', 'projects/iotlcm/guide/deploy', 'projects/iotlcm/guide/quickstart'] const results = [] for (const p of pages) { const resp = await page.goto(`http://127.0.0.1:${port}/${p}`, { waitUntil: 'load' }) const info = await page.evaluate(() => ({ is404: !!document.querySelector('.NotFound'), h1: (document.querySelector('h1')?.textContent || '').trim().slice(0, 36), hasNav: !!document.querySelector('.VPNav'), hasFooter: !!document.querySelector('.pf-foot'), })) results.push({ p: p || '(home)', status: resp.status(), ...info }) } console.log(`\n=== ${ROOT} 渲染验收 ===`) let ok = 0, fail = 0 for (const r of results) { const bad = r.is404 || r.status >= 400 || !r.hasNav if (bad) fail++; else ok++ console.log(`${bad ? '❌' : '✅'} ${String(r.status).padEnd(4)} ${r.p.padEnd(34)} ${r.is404 ? '[404页]' : ''} ${r.h1}`) } console.log(`\n通过 ${ok} / 失败 ${fail}`) await browser.close() server.close() process.exit(fail ? 1 : 0)