gRPC over Websockets in the browser with Go and GopherJS

This package provides wrappers for net.Conn and grpc.Dial which allow you to route gRPC calls over a websocket connection from a JS web client to a Go http server.

This is not efficient. It runs an entire HTTP2 stack on top of the underlying Websocket channel, including TLS, etc. We assume security is provided at the WS layer, so gRPC is configured with grpc.WithInsecure.

Because of the large amount of code required to implement this stack, the minified code for a simple example is over 5MB in size.

$ gopherstats client.js

Packages for client.js:
       906 kb   net/http
       663 kb   net
       544 kb   crypto/tls
       385 kb   vendor/golang_org/x/text/unicode/norm
       251 kb   reflect
       217 kb   text/template
       214 kb   html/template
       213 kb   fmt
       191 kb   text/template/parse
       181 kb   math/big
       170 kb   crypto/elliptic
       165 kb   crypto/x509
       142 kb   encoding/asn1
       139 kb   time
       117 kb   encoding/json
       111 kb   strconv
        97 kb   syscall
        80 kb   unicode
        80 kb   math/rand
        73 kb   crypto/rsa

68 more packages totalling 1468 kb, use gopherstats -all or -topN to show them



import ws ""

func main() {
    // Init websocket listener
    listener := ws.NewListener()

    // Init gRPC server
    server := grpc.NewServer()

    // Register services

    // Start gRPC listener
    go server.Serve(listener)

    // Set up HTTP handlers
    http.Handle("/grpc", websocket.Handler(listener.Handler))



import ws ""

func main() {
    // Get a gRPC *ClientConn
    conn, err := ws.Dial("ws://localhost/grpc")
    if err != nil {

    // Create clients as usual using the gRPC conn
    client := service.NewPingClient(conn)