Skip to content

Commit

Permalink
fixup! feat(typescript): allow alternative transpilers
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeagle committed Jan 3, 2022
1 parent e6c63cf commit a76ab93
Show file tree
Hide file tree
Showing 6 changed files with 264 additions and 59 deletions.
27 changes: 11 additions & 16 deletions docs/TypeScript.md
Original file line number Diff line number Diff line change
Expand Up @@ -474,9 +474,9 @@ Defaults to `False`
<pre>
ts_project(<a href="#ts_project-name">name</a>, <a href="#ts_project-tsconfig">tsconfig</a>, <a href="#ts_project-srcs">srcs</a>, <a href="#ts_project-args">args</a>, <a href="#ts_project-deps">deps</a>, <a href="#ts_project-extends">extends</a>, <a href="#ts_project-allow_js">allow_js</a>, <a href="#ts_project-declaration">declaration</a>, <a href="#ts_project-source_map">source_map</a>,
<a href="#ts_project-declaration_map">declaration_map</a>, <a href="#ts_project-resolve_json_module">resolve_json_module</a>, <a href="#ts_project-preserve_jsx">preserve_jsx</a>, <a href="#ts_project-composite">composite</a>, <a href="#ts_project-incremental">incremental</a>,
<a href="#ts_project-emit_declaration_only">emit_declaration_only</a>, <a href="#ts_project-transpiler">transpiler</a>, <a href="#ts_project-transpiler_kwargs">transpiler_kwargs</a>, <a href="#ts_project-ts_build_info_file">ts_build_info_file</a>, <a href="#ts_project-tsc">tsc</a>,
<a href="#ts_project-typescript_package">typescript_package</a>, <a href="#ts_project-typescript_require_path">typescript_require_path</a>, <a href="#ts_project-validate">validate</a>, <a href="#ts_project-supports_workers">supports_workers</a>, <a href="#ts_project-declaration_dir">declaration_dir</a>,
<a href="#ts_project-out_dir">out_dir</a>, <a href="#ts_project-root_dir">root_dir</a>, <a href="#ts_project-link_workspace_root">link_workspace_root</a>, <a href="#ts_project-kwargs">kwargs</a>)
<a href="#ts_project-emit_declaration_only">emit_declaration_only</a>, <a href="#ts_project-transpiler">transpiler</a>, <a href="#ts_project-ts_build_info_file">ts_build_info_file</a>, <a href="#ts_project-tsc">tsc</a>, <a href="#ts_project-typescript_package">typescript_package</a>,
<a href="#ts_project-typescript_require_path">typescript_require_path</a>, <a href="#ts_project-validate">validate</a>, <a href="#ts_project-supports_workers">supports_workers</a>, <a href="#ts_project-declaration_dir">declaration_dir</a>, <a href="#ts_project-out_dir">out_dir</a>, <a href="#ts_project-root_dir">root_dir</a>,
<a href="#ts_project-link_workspace_root">link_workspace_root</a>, <a href="#ts_project-kwargs">kwargs</a>)
</pre>

