gRPC-WebをNext.jsで動かす
gRPC-Webを触っててNext.js上で動かしてみたかったがあまり事例がなく、動かすまでに四苦八苦したのでメモ。
gRPC-Webは有名な実装が2種類あった。
今回はNext.jsで動かすので、Node.jsもサポートされている方を使います。
GitHub - improbable-eng/grpc-web: gRPC Web implementation for Golang and TypeScript
protoの定義などはいろんな場所で解説されているので、ハマりどころを中心にまとめていきます。
protocのjs用プラグインのビルド
protocからJSのコードを生成したいんですが、grpc/grpc-webリポジトリには以下のような注意書きがあります。
NOTE: Javascript output is no longer supported by protocolbuffers/protobuf package as it previously did. Please use the releases from protocolbuffers/protobuf-javascript instead.
GitHub - grpc/grpc-web: gRPC for Web Clients
残念ながらJS出力用のプラグインはサポートされていないので用意する必要があります。
プラグインのリポジトリを除くとバイナリが配布されていますが M1 Mac用のビルドはありません。自力でビルドする必要があります。
issueを探してみるとbazelでビルドする方法が紹介されていました。
$ git clone https://github.com/protocolbuffers/protobuf-javascript $ cd protobuf-javascript/ $ bazel build //generator:protoc-gen-js
ビルドしたプラグインを使ってJSのコードを生成します。
PROTOC_GEN_JS_PATH="./bin/protoc-gen-js" OUT_DIR="./src/generated" gen_protoc: protoc \ --plugin="protoc-gen-ts=./node_modules/.bin/protoc-gen-ts" \ --plugin=${PROTOC_GEN_JS_PATH} \ --proto_path=../protos \ ../protos/*.proto \ --js_out=import_style=commonjs,binary:${OUT_DIR} \ --ts_out="service=grpc-web:${OUT_DIR}" .PHONY: gen_protoc
ちなみにプロジェクトのディレクトリ構造はこんな感じ。
サーバー側とprotoc定義を共有するため、1リポジトリですべてのコードを管理しており、1つ上の階層にproto置き場を作っています。
--proto_path
でproto置き場を指定してるにも関わらず ..protos/.proto
と相対パスで指定する必要があるのがくせ者。
$ tree -L 2 . ├── Makefile ├── bin │ └── protoc-gen-js // ビルドしたJS用プラグイン ├── next-env.d.ts ├── node_modules ├── package-lock.json ├── package.json ├── pages │ └── index.tsx ├── src │ └── generated // protocから生成したコード置き場 └── tsconfig.json
proxyの導入
grpc/grpc-webではenvoyを使ったproxyの導入が必要ですが、improbable-eng/grpc-webにはGoのプロキシが用意されています。
幸いこちらはmacos用のビルドが配布されているので、それをDLして使います。
Releases · improbable-eng/grpc-web · GitHub
今回はローカルで使うので、CORSやTLSに関する設定はゆるゆるで。
PROXY_BIN_PATH="./bin/grpcwebproxy-v0.15.0-osx-x86_64" ${PROXY_BIN_PATH} \ --backend_addr=localhost:50051 \ --run_tls_server=false \ --allow_all_origins
ここまでやってクライアントからリクエストすると、ブラウザでgRPCなサーバーとやりとりできるNext.js製アプリケーションが動くはずです。