Sprint 25: 19-Sites-Korpus — verbleibende Blockbuster (youtube, ___dynamicImportLoader, Proof-Runner) #117
Labels
No labels
bug
docs
feature
housekeeping
html-spec
performance
react-compat
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
glow-all/true-headless-browser#117
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Sprint 25: 19-Sites-Korpus — verbleibende Blockbuster beheben
Problembeschreibung
Der Corpus-Runner zeigt 17/19 ✅, aber das ist eine oberflächliche Metrik ("kein JS-Crash"). Der Proof-Runner (echte DOM-Validierung) zeigt, dass viele Sites nur teilweise oder scheinbar korrekt laden:
___dynamicImportLoadercrasht bei relativen URLs ohne Origin (/build/q-*.js)import({...})→___dynamicImport({...}))Ziel: Alle 19 Sites vollständig und korrekt laden, gemessen an Proof-Queries im LIVE DOM (nicht nur "kein Crash").
Analyse: Aktueller Datenstand
Corpus-Runner (17/19 ✅ — oberflächlich)
Proof-Runner (echte DOM-Queries)
Die Ergebnisse aus proof-runner.ts zeigen, dass NUR VueJS alle Proof-Queries besteht. Die restlichen Sites scheitern an unterschiedlichen Barrieren.
Mermaid — Dependency Graph der Blockierer
Sub-Issue 1: youtube.com + speedtest.net — 0 Requests
Root-Cause-Analyse
Beide Sites haben exakt 0 Network-Requests und 0 DOM-Größe („-" im Corpus-Report). Das deutet darauf hin, dass die DNS-Auflösung oder der Verbindungsaufbau komplett scheitert.
Mögliche Ursachen:
Option A — Network-Debug-Session (empfohlen)
Ein dediziertes Debug-Script, das jede Seite Schritt für Schritt durch den Network-Stack verfolgt:
bun -e 'console.log(await Bun.resolve("youtube.com"))'useCurlTransport: true/false)fetch()außerhalb des BrowsersAufwand: 2h — reine Analyse
Option B — YouTube-spezifischen Interceptor
Vorhandene YouTube-Redirect-Muster erkennen und bypassen. YouTube verwendet oft:
https://www.youtube.com→ redirect zuhttps://www.youtube.com/?app=desktopAufwand: 4h — schwer wartbar
Option C — Minimal: Einen bekannten Workaround finden
Andere Headless-Browser (Playwright, Puppeteer) laden YouTube → deren Network-Log als Referenz nutzen.
Aufwand: 1h
Sub-Issue 2: ___dynamicImportLoader crasht bei relativen URLs ohne Origin
Root-Cause-Analyse
In
execution-realm.tsZeile ~586ff wird___dynamicImportLoaderdefiniert:Wenn
___importMeta.resolve()einen relativen Specifier wie"./chunks/q-993Mv2pg.js"auflöst, erzeugtnew URL(specifier, "https://qwik.dev/assets/main.js")→https://qwik.dev/build/q-993Mv2pg.js.ABER: Wenn die Module-URL selbst aus einem anderen Kontext kommt (z.B. Inline-Script, oder der
url-Parameter ist nicht korrekt gesetzt), wirdnew URL(specifier, baseUrl)fehlschlagen und/build/q-993Mv2pg.js(nur Pfad, kein Origin) liefern.Fundamental:
___importMeta.resolve()setzt eine korrekte Basis-URL voraus. Wenn das Modulimport.meta.url = "https://qwik.dev/assets/main.js"hat, sollte die resolution korrekt sein. Das Problem ist, dass das Modul evtl. ohne URL ausgeführt wird →import.meta.resolvefällt auf die aktuelle Document-Base-URL zurück, die nicht gesetzt ist.Option A — fallback auf document.baseURI (empfohlen)
Aufwand: 1h — minimaler Fix
Option B — ___importMeta.resolve defensiv machen
buildImportMetaInjectionmuss sicherstellen, dassimport.meta.resolve()immer einen absolute URL zurückgibt:Aufwand: 1h
Option C — Fetch mit Origin-Erkennung
In
___dynamicImportLoaderprüfen, ob die URL absolut ist (= startet mithttp://oderhttps://). Falls nicht, gegen den letzten bekannten Origin auflösen.Aufwand: 2h
Sub-Issue 3: HTML-served-as-JS (Cloudflare/Vercel Challenge)
Analyse
Seiten hinter Cloudflare (solidjs.com, web.dev) oder Vercel (kit.svelte.dev) liefern HTML-Inhalt (Challenge-Pages) auf JS-Endpunkte. Unser
ScriptLoader.fetchContent()erkennt das:Der Fehler
Empty chunkkommt ausdynamic-scripts.tsZeile 709, wo leerer Content als Fehler behandelt wird. Das ist eigentlich kein echter Bug — die Seite kann nicht anders (Challenge). ABER: derEmpty chunk-Error erzeugt unhandled Promise-Rejections (Fix in Sprint 24b teilweise angewandt).Option A — Challenge-Erkennung + Graceful Degradation
Challenges erkennen und als „blocked by Cloudflare" markieren statt als „Empty chunk". Im Corpus-Report ein eigenes Status-Flag.
Aufwand: 2h
Option B — Challenge automatisch lösen
Camoufox oder Playwright-Integration für Challenge-Seiten → löst Cloudflare/Vercel Challenges. ABER: das ist ein ganzes Feature (separates Issue).
Aufwand: 20h+
Sub-Issue 4: replaceStaticImports Regex — false positives
Analyse
Der Error auf vuejs.org:
Ursache:
replaceDynamicImports()transformiertimport({...})zu___dynamicImport({...}). Das originaleimport(in manchen Scripts wird fälschlich als dynamischer import erkannt.Der Regex
/import\s*\(/gmatcht JEDESimport(— auch in Strings, Comments, und Objekt-Literalen.Der Regex in
replaceStaticImportsmatchtimport\s*(?:\{.... Das kann block-scoped imports treffen, die nicht statische imports sind (z.B. dynamischerimport()mit destructuring).Option A — AST-basierte Transformation (empfohlen)
Statt Regex einen echten JavaScript-Parser für die Transformation verwenden. Leichte Option:
@babel/parseroderacornmit einfachem Walk.Aufwand: 4h
Option B — Regex verfeinern
replaceDynamicImportsauf Zeilen beschränken, die nicht mit{nachimport(beginnen:Aufwand: 1h — Workaround, kein echter Fix
Option C — Import-Statement-Klasse bauen
Eigene kleine Parser-Klasse für statische imports (kein AST, aber Token-basiert):
Aufwand: 6h
Sub-Issue 5: Proof-Runner — incrementelle Speicherung + Fehlertoleranz
Analyse
Der Proof-Runner (
proof-runner.ts) schreibtproof-results.jsonerst NACH allen 19 Sites. Wenn eine Site crasht (z.B. Sub-Issue 2), sind ALLE vorherigen Ergebnisse verloren.Option A — Incremental Write + Catch per Site (empfohlen)
Aufwand: 1h
Option B — Timeout per Site
Aufwand: 0.5h
Akzeptanzkriterien
Phase 1: Proof-Runner Resilienz
crashederfasst, nicht als AbbruchPhase 2: ___dynamicImportLoader Fix
/) werden gegendocument.baseURIaufgelöstCannot find module-CrashPhase 3: youtube + speedtest Debug
Phase 4: replaceStaticImports Regex
SyntaxError: import call expects one or two argumentsmehr auf vuejs.orgPhase 5: HTML-served-as-JS
Empty chunkError mehrBetroffene Dateien
proof-runner.tssrc/js/execution-realm.tssrc/js/module-transformer.tssrc/js/module-transformer.tssrc/js/dynamic-scripts.tssrc/pages/page.tsodertransport-manager.tsproof-queries.tsDependencies
Technische Risiken
Performance-Impact
if-CheckTestplan
Phase 1: Proof-Runner (2 unit tests)
crashederfasstPhase 2: ___dynamicImportLoader (3 integration tests)
/build/q-123.jswird aufgelöstPhase 3: youtube+speedtest (2 tests)
Phase 4: Regex (2 tests)
import({...})wird NICHT von replaceDynamicImports getroffenPhase 5: HTML-served-as-JS (1 test)
Zeitplan
Empfohlene Reihenfolge
✅ Sprint 25 Fixes — 4 Issues gelöst (Commit
aaabcbc3)Gelöste Issues
#5: Proof-Runner Resilienz 🔴
corpus/partial-results.jsongespeichert--no-resumeum zu deaktivieren)Promise.racezwischen page-load und Timeout (customTimeout + 10s Grace)#2: ___dynamicImportLoader crash bei /build/q-*.js ohne Origin 🔴
buildImportMetaInjection()erkennt relative URLs (keinhttp:///https://)window.location.origin+ relative URL verwendetnew URL(specifier, base)erhält damit immer einen validen absoluten Base-URL#4: replaceStaticImports Regex false positives 🟢
replaceDynamicImports()Regex um(?!{)) ergänzt (Negative Lookahead)import({...}), was nie ein gültiger dynamic import ist#3: HTML-served-as-JS (Cloudflare Noise) 🟢
fetchContent()in ScriptLoader nutzt gleicheshtmlPatternwieexecuteRaw()<!DOCTYPE,<html>,<head>,<body>,<!--etc.)x < 5) werden korrekt durchgelassen#1: youtube.com + speedtest.net — 0 Requests 🟡
setAttribute('', 'value')InvalidCharacterError — DOM-API-Level Issue, kein "0 Requests"-Problem