parity_debug.mjs 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. /**
  2. * 诊断:为什么 jsdom 里跑旧 app.js 没把 DOM 渲出来(基线为空 ⇒ 对拍无从比)。
  3. * 打印:页面里的 script 标签形态、eval 是否抛错、渲染后 #root/#tabs 的内容抽样。
  4. */
  5. import { JSDOM, VirtualConsole } from 'jsdom'
  6. const GATEWAY = process.argv[2] || 'http://127.0.0.1:28084'
  7. const html = await (await fetch(GATEWAY + '/detail/v2')).text()
  8. const vc = new VirtualConsole()
  9. vc.on('jsdomError', (e) => console.log(' [jsdomError]', String(e.message).slice(0, 120)))
  10. const dom = new JSDOM(html, { url: GATEWAY + '/detail/v2', runScripts: 'dangerously', pretendToBeVisual: true, virtualConsole: vc })
  11. const { window } = dom
  12. const doc = window.document
  13. console.log('== 页面脚本标签 ==')
  14. for (const s of Array.from(doc.querySelectorAll('script'))) {
  15. const src = s.getAttribute('src')
  16. console.log(` type=${s.getAttribute('type') || 'classic'} src=${src || '(内联, ' + s.textContent.length + ' 字节)'}`)
  17. }
  18. console.log('== 容器初始状态 ==')
  19. for (const id of ['root', 'tabs', 'top', 'foot']) {
  20. const el = doc.getElementById(id)
  21. console.log(` #${id}: ${el ? (el.innerHTML.trim().length + ' 字节') : '不存在'}`)
  22. }
  23. // 装 fetch 桩(记录 fleet 响应)
  24. const state = {}
  25. window.fetch = async (input, init) => {
  26. const raw = typeof input === 'string' ? input : (input && input.url) || String(input)
  27. const url = raw.startsWith('http') ? raw : GATEWAY + (raw.startsWith('/') ? raw : '/' + raw)
  28. const resp = await fetch(url, init)
  29. const body = await resp.text()
  30. if (url.includes('/api/fleet')) state.fleet = body.length
  31. return { ok: resp.ok, status: resp.status, headers: { get: (k) => resp.headers.get(k) },
  32. json: async () => JSON.parse(body), text: async () => body }
  33. }
  34. console.log('== 手动执行外链脚本 ==')
  35. for (const s of Array.from(doc.querySelectorAll('script[src]'))) {
  36. const src = s.getAttribute('src')
  37. const code = await (await fetch(GATEWAY + src)).text()
  38. try {
  39. window.eval(code)
  40. console.log(` [OK] eval ${src}(${code.length} 字节)`)
  41. } catch (e) {
  42. console.log(` [X ] eval ${src} 抛错: ${e.name}: ${String(e.message).slice(0, 160)}`)
  43. }
  44. }
  45. for (let i = 0; i < 20; i++) {
  46. if (doc.querySelector('.kpis .kpi')) break
  47. await new Promise((r) => setTimeout(r, 500))
  48. }
  49. console.log('== 12 秒后 ==')
  50. console.log(' .kpis .kpi:', doc.querySelectorAll('.kpis .kpi').length)
  51. console.log(' #tabs 按钮:', doc.querySelectorAll('#tabs button').length)
  52. console.log(' button 总数:', doc.querySelectorAll('button').length)
  53. console.log(' #root 前 260 字:', (doc.getElementById('root')?.innerHTML || '').trim().slice(0, 260).replace(/\s+/g, ' '))
  54. console.log(' fleet 响应字节:', state.fleet ?? '(未请求)')
  55. console.log(' window.__WIN:', JSON.stringify(window.__WIN ?? null).slice(0, 80))
  56. console.log(' window.__L 键数:', window.__L ? Object.keys(window.__L).length : '(无)')