add WASM blazor-like thing
This commit is contained in:
68
go/wasmruntime/persist_wasm.go
Normal file
68
go/wasmruntime/persist_wasm.go
Normal file
@@ -0,0 +1,68 @@
|
||||
//go:build js && wasm
|
||||
|
||||
package wasmruntime
|
||||
|
||||
import (
|
||||
"syscall/js"
|
||||
|
||||
"kjol/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))
|
||||
}
|
||||
Reference in New Issue
Block a user