简介
Buf 是一款更高效、开发者友好的 Protobuf API 管理工具,不仅支持代码生成,还支持插件和 Protobuf 格式化。
我们可以使用 Buf 替代原本基于 Protoc 的代码生成流程,一方面可以统一管理团队 Protoc 插件的版本、代码生成配置,另一方面可以简化项目开发配置。
本文将会用两部分内容来简述 Buf 的使用流程,涵盖 Golang 服务端开发和前端开发的内容。
- 基于 Protobuf 生成 Golang 代码。
- 基于 Protobuf 生成 Typescript 类型定义代码。
Buf 安装
如果您使用的是 Macos,可以直接通过 Brew 安装。
代码语言:shell复制brew install bufbuild/buf/buf
如果您使用的是 Windows,推荐您通过 Golang 的 install 命令安装。
代码语言:shell复制# 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 配置如下所示。
代码语言: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。
代码语言:go复制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 协议文件的创建之后,我们的目录如图所示。
代码语言:shell复制.
└── 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 代码,值得注意的是第一次运行需要加载远程插件,具体耗时取决于您的网络条件。
代码语言:shell复制.
├── 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 类型定义代码,值得注意的是第一次运行同样需要加载远程插件,具体耗时取决于您的网络条件。
代码语言:shell复制.
├── 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