Search code examples
node.jstypescriptprotocol-buffersgrpcgrpc-node

The package import path is different for dynamic codegen and static codegen


Here is the structure for src directory of my project:

.
├── 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;
}

As you can see, I try to import share package and use UserBase message type in Topic message type. When I try to start the server, got error:

no such Type or Enum 'share.UserBase' in Type .topic.Topic

But when I changed the package import path to a relative path import "../share/user.proto";. It works fine and got server logs: Server is listening on http://localhost:3000.

Above is the usage of dynamic codegen.

Now, I switch to using static codegen, here is the shell script for generating the codes:

protoc \
  --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts \
  --ts_out=./src/protos \
  -I ./src/protos \
  ./src/protos/**/*.proto

It seems protocol buffer compiler doesn't support relative path, got error:

../share/user.proto: Backslashes, consecutive slashes, ".", or ".." are not allowed in the virtual path

And, I changed the the package import path back to import "share/user.proto";. It generated code correctly, but when I try to start my server, got same error:

no such Type or Enum 'share.UserBase' in Type .topic.Topic

It's weird.

Package versions:

"grpc-tools": "^1.6.6",
"grpc_tools_node_protoc_ts": "^4.1.3",
protoc --version                                                                  
libprotoc 3.10.0

UPDATE:

repo: https://github.com/mrdulin/nodejs-grpc/tree/master/src


Solution

  • Your dynamic codegen is failing because you are not specifying the paths to search for imported .proto files. You can do this using the includeDirs option when calling protoLoader.loadSync, which works in a very similar way to the -I option you pass to protoc. In this case, you are loading the proto files from the src/protos directory, so it should be sufficient to pass the option includeDirs: [__dirname]. Then the import paths in your .proto files should be relative to that directory, just like when you use protoc.

    You are probably seeing the same error when you try to use the static code generation because it is actually the dynamic codegen error; you don't appear to be removing the dynamic codegen code when trying to use the statically generated code.

    However, the main problem you will face with the statically generated code is that you are only generating the TypeScript type definition files. You also need to generate JavaScript files to actually run it. The official Node gRPC plugin for proto is distributed in the grpc-tools package. It comes with a binary called grpc_tools_node_protoc, which should be used in place of protoc and automatically includes the plugin. You will still need to pass a --js_out flag to generate that code.