add WASM blazor-like thing

This commit is contained in:
2026-07-13 00:40:08 -04:00
parent 98978e4930
commit 3c494605ba
38 changed files with 3070 additions and 1 deletions

77
go/wasmruntime/fetch.go Normal file
View File

@@ -0,0 +1,77 @@
//go:build js && wasm
package wasmruntime
import (
"errors"
"fmt"
"sync"
"syscall/js"
)
// Fetch performs an HTTP GET via the browser Fetch API and returns the response
// body as a string. It bridges a JS Promise into Go: it registers then/catch
// callbacks and blocks the calling goroutine on a channel until the request
// settles.
//
// Because it blocks, call it from a goroutine — never from a reactive callback
// or event handler — and write the result into signals when it returns, e.g.:
//
// go func() {
// body, err := Fetch(url)
// ...
// data.Set(...) // updates the UI reactively
// }()
func Fetch(url string) (string, error) {
var (
once sync.Once
done = make(chan struct{})
body string
ferr error
onResp, onText, onErr js.Func
)
finish := func() { once.Do(func() { close(done) }) }
onErr = js.FuncOf(func(this js.Value, args []js.Value) any {
msg := "fetch error"
if len(args) > 0 && args[0].Truthy() {
e := args[0]
if m := e.Get("message"); m.Truthy() {
msg = m.String()
} else {
msg = e.Call("toString").String()
}
}
ferr = errors.New(msg)
finish()
return nil
})
onText = js.FuncOf(func(this js.Value, args []js.Value) any {
if len(args) > 0 {
body = args[0].String()
}
finish()
return nil
})
onResp = js.FuncOf(func(this js.Value, args []js.Value) any {
resp := args[0]
if !resp.Get("ok").Bool() {
ferr = fmt.Errorf("HTTP %d", resp.Get("status").Int())
finish()
return nil
}
// resp.text() -> Promise<string>
resp.Call("text").Call("then", onText).Call("catch", onErr)
return nil
})
js.Global().Call("fetch", url).Call("then", onResp).Call("catch", onErr)
<-done
onResp.Release()
onText.Release()
onErr.Release()
return body, ferr
}