/** * 检查文章页代码块在窄屏下的滚动行为。 * * 期望:代码块自身横向滚动(overflow-x: auto), * 而不是把整个页面撑出横向滚动条。 * * 用法:CDP_WS= node scripts/check-code-blocks.mjs */ const [, , targetUrl, widthArg = "390"] = process.argv; const width = Number(widthArg); const wsUrl = process.env.CDP_WS; if (!wsUrl) { console.error("缺少 CDP_WS 环境变量"); process.exit(1); } const socket = new WebSocket(wsUrl); let messageId = 0; const pending = new Map(); function send(method, params = {}) { const id = ++messageId; socket.send(JSON.stringify({ id, method, params })); return new Promise((resolve, reject) => { pending.set(id, { resolve, reject }); setTimeout(() => { if (pending.has(id)) { pending.delete(id); reject(new Error(`CDP 超时: ${method}`)); } }, 30000); }); } socket.addEventListener("message", (event) => { const message = JSON.parse(event.data); if (message.id && pending.has(message.id)) { const { resolve } = pending.get(message.id); pending.delete(message.id); resolve(message.result); } }); socket.addEventListener("open", async () => { await send("Page.enable"); await send("Runtime.enable"); await send("Emulation.setDeviceMetricsOverride", { width, height: 900, deviceScaleFactor: 1, mobile: true, }); await send("Page.navigate", { url: targetUrl }); await new Promise((resolve) => setTimeout(resolve, 4000)); const result = await send("Runtime.evaluate", { expression: `(() => { const pres = [...document.querySelectorAll('.prose-blog pre')]; const doc = document.documentElement; return { documentOverflow: doc.scrollWidth - doc.clientWidth, preCount: pres.length, blocks: pres.map((pre, index) => { const figure = pre.closest('figure'); return { index, overflowX: getComputedStyle(pre).overflowX, scrollable: pre.scrollWidth > pre.clientWidth, scrollWidth: pre.scrollWidth, clientWidth: pre.clientWidth, figureOverflow: figure ? getComputedStyle(figure).overflow : null, }; }), }; })()`, returnByValue: true, }); console.log(JSON.stringify(result.result.value, null, 2)); socket.close(); process.exit(0); });