Search code examples
gowebassemblywasigo-wasm

Will Go 1.21 include ability to host http via WebAssembly? How?


I'd like to try an http server via WebAssembly on Go. I think that compiling go for webassembly outside the browser is not supported in go 1.20, and that the net/http libraries aren't included in tinygo.

I tried to do it with gotip after reading https://stackoverflow.com/a/76091829 (thanks @TachyonicBytes), but whenever I tried to start the server (or any blocking/waiting function), I got an error: fatal error: all goroutines are asleep - deadlock!. I tried moving things to a goroutine with wait functions and that either simply ended the function, or gave the same error. Here's how I ran it:

go install golang.org/dl/gotip@latest
gotip download
GOOS=wasip1 GOARCH=wasm gotip build -o server.wasm server.go && wasm3 server.wasm

Here's the example server.go:

package main

import (
    "fmt"
    "net/http"
    "sync"
)

func main() {
    s := http.Server{
        Addr: ":8080",
        Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            w.Write([]byte("Hello, World!"))
        }),
    }

    fmt.Println("about to serve")
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        err := s.ListenAndServe()
        if err != nil {
            fmt.Printf("Unable to serve: %v\n", err)
        }
        wg.Done()
        fmt.Println("serving stopped")
    }()
    wg.Wait()
    fmt.Println("started up server")
}

So, is this just because go 1.21 is a WIP, because I'm failing to understand the proper way to start a blocking function, or because this sort of thing won't be supported in go 1.21?

I tried to start a go server in a server side webassembly runner wasm3 on an Intel Mac. I expected it to serve http, but found it either threw an error, or exited immediately.


Solution

  • Glad to have been of help!

    Unfortunately no, it seems that wasm networking will not be a part of go 1.21. It's a bit complicated to implement networking in wasm. Running your code, I got this line:

        sdk/gotip/src/net/net_fake.go:229
    

    Upon inspection, it has this disclaimer:

    // Fake networking for js/wasm and wasip1/wasm.
    // This file only exists to make the compiler happy.
    

    The hard part of doing this is that WASI has only partial support for sockets, so no full blown Berkeley sockets for WASI, yet.

    The good news is that you can actually do http, but in tinygo. Tinygo has partial support for the go net/http package, with it's drivers.

    If you want to see some real-life usage of this, I am currently trying to port this project to wasm, using tinygo. If I recall correctly, I got it to work, but it has been a while, and I know for sure that I did not complete the conversion yet. Maybe it was impossible for the time being.

    Another thing is that wasm3, despite having partial wasi implementation, may not have implemented the sockets part. I would suggest also playing with some other runtimes, like wasmtime, wasmer, wasmedge, or wazero, which @Gedw99 suggested. Wasmedge has great support for sockets, but in your case, the compiler is actually the problem.