简介
Buf 是一款更高效、开发者友好的 Protobuf API 管理工具,不仅支持代码生成,还支持插件和 Protobuf 格式化。
我们可以使用 Buf 替代原本基于 Protoc 的代码生成流程,一方面可以统一管理团队 Protoc 插件的版本、代码生成配置,另一方面可以简化项目开发配置。
本文将会用两部分内容来简述 Buf 的使用流程,涵盖 Golang 服务端开发和前端开发的内容。
- 基于 Protobuf 生成 Golang 代码。
- 基于 Protobuf 生成 Typescript 类型定义代码。
Buf 安装
如果您使用的是 Macos,可以直接通过 Brew 安装。
brew install bufbuild/buf/buf
复制
如果您使用的是 Windows,推荐您通过 Golang 的 install 命令安装。
# Substitute GOBIN for your bin directory # Leave unset to default to $GOPATH/bin GO111MODULE=on GOBIN=/usr/local/bin go install \ github.com/bufbuild/buf/cmd/buf@v1.18.0
复制
更多安装方式可以自行查阅官方文档 - Getting Started with the Buf CLI。
安装成功之后,我们可以通过 buf --version
命令进行验证。
使用 Buf 生成 Golang 代码
使用 Buf 生成代码可以拆分以下步骤。
- 初始化 Buf 配置(配置 Protobuf 协议格式化和 Lint 校验)。
- 编写 Protobuf 协议。
- 初始化 Buf 代码生成配置。
- 运行 Buf 生成代码。
本文将会基于 Buf 提供的 Remote Plugin 工具进行说明。
初始化 Buf 配置
我们在任意项目下创建名为 proto 的目录并使用 buf mod init
初始化 Protobuf 协议的 Buf 配置。
值得注意的是这个目录既可以是前后端共享的路径,也可以是共享的集中式 Git 仓库,形式取决于项目管理者本身的规划。
此时项目的 proto 目录下会出现一个名为 buf.yaml
的配置文件,如图所示。
. └── proto └── buf.yaml
复制
一般情况下,我们可以考虑改动 buf.yaml 配置如下所示。
version: v1 deps: - buf.build/googleapis/googleapis:main lint: use: - DEFAULT except: - PACKAGE_DIRECTORY_MATCH - PACKAGE_VERSION_SUFFIX breaking: use: - FILE
复制
改动之后的配置可以允许我们在协议中导入 google 提供的 api,禁用包名和目录对不上将会导致编译报错,禁用强制包名后缀为版本号将会导致报错。
其中后面两项为 Proto3 协议规范,但有时候我们可以根据情况进行调整。
编写 Protobuf 协议
接下来我们继续创建 proto/api 和 proto/api/hello 子目录,并在 proto/api/hello 目录下创建文件 hello.proto。
syntax = "proto3"; // 一般情况下 Package 可以按照「项目名.服务类型.服务名」的方式进行命名 package bufexample.api.hello; import "google/protobuf/timestamp.proto"; // 如果需要生成 Golang 代码需要指定 go_package, 通常是「项目名/服务类型/服务名」即可 option go_package = "bufexample/api/hello;hello"; // Buf 官方推荐服务名后面增 service HelloService { rpc Hello(HelloRequest) returns (HelloResponse) {} } message HelloRequest { string name = 1; } message HelloResponse { string name = 1; google.protobuf.Timestamp now = 2; }
复制
完成 Protobuf 协议文件的创建之后,我们的目录如图所示。
. └── proto ├── api │ └── hello │ └── hello.proto └── buf.yaml
复制
初始化 Buf 代码生成配置
完成 Protobuf 协议编写之后,我们切换回项目目录,并在此创建两个文件,分别是 buf.go.gen.yaml
和 buf.ts.gen.yaml
用于生成 Golang 和 Typescript 的代码。
其中 buf.go.gen.yaml
文件用于生成 Golang 的代码,内容如下所示。
version: v1 plugins: - plugin: buf.build/protocolbuffers/go out: ./gengo # 这个 module 参数其实就是协议 package 的第一个点的名称,去掉的话就会多一层名为 bufexample 的目录 opt: module=bufexample - plugin: buf.build/grpc/go:v1.3.0 out: ./gengo # 这个 module 参数其实就是协议 package 的第一个点的名称,去掉的话就会多一层名为 bufexample 的目录 opt: module=bufexample
复制
另一个 buf.ts.gen.yaml
文件用于生成 Typescript 类型定义代码,内容如下所示。
version: v1 plugins: - plugin: buf.build/bufbuild/es out: ./gents
复制
值得注意的是两份配置均使用了远程
运行 Buf 生成代码
在完成上述步骤之后,我们可以在项目目录下运行指定命令 buf generate
即可生成代码。
对于 Golang 代码生成,我们可以指定 buf.go.gen.yaml
作为生成配置。
buf generate --template ./buf.go.gen.yaml .
复制
命令运行之后,Buf 工具将会帮助我们生成对应的 Golang 代码,值得注意的是第一次运行需要加载远程插件,具体耗时取决于您的网络条件。
. ├── buf.go.gen.yaml ├── buf.ts.gen.yaml ├── gengo │ └── api │ └── hello │ ├── hello.pb.go │ └── hello_grpc.pb.go └── proto ├── api │ └── hello │ └── hello.proto └── buf.yaml
复制
对于 Typescript 类型定义代码,我们可以指定 buf.ts.gen.yaml
作为生成配置。
命令运行之后,Buf 工具将会帮助我们生成对应的 Typescript 类型定义代码,值得注意的是第一次运行同样需要加载远程插件,具体耗时取决于您的网络条件。
. ├── buf.go.gen.yaml ├── buf.ts.gen.yaml ├── gents │ └── proto │ └── api │ └── hello │ ├── hello_pb.d.ts │ └── hello_pb.js └── proto ├── api │ └── hello │ └── hello.proto └── buf.yaml
复制