Generate GopherJS interfaces to ProtobufJS and gRPC Web from your proto files.
Most of the code is based on a fork of Googles protoc-gen-go code generator, with heavy modifications to output GopherJS compatible structs.
Only proto files with syntax="proto3";
are supported.
To use this software, you must:
-
Install the protocol buffer compiler,
protoc
: https://developers.google.com/protocol-buffers/ -
Install the Go compiler and tools: https://golang.org/
-
Grab the code from the repository and install the proto package.
$ go get -u github.com/johanbrandhorst/protobuf/protoc-gen-gopherjs
The compiler plugin,
protoc-gen-gopherjs
, will be installed in$GOBIN
, defaulting to$GOPATH/bin
. It must be in your$PATH
for the protocol compiler,protoc
, to find it.
This package generates files that import the
GopherJS ProtobufJS bindings. The
generated interface is designed to be as similar as possible to that of files
generated with protoc-gen-go
, with one exception:
Marshal
andUnmarshal
methods for each type. Instead ofproto.Marshal
andproto.Unmarshal
, these are used to serialize to and from binary.
Once the software is installed, there are two steps to using it. First you must compile the protocol buffer definitions and then import them into your program.
To compile the protocol buffer definition, run protoc with the --gopherjs_out
parameter set to the directory you want to output the GopherJS code to.
$ protoc --gopherjs_out=. *.proto
The generated files are suffixed .pb.gopherjs.go
.
Consider the file test.proto
, containing
syntax="proto3";
package example;
message Test {
string label = 1;
int32 type = 2;
int64 reps = 3;
}
Generate it:
$ protoc --gopherjs_out=. test.proto
This generates the following client code (abbreviated):
// Code generated by protoc-gen-gopherjs. DO NOT EDIT.
// source: test.proto
package example
import jspb "github.com/johanbrandhorst/protobuf/jspb"
type Test struct {
Label string
Type int32
Reps int64
}
// Getters...
// MarshalToWriter marshals Test to the provided writer.
func (m *Test) MarshalToWriter(writer jspb.Writer) {
if m == nil {
return
}
if len(m.Label) > 0 {
writer.WriteString(1, m.Label)
}
if m.Type != 0 {
writer.WriteInt32(2, m.Type)
}
if m.Reps != 0 {
writer.WriteInt64(3, m.Reps)
}
}
// Marshal marshals Test to a slice of bytes.
func (m *Test) Marshal() []byte {
writer := jspb.NewWriter()
m.MarshalToWriter(writer)
return writer.GetResult()
}
// UnmarshalFromReader unmarshals a Test from the provided reader.
func (m *Test) UnmarshalFromReader(reader jspb.Reader) *Test {
for reader.Next() {
if m == nil {
m = &Test{}
}
switch reader.GetFieldNumber() {
case 1:
m.Label = reader.ReadString()
case 2:
m.Type = reader.ReadInt32()
case 3:
m.Reps = reader.ReadInt64()
default:
reader.SkipField()
}
}
return m
}
// Unmarshal unmarshals a Test from a slice of bytes.
func (m *Test) Unmarshal(rawBytes []byte) (*Test, error) {
reader := jspb.NewReader(rawBytes)
m = m.UnmarshalFromReader(reader)
if err := reader.Err(); err != nil {
return nil, err
}
return m, nil
}
In your client code, you can use the library like so:
package main
import "github.com/youruser/yourrepo/example"
func main() {
t := example.Test{
Label: "Label",
Type: 1234,
Rep: 5678,
}
rawBytes, err := t.Marshal()
if err != nil {
panic(err)
}
t1, err := new(example.Test).Unmarshal(rawBytes)
if err != nil {
panic(err)
}
}
To pass extra parameters to the plugin, use a comma-separated parameter list separated from the output directory by a colon:
$ protoc --gopherjs_out=plugins=grpc,import_path=mypackage:. *.proto
1. `import_prefix=xxx` - a prefix that is added onto the beginning of
all imports. Useful for things like generating protos in a
subdirectory, or regenerating vendored protobufs in-place.
1. import_path=foo/bar
- used as the package if no input files
declare gopherjs_package
. If it contains slashes, everything up to the
rightmost slash is ignored.
1. plugins=plugin1+plugin2
- specifies the list of sub-plugins to
load. The only plugin in this repo is grpc
.
1. Mfoo/bar.proto=quux/shme
- declares that foo/bar.proto
is
associated with Go package quux/shme
. This is subject to the
import_prefix
parameter.
If a proto file specifies RPC services, protoc-gen-gopherjs
can be instructed to
generate code compatible with the GopherJS gRPC-Web bindings.
To do this, pass the plugins
parameter to protoc-gen-gopherjs
:
$ protoc --gopherjs_out=plugins=grpc:. *.proto
Use of the gRPC-Web/WsProxy bindings require the target gRPC server to be wrapped by the Improbable gRPC-Web proxy and the gRPC-Web Websocket proxy. See the test setup for an example implementation of this wrapping.