Sus*_*ath 5 bazel bazel-rules bazel-rules-nodejs
我正在 js 中为 mono 仓库编写 bazel 规则。这背后的想法是 Mono 存储库(微服务)内的服务在开放的 api 模式文件中定义 api 规范。在我们的例子中,这些模式位于 ts 文件中,因为当每个路由和最终规范文件导入每个路由模式并集成到最终对象时,规范被破坏。
我想在集中位置编写 bazel 规则,以便每个项目都可以加载该规则并使用其架构文件调用它
generate_yaml_from_ts(
name = 'generate_yaml',
schema = "src/api/routes/openapi.schema.ts"
)
Run Code Online (Sandbox Code Playgroud)
我不确定是否所有模式文件( openapi.schema.ts 导入其他 ts 文件)都需要可供规则使用。
在规则中,我有一个 ts 代码,我想在其中引用传递的模式文件并生成yaml
文件。(如下所示,我知道静态导入不起作用)
import fs from 'fs';
import YAML from 'yaml';
import openapiJson from './src/api/routes/openapi.schema';
fs.writeFileSync(process.argv[2], YAML.stringify(openapiJson));
Run Code Online (Sandbox Code Playgroud)
我创建了一个节点可执行文件以从代码运行ts-node
,但问题是我们提供的输入也是ts
文件,因此需要首先编译。
我可以想到两种可能的方法来解决这个问题,但我不确定到底该怎么做。
ts
在从服务传递到规则之前编译架构。(使用 ats_library
并将输出传递给规则?)ts-node
在 bzl 文件中使用),传递源文件连接generateYml.ts
和传递的模式文件。github上提供了带有 bazel 设置的简单项目
我编写了一条规则,从项目中获取 json 文件并生成build/rules/json2yaml
有效的 yaml。
努力用 type script it in 做同样的事情build/rules/ts-yaml
。
我的问题如下
ts_library
并传递 bazel 规则的输出吗?我找到了一种方法来完成这件事,所以我会尝试解释一下,这样如果其他人也必须这样做,这可能会挽救他的一天。
首先,将ts
文件作为参数传递的问题是它们需要在运行之前进行编译。通常,当您使用或创建可执行文件时ts-node
,您已有的处理部分会被编译,但参数不会。ts_project
nodejs_binary
所以我需要的是在运行时编译和执行打字稿的东西。以下是我找到的解决方案。
您可以使用 require('ts-node').register({ /* options */ }) 来 require ts-node 并注册加载器以供将来使用。您还可以使用文件快捷方式 - node -r ts-node/register 或 node -r ts-node/register/transpile-only - 根据您的喜好。文档在这里
基本上你可以在运行时执行以下操作并导入打字稿。
require('ts-node').register({/* options */})
const something = require('some-ts-file`);
Run Code Online (Sandbox Code Playgroud)
所以我的 yaml 生成器代码可以使用它来导入作为参数传递的 ts 文件。
首先是规则的 BUILD.bazel
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
nodejs_binary(
name = "ys-2-yaml",
data = [
"main.js",
"@npm//yaml",
"@npm//openapi-core",
"@npm//ts-node"
],
entry_point = "main.js",
visibility = ["//visibility:public"],
)
Run Code Online (Sandbox Code Playgroud)
main.js
是要进行处理的文件。它需要yaml
npm 提供的库,并ts-node
在运行时加载打字稿文件。
Bazel 规则如下
"""Generate the openapi yml file from the JSON version."""
def _generateYaml(ctx):
inputs = [] + ctx.files.schemas
inputs.extend(ctx.attr.generator[DefaultInfo].data_runfiles.files.to_list())
ctx.actions.run(
inputs = inputs,
outputs = [ctx.outputs.yaml],
arguments = [ctx.outputs.yaml.path, ctx.file.main_file.path],
executable = ctx.executable.generator,
)
ts_2_yaml = rule(
implementation = _generateYaml,
attrs = {
"generator": attr.label(
default = "//build/rules/tsnoderegister:ys-2-yaml",
cfg = "target",
executable = True,
),
"schemas": attr.label_list(default = [], allow_files = True),
"main_file": attr.label(
allow_single_file = True,
mandatory = True,
),
},
outputs = {
"yaml": "openapi.yaml",
},
)
Run Code Online (Sandbox Code Playgroud)
可执行文件(生成器)是nodejs_binary
之前的目标。规则需要两个参数。schemas
这是 ts 代码中的模式文件。这是多个文件的原因是模式被分解为不同的对象并与每个路由一起存储以提高可读性。因此,主模式文件导入并将所有内容附加在一起。我需要另一个变量,以便规则知道哪个是主模式文件。因此,通过传递inputs
和 main ts 文件作为参数传递,模式文件可供可执行文件使用。
以下是main.js
文件。
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
nodejs_binary(
name = "ys-2-yaml",
data = [
"main.js",
"@npm//yaml",
"@npm//openapi-core",
"@npm//ts-node"
],
entry_point = "main.js",
visibility = ["//visibility:public"],
)
Run Code Online (Sandbox Code Playgroud)
基本上它导入传递的打字稿文件并解析yaml
并将其保存到文件中。路径有一点问题(因此../../../
),我需要做得更优雅。
最后规则可以在传递模式的包中使用,如下所示。
load("//build/rules/tsnoderegister:runtimets.bzl", "ts_2_yaml")
ts_2_yaml(
name = "generate_yaml",
schemas = glob(["src/**/*schema.ts"]),
main_file = "src/api/routes/openapi.schema.ts"
)
Run Code Online (Sandbox Code Playgroud)
运行目标和规则将生成yaml文件
"""Generate the openapi yml file from the JSON version."""
def _generateYaml(ctx):
inputs = [] + ctx.files.schemas
inputs.extend(ctx.attr.generator[DefaultInfo].data_runfiles.files.to_list())
ctx.actions.run(
inputs = inputs,
outputs = [ctx.outputs.yaml],
arguments = [ctx.outputs.yaml.path, ctx.file.main_file.path],
executable = ctx.executable.generator,
)
ts_2_yaml = rule(
implementation = _generateYaml,
attrs = {
"generator": attr.label(
default = "//build/rules/tsnoderegister:ys-2-yaml",
cfg = "target",
executable = True,
),
"schemas": attr.label_list(default = [], allow_files = True),
"main_file": attr.label(
allow_single_file = True,
mandatory = True,
),
},
outputs = {
"yaml": "openapi.yaml",
},
)
Run Code Online (Sandbox Code Playgroud)
const fs = require("fs");
const yaml = require("yaml");
require("ts-node").register({
transpileOnly: true,
// insert other options with a boolean flag here
});
const schemaFile = require("../../../" + process.argv[3]);
fs.writeFileSync(process.argv[2], yaml.stringify(schemaFile));
Run Code Online (Sandbox Code Playgroud)
本例的gihub代码链接