Compiles one TypeScript project using `tsc --project`
Expand Down Expand Up @@ -736,8 +736,8 @@ Defaults to `False`
<h4 id="ts_project-transpiler">transpiler</h4>
What tool to run that produces the JavaScript outputs.
By default, this is the string `tsc` which means to produce `.js` outputs
in the same action that does the type-checking to produce `.d.ts` outputs.
By default, this is the string `tsc`. With that value, `ts_project` expects `.js` outputs
to be written in the same action that does the type-checking to produce `.d.ts` outputs.
This is the simplest configuration, however `tsc` is slower than alternatives.
It also means developers must wait for the type-checking in the developer loop.
Expand All @@ -747,21 +747,16 @@ can only see one set of dependencies, and so it cannot be shared between differe
`ts_project` rules. That attribute is documented as experimental, and may never graduate
to a better support contract.
Instead, you can pass a rule or macro that accepts these arguments:
`(name, srcs, js_outs, map_outs, args, data, tags, visibility)`
Instead of the string `tsc`, this attribute also accepts a rule or macro that accepts these arguments:
`name, srcs, js_outs, map_outs, args, data, tags, visibility, testonly`
The rules_nodejs authors believe that [SWC](https://swc.rs) is a great choice.
If you need to pass additional arguments to the transpiler, you can use a partial
https://github.com/bazelbuild/bazel-skylib/blob/main/lib/partial.bzl
to bind some arguments at the "make site", then pass that partial to this attribute where it
will be called with the remaining arguments.
Defaults to `"tsc"`
<h4 id="ts_project-transpiler_kwargs">transpiler_kwargs</h4>
if the `transpiler` attribute is a rule or macro, then this dictionary
is passed as additional keyword arguments of that rule or macro.
For example if the transpiler accepts `args`, then use `transpiler_kwargs={"args": ["some-arg"]}`
Defaults to `{}`
<h4 id="ts_project-ts_build_info_file">ts_build_info_file</h4>
the user-specified value of `tsBuildInfoFile` from the tsconfig.
Expand Down
48 changes: 28 additions & 20 deletions packages/typescript/internal/ts_project.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
load("@build_bazel_rules_nodejs//:providers.bzl", "DeclarationInfo", "ExternalNpmPackageInfo", "declaration_info", "js_module_info", "run_node")
load("@build_bazel_rules_nodejs//internal/linker:link_node_modules.bzl", "module_mappings_aspect")
load("@build_bazel_rules_nodejs//internal/node:node.bzl", "nodejs_binary")
load("@build_bazel_rules_nodejs//third_party/github.com/bazelbuild/bazel-skylib:lib/partial.bzl", "partial")
load(":ts_config.bzl", "TsConfigInfo", "write_tsconfig")

_ValidOptionsInfo = provider()
Expand Down Expand Up @@ -372,7 +373,6 @@ def ts_project_macro(
incremental = False,
emit_declaration_only = False,
transpiler = "tsc",
transpiler_kwargs = {},
ts_build_info_file = None,
tsc = None,
typescript_package = _DEFAULT_TYPESCRIPT_PACKAGE,
Expand Down Expand Up @@ -547,8 +547,8 @@ def ts_project_macro(
args: List of strings of additional command-line arguments to pass to tsc.
transpiler: What tool to run that produces the JavaScript outputs.
By default, this is the string `tsc` which means to produce `.js` outputs
in the same action that does the type-checking to produce `.d.ts` outputs.
By default, this is the string `tsc`. With that value, `ts_project` expects `.js` outputs
to be written in the same action that does the type-checking to produce `.d.ts` outputs.
This is the simplest configuration, however `tsc` is slower than alternatives.
It also means developers must wait for the type-checking in the developer loop.
Expand All @@ -558,14 +558,13 @@ def ts_project_macro(
`ts_project` rules. That attribute is documented as experimental, and may never graduate
to a better support contract.
Instead, you can pass a rule or macro that accepts these arguments:
`(name, srcs, js_outs, map_outs, args, data, tags, visibility)`
Instead of the string `tsc`, this attribute also accepts a rule or macro that accepts these arguments:
`name, srcs, js_outs, map_outs, args, data, tags, visibility, testonly`
The rules_nodejs authors believe that [SWC](https://swc.rs) is a great choice.
transpiler_kwargs: if the `transpiler` attribute is a rule or macro, then this dictionary
is passed as additional keyword arguments of that rule or macro.
For example if the transpiler accepts `args`, then use `transpiler_kwargs={"args": ["some-arg"]}`
If you need to pass additional arguments to the transpiler, you can use a partial
https://github.com/bazelbuild/bazel-skylib/blob/main/lib/partial.bzl
to bind some arguments at the "make site", then pass that partial to this attribute where it
will be called with the remaining arguments.
tsc: Label of the TypeScript compiler binary to run.
Expand Down Expand Up @@ -783,9 +782,12 @@ def ts_project_macro(
if declaration_map:
typing_maps_outs.extend(_out_paths(srcs, typings_out_dir, root_dir, allow_js, {"*": ".d.ts.map"}))

if type(transpiler) == "function" or type(transpiler) == "rule":
tsc_js_outs = []
tsc_map_outs = []
tsc_js_outs = []
tsc_map_outs = []
if transpiler == "tsc":
tsc_js_outs = js_outs
tsc_map_outs = map_outs
elif type(transpiler) == "function" or type(transpiler) == "rule":
transpiler(
name = name + "_transpile",
srcs = srcs,
Expand All @@ -795,15 +797,21 @@ def ts_project_macro(
tags = kwargs.get("tags", []),
visibility = kwargs.get("visibility", None),
testonly = kwargs.get("testonly", None),
**transpiler_kwargs
)
elif transpiler == "tsc":
tsc_js_outs = js_outs
tsc_map_outs = map_outs
if len(transpiler_kwargs.keys()):
fail("transpiler_kwargs should not be used with `transpiler='tsc'`, just pass them to the `args`")
elif partial.is_instance(transpiler):
partial.call(
transpiler,
name = name + "_transpile",
srcs = srcs,
js_outs = js_outs,
map_outs = map_outs,
data = [],
tags = kwargs.get("tags", []),
visibility = kwargs.get("visibility", None),
testonly = kwargs.get("testonly", None),
)
else:
fail("transpiler attribute should be a rule/macro or the string 'tsc'.")
fail("transpiler attribute should be a rule/macro, a skylib partial, or the string 'tsc'. Got " + type(transpiler))

if not len(tsc_js_outs) and not len(typings_outs):
fail("""ts_project target "//{}:{}" is configured to produce no outputs.
Expand Down
22 changes: 17 additions & 5 deletions packages/typescript/test/ts_project/swc/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
load("@bazel_skylib//rules:write_file.bzl", "write_file")
load("//packages/typescript:index.bzl", "ts_project")
load(":mock_swc.bzl", "swc")
load(":swc.bzl", "swc", "swc_macro")

write_file(
name = "gen_ts",
Expand All @@ -14,11 +14,23 @@ write_file(
ts_project(
name = "transpile_with_swc",
srcs = ["big.ts"],
transpiler = swc,
transpiler_kwargs = {
"args": ["--env-name=test"],
"swcrc": ".swcrc",
transpiler = swc_macro,
tsconfig = {
"compilerOptions": {
"declaration": True,
"sourceMap": True,
},
},
)

ts_project(
name = "transpile_with_configurable_swc",
srcs = ["big.ts"],
out_dir = "configurable",
transpiler = swc(
args = ["--env-name=test"],
swcrc = "//:.swcrc",
),
tsconfig = {
"compilerOptions": {
"declaration": True,
Expand Down
18 changes: 0 additions & 18 deletions packages/typescript/test/ts_project/swc/mock_swc.bzl

This file was deleted.

32 changes: 32 additions & 0 deletions packages/typescript/test/ts_project/swc/swc.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"Fixture to demonstrate a custom transpiler for ts_project"

load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
load("@bazel_skylib//rules:write_file.bzl", "write_file")
load("@bazel_skylib//lib:partial.bzl", "partial")

_DUMMY_SOURCEMAP = """{"version":3,"sources":["%s"],"mappings":"AAAO,KAAK,CAAC","file":"in.js","sourcesContent":["fake"]}"""

def swc_macro(name, srcs, js_outs, map_outs, **kwargs):
"""Mock swc transpiler macro.
In real usage you would wrap a rule like
https://github.com/aspect-build/rules_swc/blob/main/docs/swc.md
"""

for i, s in enumerate(srcs):
copy_file(
name = "_{}_{}_js".format(name, s),
src = s,
out = js_outs[i],
)

write_file(
name = "_{}_{}_map".format(name, s),
out = map_outs[i],
content = [_DUMMY_SOURCEMAP % s],
)

# In Bazel 5, we could use a lambda to build a higher-order function
# but for Bazel 4 and below, we need partials.
def swc(args = [], swcrc = None):
return partial.make(swc_macro, args = args, swcrc = swcrc)
Loading

0 comments on commit a76ab93

Please sign in to comment.