69 lines
2.0 KiB
Go
69 lines
2.0 KiB
Go
//go:build js && wasm
|
|
|
|
package wasmruntime
|
|
|
|
import (
|
|
"syscall/js"
|
|
|
|
"kjol/wasmruntime/vdom"
|
|
)
|
|
|
|
// State preservation across an in-place hot swap (see the dev server's
|
|
// livereload script). A fresh wasm instance has fresh Go memory, so signal
|
|
// values would reset on every rebuild. To keep them, the outgoing instance
|
|
// snapshots its signals (by creation order, via a vdom.Collector) into
|
|
// sessionStorage on dispose, and the incoming instance restores them on boot.
|
|
//
|
|
// It's best-effort: if an edit adds/removes/reorders signals, the by-order match
|
|
// shifts and unmatched signals fall back to their initial value — the same
|
|
// hook-order caveat as server components.
|
|
|
|
const stateKey = "__gowasm_hmr_state"
|
|
|
|
var stateCollector *vdom.Collector
|
|
|
|
// PreserveState registers the collector whose signals are snapshotted to
|
|
// sessionStorage when this instance is disposed for a hot swap.
|
|
func PreserveState(c *vdom.Collector) { stateCollector = c }
|
|
|
|
// RestoreState returns the signal snapshot saved by a prior instance before a
|
|
// hot swap, or nil if there is none. It is one-shot: the entry is cleared so a
|
|
// manual page refresh starts from initial state.
|
|
func RestoreState() [][]byte {
|
|
ss := js.Global().Get("sessionStorage")
|
|
if !ss.Truthy() {
|
|
return nil
|
|
}
|
|
raw := ss.Call("getItem", stateKey)
|
|
if !raw.Truthy() {
|
|
return nil
|
|
}
|
|
ss.Call("removeItem", stateKey)
|
|
arr := js.Global().Get("JSON").Call("parse", raw)
|
|
if arr.Type() != js.TypeObject {
|
|
return nil
|
|
}
|
|
out := make([][]byte, arr.Length())
|
|
for i := range out {
|
|
out[i] = []byte(arr.Index(i).String())
|
|
}
|
|
return out
|
|
}
|
|
|
|
// saveState writes the preserved collector's current signal values to
|
|
// sessionStorage. Called from the dispose hook before the DOM is torn down.
|
|
func saveState() {
|
|
if stateCollector == nil {
|
|
return
|
|
}
|
|
ss := js.Global().Get("sessionStorage")
|
|
if !ss.Truthy() {
|
|
return
|
|
}
|
|
arr := js.Global().Get("Array").New()
|
|
for _, b := range stateCollector.Snapshot() {
|
|
arr.Call("push", string(b))
|
|
}
|
|
ss.Call("setItem", stateKey, js.Global().Get("JSON").Call("stringify", arr))
|
|
}
|