动态代码生成和静态代码生成的包导入路径不同
The package import path is different for dynamic codegen and static codegen
这是我的项目 src
目录的结构:
.
├── config.ts
├── protos
│ ├── index.proto
│ ├── index.ts
│ ├── share
│ │ ├── topic.proto
│ │ ├── topic_pb.d.ts
│ │ ├── user.proto
│ │ └── user_pb.d.ts
│ ├── topic
│ │ ├── service.proto
│ │ ├── service_grpc_pb.d.ts
│ │ ├── service_pb.d.ts
│ │ ├── topic.integration.test.ts
│ │ ├── topic.proto
│ │ ├── topicServiceImpl.ts
│ │ ├── topicServiceImplDynamic.ts
│ │ └── topic_pb.d.ts
│ └── user
│ ├── service.proto
│ ├── service_grpc_pb.d.ts
│ ├── service_pb.d.ts
│ ├── user.proto
│ ├── userServiceImpl.ts
│ └── user_pb.d.ts
└── server.ts
share/user.proto
:
syntax = "proto3";
package share;
message UserBase {
string loginname = 1;
string avatar_url = 2;
}
topic/topic.proto
:
syntax = "proto3";
package topic;
import "share/user.proto";
enum Tab {
share = 0;
ask = 1;
good = 2;
job = 3;
}
message Topic {
string id = 1;
string author_id = 2;
Tab tab = 3;
string title = 4;
string content = 5;
share.UserBase author = 6;
bool good = 7;
bool top = 8;
int32 reply_count = 9;
int32 visit_count = 10;
string create_at = 11;
string last_reply_at = 12;
}
如您所见,我尝试导入 share
包并在 Topic
消息类型中使用 UserBase
消息类型。当我尝试启动服务器时,出现错误:
no such Type or Enum 'share.UserBase' in Type .topic.Topic
但是当我将包导入路径更改为相对路径时import "../share/user.proto";
。它工作正常并获得服务器日志:Server is listening on http://localhost:3000
.
以上是dynamic codegen的用法
现在,我切换到使用静态代码生成器,这里是用于生成代码的 shell 脚本:
protoc \
--plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts \
--ts_out=./src/protos \
-I ./src/protos \
./src/protos/**/*.proto
protocol buffer编译器似乎不支持相对路径,出现错误:
../share/user.proto: Backslashes, consecutive slashes, ".", or ".." are not allowed in the virtual path
并且,我将包导入路径改回 import "share/user.proto";
。它正确地生成了代码,但是当我尝试启动我的服务器时,出现了同样的错误:
no such Type or Enum 'share.UserBase' in Type .topic.Topic
很奇怪。
包版本:
"grpc-tools": "^1.6.6",
"grpc_tools_node_protoc_ts": "^4.1.3",
protoc --version
libprotoc 3.10.0
更新:
您的动态代码生成失败,因为您没有指定搜索导入的 .proto
文件的路径。您可以在调用 protoLoader.loadSync
时使用 includeDirs
选项来执行此操作,其工作方式与传递给 protoc
的 -I
选项非常相似。在这种情况下,您将从 src/protos
目录加载原型文件,因此传递选项 includeDirs: [__dirname]
应该就足够了。然后 .proto
文件中的导入路径应该是相对于该目录的,就像您使用 protoc
.
一样
当您尝试使用静态代码生成时,您可能会看到同样的错误,因为它实际上是动态代码生成错误;在尝试使用静态生成的代码时,您似乎没有删除动态代码生成代码。
但是,静态生成的代码将面临的主要问题是您只生成 TypeScript 类型定义文件。您还需要生成 JavaScript 个文件才能真正 运行 它。 proto
的官方 Node gRPC 插件在 grpc-tools
包中分发。它带有一个名为 grpc_tools_node_protoc
的二进制文件,应该用来代替 protoc
并自动包含该插件。您仍然需要传递一个 --js_out
标志来生成该代码。
这是我的项目 src
目录的结构:
.
├── config.ts
├── protos
│ ├── index.proto
│ ├── index.ts
│ ├── share
│ │ ├── topic.proto
│ │ ├── topic_pb.d.ts
│ │ ├── user.proto
│ │ └── user_pb.d.ts
│ ├── topic
│ │ ├── service.proto
│ │ ├── service_grpc_pb.d.ts
│ │ ├── service_pb.d.ts
│ │ ├── topic.integration.test.ts
│ │ ├── topic.proto
│ │ ├── topicServiceImpl.ts
│ │ ├── topicServiceImplDynamic.ts
│ │ └── topic_pb.d.ts
│ └── user
│ ├── service.proto
│ ├── service_grpc_pb.d.ts
│ ├── service_pb.d.ts
│ ├── user.proto
│ ├── userServiceImpl.ts
│ └── user_pb.d.ts
└── server.ts
share/user.proto
:
syntax = "proto3";
package share;
message UserBase {
string loginname = 1;
string avatar_url = 2;
}
topic/topic.proto
:
syntax = "proto3";
package topic;
import "share/user.proto";
enum Tab {
share = 0;
ask = 1;
good = 2;
job = 3;
}
message Topic {
string id = 1;
string author_id = 2;
Tab tab = 3;
string title = 4;
string content = 5;
share.UserBase author = 6;
bool good = 7;
bool top = 8;
int32 reply_count = 9;
int32 visit_count = 10;
string create_at = 11;
string last_reply_at = 12;
}
如您所见,我尝试导入 share
包并在 Topic
消息类型中使用 UserBase
消息类型。当我尝试启动服务器时,出现错误:
no such Type or Enum 'share.UserBase' in Type .topic.Topic
但是当我将包导入路径更改为相对路径时import "../share/user.proto";
。它工作正常并获得服务器日志:Server is listening on http://localhost:3000
.
以上是dynamic codegen的用法
现在,我切换到使用静态代码生成器,这里是用于生成代码的 shell 脚本:
protoc \
--plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts \
--ts_out=./src/protos \
-I ./src/protos \
./src/protos/**/*.proto
protocol buffer编译器似乎不支持相对路径,出现错误:
../share/user.proto: Backslashes, consecutive slashes, ".", or ".." are not allowed in the virtual path
并且,我将包导入路径改回 import "share/user.proto";
。它正确地生成了代码,但是当我尝试启动我的服务器时,出现了同样的错误:
no such Type or Enum 'share.UserBase' in Type .topic.Topic
很奇怪。
包版本:
"grpc-tools": "^1.6.6",
"grpc_tools_node_protoc_ts": "^4.1.3",
protoc --version
libprotoc 3.10.0
更新:
您的动态代码生成失败,因为您没有指定搜索导入的 .proto
文件的路径。您可以在调用 protoLoader.loadSync
时使用 includeDirs
选项来执行此操作,其工作方式与传递给 protoc
的 -I
选项非常相似。在这种情况下,您将从 src/protos
目录加载原型文件,因此传递选项 includeDirs: [__dirname]
应该就足够了。然后 .proto
文件中的导入路径应该是相对于该目录的,就像您使用 protoc
.
当您尝试使用静态代码生成时,您可能会看到同样的错误,因为它实际上是动态代码生成错误;在尝试使用静态生成的代码时,您似乎没有删除动态代码生成代码。
但是,静态生成的代码将面临的主要问题是您只生成 TypeScript 类型定义文件。您还需要生成 JavaScript 个文件才能真正 运行 它。 proto
的官方 Node gRPC 插件在 grpc-tools
包中分发。它带有一个名为 grpc_tools_node_protoc
的二进制文件,应该用来代替 protoc
并自动包含该插件。您仍然需要传递一个 --js_out
标志来生成该代码。