メインコンテンツへスキップ

protoc から Buf に移行するために動作を確認してみた

·1044 文字·3 分
目次

背景
#

protoc を使った複雑なスクリプトを引き継いだので、 Buf に移行したいよねという気持ちから調べてみた結果をまとめる。

前提
#

簡略化したプロジェクト構成はこちら。実際のコードではパッケージ名とディレクトリ構造が一致しておらずリンターにも指摘されているのですが、ここではその点は省略します。

/
├─ buf.yaml
├─ buf.gen.yaml
├─ buf.lock
├─ proto/
│  ├─ v1/
│  │  ├─ analytics/
│  │  │  ├─ analytics.proto
│  │  │  └─ analyticsHealth.proto // ../healthcheck.proto に依存
│  │  ├─ api/
│  │  │  └─ api.proto
│  │  └─ healthcheck.proto
│  └─ v2/
│     └─ api/
│        ├─ api.v2.proto
│        └─ other.proto // google/protobuf/timestamp に依存
└─ gen/ // 将来はここに生成させたい

みたこと
#

Buf には build と generate の両方の設定ファイルに入力ファイルの指定がある
#

そもそも buf.gen.yaml の方の inputs は任意だった。これは paths や exclude_paths などを使って module の中を更に絞り込みたい時に使うべきと理解。

buf.gen.yaml - Buf Docs

複数の module を指定したときは生成結果はマージされる
#

buf.yaml

modules:
  - path: proto/v1
  - path: proto/v2

buf.gen.yaml

plugins:
  - local: ./node_modules/ts-proto/protoc-gen-ts_proto
    out: gen/ts_proto
    strategy: all

こういう時。 proto/v1 proto/v2 がそれぞれカレントディレクトリとして処理されるので、生成されるファイルは api/api.ts api/api.v2.ts のように、どちらも api/ 配下になる。 最終的にマージされるので、結果は以下になる。重複しているファイルは上書きになる。上書きが発生した時は警告が出た。

gen
└── ts_proto
    ├── analytics
    │   ├── analytics.ts
    │   └── analyticsHealth.ts
    ├── api
    │   ├── api.ts
    │   ├── api.v2.ts
    │   └── other.ts
    ├── google
    │   ├── api
    │   │   ├── annotations.ts
    │   │   └── http.ts
    │   └── protobuf
    │       ├── descriptor.ts
    │       └── timestamp.ts
    └── healthcheck.ts

特定のファイルのみ generate するときは buf.gen.yaml の inputs.paths を使う
#

例として v1 だけ生成するとします。module のルートを変更するので import のパスは適切に変更してください。

buf.yaml

modules:
  - path: proto

buf.gen.yaml

inputs:
  - directory: .
    paths:
      - proto/v1

結果

gen
└── ts_proto
    ├── google
    │   ├── api
    │   │   ├── annotations.ts
    │   │   └── http.ts
    │   └── protobuf
    │       └── descriptor.ts
    └── v1
        ├── analytics
        │   ├── analytics.ts
        │   └── analyticsHealth.ts
        ├── api
        │   └── api.ts
        └── healthcheck.ts

protoc-gen-ts には grpc-js が必要で、 ts-proto には不要
#

オプションなしの素の状態で生成した場合はそうなった。NestJS に組み込む場合は protoc-gen-ts で出る雛形(UnimplementedXXXXService)は使わないので、どちらでもいい。

protoc は -XXX_out を基準にコード生成が実行されるので、protoc では1回の実行であっても Buf に移行すると plugins を複数書く場合がある
#

  • つまり複数の -XXX_out を書くことで 1 回の protoc で複数のプラグインを実行可能
  • –plugin を指定しても、対応する -XXX_out が存在しないとそのプラグインは実行されない(-XXX_opt も同様で、無駄な指定になる)
    • 無駄な指定めっちゃあって 😡

js は protoc にビルトインされているので、–plugin を指定せずともコード生成可能
#

書いている通り。

最後に
#

更新するかも。

最終更新日: 2026-01-13

Taiyo Minagawa (sun-yryr)
著者
Taiyo Minagawa (sun-yryr)
ソフトウェアエンジニア(Backend)/ SwiftとASMRが好きです