blob: d9e9b21ae1aed95c4dcbc54389601fad035ef248 [file]
"""**EXPERIMENTAL**: RPC support for JavaScript and TypeScript.
Note that if you are using Connect, you do not need any additional setup beyond
registering protoc-gen-es with a js_proto_toolchain. As of v2, protoc-gen-es
generates code for Connect right alongside the protobuf-es code, in the same
file.
This API is subject to breaking changes outside our usual semver policy.
In a future release of rules_js this should become stable.
### Typical setup
1. Choose a protoc plugin that generates RPC client code.
A common choice is `@connectrpc/protoc-gen-connect-query`, which generates
TanStack Query hooks for services defined in your proto files.
Add it as a devDependency in `package.json` under a `/tools` directory.
2. Declare a binary target that runs the generator, in `tools/toolchains/BUILD`:
```starlark
load("@npm//tools:@connectrpc/protoc-gen-connect-query/package_json.bzl", connect_query = "bin")
connect_query.protoc_gen_connect_query_binary(name = "protoc_gen_connect_query")
```
3. Define a `js_rpc_toolchain` that uses the plugin. See the rule documentation below.
4. Update `MODULE.bazel` to register it:
```starlark
register_toolchains("//tools/toolchains:all")
```
### Usage
Write `proto_library` targets with `service` definitions as usual. Use `js_library`
with proto deps to generate message serialization code, and `js_rpc_library` to generate
the RPC client stubs:
```starlark
load("@aspect_rules_js//js:defs.bzl", "js_library")
load("@aspect_rules_js//js:rpc.bzl", "js_rpc_library")
load("@protobuf//bazel:proto_library.bzl", "proto_library")
proto_library(
name = "eliza_proto",
srcs = ["eliza.proto"],
)
# Generates message serialization code (eliza_pb.js) via js_proto_aspect
js_library(
name = "eliza_js",
deps = [":eliza_proto"],
)
# Generates one file per service via protoc-gen-connect-query
js_rpc_library(
name = "eliza_rpc",
deps = [":eliza_proto"],
outs = [
"eliza-ElizaService_connectquery.js",
"eliza-ElizaService_connectquery.d.ts",
],
)
```
See the e2e/protobuf-es example for a ConnectQuery setup, or e2e/protobuf-google for a grpc-js setup.
"""
load("//js/private:js_proto_toolchain.bzl", _js_proto_toolchain = "js_proto_toolchain")
load("//js/private:rpc.bzl", "LANG_RPC_TOOLCHAIN", _js_rpc_library = "js_rpc_library")
js_rpc_library = _js_rpc_library
def js_rpc_toolchain(name, plugin_name, plugin_options, plugin_bin, runtime, out_dts_extension = None, out_js_extension = None, target_settings = [], exec_compatible_with = [], target_compatible_with = [], **kwargs):
"""Define a toolchain for a protoc plugin that generates RPC client code.
Example:
```starlark
js_rpc_toolchain(
name = "connect_query_toolchain",
plugin_bin = ":protoc_gen_connect_query",
plugin_name = "connect-query",
plugin_options = [
"target=js+dts",
"import_extension=js",
],
runtime = "//:node_modules/@connectrpc/connect-query-core",
)
```
Args:
name: The name of the toolchain. A target named [name]_toolchain is also created, which is the one to use in register_toolchains.
plugin_name: The `NAME` of the plugin program, used in command-line flags to protoc, as follows:
> `protoc --plugin=protoc-gen-NAME=path/to/mybinary --NAME_out=OUT_DIR`
See https://protobuf.dev/reference/cpp/api-docs/google.protobuf.compiler.plugin
plugin_options: (List of strings) Option strings passed to the plugin via --NAME_opt=.
plugin_bin: The plugin binary. This should be the label of a binary target declared using the plugin's package_json.bzl entry point.
runtime: The npm package that the generated code imports from at runtime.
Note that node module resolution requires the runtime to be in a parent folder of any package containing generated code.
out_dts_extension: The suffix that should replace ".proto" in determining the .d.ts output file name, or None if the plugin does not produce a type declaration file.
out_js_extension: The suffix that should replace ".proto" in determining the .js output file name.
If neither of the two above parameters are set, then each js_rpc_library target must indicate its expected outputs via the outs parameter.
target_settings: List of target config settings the toolchain is compatible with.
exec_compatible_with: List of constraint_values that the execution platform must be compatible with.
target_compatible_with: List of constraint values that the target platform must be compatible with.
**kwargs: Additional arguments to pass to the underlying rule.
"""
command_line_flags = ["--{}_opt={}".format(plugin_name, o) for o in plugin_options]
command_line_flags.append("--{}_out=$(OUT)".format(plugin_name))
_js_proto_toolchain(
name = name,
command_line = " ".join(command_line_flags),
plugin_format_flag = "--plugin=protoc-gen-{}=%s".format(plugin_name),
toolchain_type = LANG_RPC_TOOLCHAIN,
plugin = plugin_bin,
out_dts_extension = out_dts_extension,
out_js_extension = out_js_extension,
runtime = runtime,
**kwargs
)
native.toolchain(
name = name + "_toolchain",
toolchain_type = LANG_RPC_TOOLCHAIN,
toolchain = name,
target_settings = target_settings,
exec_compatible_with = exec_compatible_with,
target_compatible_with = target_compatible_with,
)