【问题标题】:Execute typescript files passed as arguments from a bazel rule执行从 bazel 规则作为参数传递的打字稿文件
【发布时间】:2021-09-23 12:30:10
【问题描述】:

我正在 js 中为一个单一的 repo 编写一个 bazel 规则。这背后的想法是mono repo(微服务)中的服务在开放的api模式文件中定义了api规范。在我们的例子中,这些模式在 ts 文件中,因为规范被破坏,因为每个路由和最终规范文件导入每个路由模式并集成到最终对象。

我想在一个集中位置编写一个 bazel 规则,以便每个项目都可以加载该规则并使用它的架构文件调用它

generate_yaml_from_ts(
    name = 'generate_yaml',
    schema = "src/api/routes/openapi.schema.ts"
)

我不确定是否所有架构文件(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));

我创建了一个节点可执行文件以使用 ts-node 从代码运行,但问题是我们提供的输入也是 ts 文件,因此需要先编译。

我可以想到两种可能的方法来解决这个问题,但我都不确定该怎么做。

  1. 在从服务传递到规则之前编译架构ts。 (使用ts_library 并将输出传递给规则?)
  2. 在规则处创建 ts 可执行文件(在 bzl 文件中使用 ts-node)传递源文件,并连接 generateYml.ts 和传递的架构文件。

带有 bazel 设置的简单项目可在 github 获得

我写了一个规则来从项目中获取一个 json 文件并生成 yaml build/rules/json2yaml 可以工作。

努力在build/rules/ts-yaml 中输入脚本。

我的问题如下

  • 我可以使用ts_library 并通过输出bazel 规则吗?
  • 我可以从服务传递 ts 文件并从规则 sile 编译和执行逻辑(更好)吗?

【问题讨论】:

    标签: bazel bazel-rules bazel-rules-nodejs


    【解决方案1】:

    我能够找到一种方法来完成这项工作,因此我将尝试解释它,以便如果其他人必须这样做,这可能会节省他的时间。

    首先,将ts 文件作为参数传递的问题是它们需要在运行之前进行编译。通常,当您使用ts-nodets_projectnodejs_binary 创建可执行文件时,您已经拥有的处理部分会被编译,但参数不会。

    所以我需要的是在运行时编译和执行 typescript 的东西。以下是我找到的解决方案。

    您可以要求 ts-node 并注册加载程序以备将来需要 使用 require('ts-node').register({ /* options */ })。你也可以使用 文件快捷方式 - node -r ts-node/register 或 node -r ts-node/register/transpile-only - 取决于您的偏好。 文档here

    基本上你可以在运行时执行以下操作并导入打字稿。

        require('ts-node').register({/* options */})
        
        const something = require('some-ts-file`);
    

    所以我的 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"],
    )
    

    main.js 是要进行处理的文件。它需要来自 npm 的 yaml 库,因此提供了 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",
        },
    )
        
    

    executable(generator) 是之前的 nodejs_binary 目标。规则需要两个参数。 schemas 是 ts 代码中的架构文件。这是多个文件的原因是架构被分解为不同的对象并与每个路由一起存储以提高可读性。因此,主模式文件将所有内容导入并附加在一起。我需要另一个变量,以便规则知道哪个是主模式文件。因此,通过传递给inputs 和主 ts 文件作为参数传递给可执行文件。

    下面是main.js 文件。

    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));
    
    

    基本上它会导入传递的打字稿文件并解析为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"
    )
    

    运行目标和规则会生成yaml文件

    bazel build //services/my-sample-service:generate_yaml
    
    bazel build //services/my-sample-service:generate_yaml
    INFO: Analyzed target //services/my-sample-service:generate_yaml (0 packages loaded, 0 targets configured).
    INFO: Found 1 target...
    Target //services/my-sample-service:generate_yaml up-to-date:
      bazel-bin/services/my-sample-service/openapi.yaml
    INFO: Elapsed time: 0.053s, Critical Path: 0.00s
    INFO: 1 process: 1 internal.
    INFO: Build completed successfully, 1 total action
    

    链接到这个例子的 gihub code

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-26
      • 1970-01-01
      • 2022-12-01
      • 2017-12-01
      • 2021-06-17
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多