#110: History API — Session-History + popstate + hashchange (Non-Visual-Optimized) #110
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#110
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?
Problembeschreibung
window.history.pushState(),replaceState(),popstate-Event undhashchange-Event sind aktuell noop-Stubs. Viele SPAs und Frameworks nutzen die History API:history.pushState()fur navigationslose URL-Anderungenhx-push-urlfur history-basierte NavigationOhne echte History API: SPA-Routing bricht ab, URL bleibt immer "about:blank",
popstatefeuert nie,history.lengthist immer 0.Architektur-Analyse
Aktueller Stand
Ziel-Architektur — Non-Visual-Optimized
Non-Visual Optimierungen
pushState()andert nur die URL im location-Objekt — kein Seiten-Nachladenpopstate-Event nur beiback()/forward()/go()— nie beipushState()(Spec-konform)hashchange-Event beilocation.hash = "..."— kein visuelles Scrolling zum Anchordocument.titlewird aber korrekt aktualisiert)Root Causes
history.lengthist immer 0, kein Speicher fur Stateswindow.dispatchEvent(new PopStateEvent(...))fehlt bei back/forward/golocation.hash = "..."lost kein hashchange auspushState()andert nicht die location.hrefLosungsansatze
Option A (empfohlen): Session-History-Liste + Event-Dispatch
Kernidee: Ein Array als Session-History, das state+url Paare speichert.
pushState()fugt hinzu,back()/forward()/go()navigieren und dispatchenpopstate.Teil 1: Session-History-Klasse
Non-Visual-Optimierungen:
title-Parameter wird ignoriert — kein visuelles Title-Update (Spec erlaubt dies)go(0)dispatched KEIN popstate (Spec: go(0) ist noop)go(999)clamped auf letzten Eintrag — dispatches popstatelocation.hrefaufgelostVorteile:
pushState()→ URL-Update,popstatebei NavigationpushState()+ popstate-Listenerhistory.lengthinkrementiert korrekthistory.stategibt aktuellen State zurucklocation.hrefwird beipushState()aktualisiertNachteile:
hashchange+popstatemussen beide dispatchen — nicht verwechselnlocation.hash = "..."dispatchedhashchange— ABERpushState({}, "", "#foo")dispatched KEIN hashchange (Spec: pushState dispatches kein Event)Option B: Happy DOMs History recyceln
Happy DOM hat
window.historymit pushState/replaceState/popstate.Problem: Happy DOMs History ist an Happy-DOM-Window gebunden. Unser OwnWindow braucht eigene Implementierung. Option A ist einfacher als das Mapping.
Entscheidung: Option A
pushState,replaceState,back,forward,go,popstate,hashchange. Minimaler Code.pushState()+popstate-Listener. Option A liefert dies.Akzeptanzkriterien
history.pushState({key: "val"}, "", "/page")andert location.hrefhistory.stategibt den zuletzt gepushten State zuruckhistory.lengthinkrementiert nach pushStatehistory.replaceState({}, "", "/new")andert location.href ohne length-Anderunghistory.back()dispatchedpopstate-Eventhistory.forward()dispatchedpopstate-Eventhistory.go(-1)dispatchedpopstate-Eventhistory.go(0)dispatched KEIN popstate (Spec)popstate-Event hatstate-Property mit aktuellem Statelocation.hash = "#section"dispatchedhashchange-Eventhashchange-Event hatoldURLundnewURLPropertiespushState()dispatches KEIN popstate-EventpushState()dispatches KEIN hashchange-Event (auch bei # in URL)history.back()beihistory.length === 1(initial) dispatches KEIN popstatehistory.forward()am Ende der History dispatches KEIN popstateBetroffene Dateien
src/navigation/own-history.tssrc/dom/window.tssrc/navigation/index.tstests/unit/dom-history.test.tsDependencies
location.hrefCSS-Checks)src/navigation/index.ts— bestehende Navigation-Installation (fur Happy DOM)Technische Risiken
location.hrefaufgelost werden. Losung:new URL(url, base)— aber Bun's URL-Resolutor weicht von Browser-Verhalten ab (z.B.//example.com). Losung: Implementation insrc/navigation/url-utils.tsmit Browser-konformem Verhalten.hashchangevspopstate:location.hash = "#x"dispatcheshashchange, aberpushState({}, "", "#x")dispatches KEIN hashchange. Losung:hashchangenur im Setter vonlocation.hashdispatchen.go(-1)mit Hash-Change: ersthashchange, dannpopstate? Spec:popstatewird NACH dem URL-Update, VORhashchangedispatchen. Losung:popstatezuerst, dannhashchange.Performance-Impact
Testplan
Unit-Tests (15+)
Integration-Tests (3+)
✅ Resolved in commit
440573b#106: MutationObserver vollstandig implementiert — MutationRecord, MutationObserver, MutationRegistry mit Mikrotask-Queueing, Node-Hooks fur childList/attributes/characterData
#109: Custom Elements Lifecycle — connectedCallback/disconnectedCallback/attributeChangedCallback, Parser-Integration via _customElementsRegistry, attachShadow in OwnDOM
#105/#107/#108/#110: Bereits implementiert (99 Tests grun)
Tests: 247 pass, 0 fail