Currently, only the Go API is available.
Deploy your gRPC server as WebAssembly (WASM) and communicate with browser-side JavaScript.
Why is this needed? I was just tired of having to spin up a separate gRPC server every time I test the UI.
- Unary call
- Server streaming call
- Client streaming call
- Bi-directional streaming call
- Support transport implementation for connectrpc/connect-es 🏗️
- Support transport implementation for timostamm/protobuf-ts
import (
grpcwasm "github.com/lesomnus/grpc-wasm"
"google.golang.org/grpc"
)
func main() {
s := grpc.NewServer()
// Register your gRPC service server implementation
// e.g.
// echo.RegisterEchoServiceServer(s, echo.EchoServer{})
grpcwasm.Serve(s)
}
Neat! I call this program a bridge because it exposes the socket to your gRPC server to the browser.
Assuming your bridge code is located at ./cmd/bridge
, build it into WASM:
GOOS=js GOARCH=wasm go build -o ./bridge.wasm ./cmd/bridge
import { open } from "grpc-wasm";
const sock = await open('path/to/your/bridge.wasm')
const conn = await sock.dial()
const msg: Echo = {
message: "Royale with Cheese",
circularShift: 6n
};
const req = Echo.toBinary(msg)
const rst = await conn.invoke("/echo.EchoService/Once", req, {});
const res = Echo.fromBinary(rst.response);
console.log(res.message)
// "Cheese Royale with "
await conn.close()
await sock.close()
import { open } from "grpc-wasm";
import workerUrl from "grpc-wasm/worker?worker&url";
const sock = await open('path/to/your/bridge.wasm', { workerUrl })
...
It works for both development and production build.
import { createClient } from "@connectrpc/connect";
import { open } from "grpc-wasm";
import { GrpcWasmTransport } from "grpc-wasm/@connectrpc";
const sock = await open('path/to/your/bridge.wasm')
const conn = await sock.dial()
const transport = new GrpcWasmTransport({ conn });
const client = createClient(EchoService, transport);
const response = await client.Once({
message: "Royale with Cheese",
circularShift: 6n
})
console.log(response.message)
// "Cheese Royale with "
import { open } from "grpc-wasm";
import { GrpcWasmTransport } from "grpc-wasm/@protobuf-ts";
const sock = await open('path/to/your/bridge.wasm')
const conn = await sock.dial()
const transport = new GrpcWasmTransport({ conn });
const client = new EchoServiceClient(transport);
const { response } = await client.Once({
message: "Royale with Cheese",
circularShift: 6n
})
console.log(response.message)
// "Cheese Royale with "
You have to add following option to your Vite config:
ref: vitejs/vite#15547
definedConfig({
// ...
optimizeDeps: {
exclude: ["grpc-wasm"],
},
})
flowchart LR
subgraph Worker
subgraph "WASM (bridge)"
Server --- bufconn
end
bufconn --- Sock
end
Sock --- Conn