diff --git a/packages/typescript/install.md b/packages/typescript/install.md index 4d5e461a16..9c762f3726 100644 --- a/packages/typescript/install.md +++ b/packages/typescript/install.md @@ -6,18 +6,26 @@ The TypeScript rules integrate the TypeScript compiler with Bazel. This package provides Bazel wrappers around the TypeScript compiler. -At a high level, there are two alternatives provided: `ts_project` and `ts_library`. +At a high level, there are three alternatives provided: `tsc`, `ts_project`, `ts_library`. This section describes the trade-offs between these rules. +`tsc` is the raw TypeScript compiler published by the team at Microsoft. +Like any npm package that exposes a binary, rules_nodejs will generate an `index.bzl` file allowing +you to run `tsc`. + +To use it, add the load statement `load("@npm//typescript:index.bzl", "tsc")` to your BUILD file. +Then call it, using the [`npm_package_bin`](Built-ins#npm_package_bin) documentation. + +The only reason to use raw `tsc` is if you want to compile an opaque directory of `.ts` files and cannot enumerate them to Bazel. +(For example if the `.ts` files are generated by some tool). +This will produce an opaque directory of `.js` file outputs, which you won't be able to individually reference. +Any other use case for `tsc` is better served by using `ts_project`. + `ts_project` simply runs `tsc --project`, with Bazel knowing which outputs to expect based on the TypeScript compiler options, and with interoperability with other TypeScript rules via a Bazel Provider (DeclarationInfo) that transmits the type information. It is intended as an easy on-boarding for existing TypeScript code and should be familiar if your background is in frontend ecosystem idioms. Any behavior of `ts_project` should be reproducible outside of Bazel, with a couple of caveats noted in the rule documentation below. -> We used to recommend using the `tsc` rule directly from the `typescript` project, like -> `load("@npm//typescript:index.bzl", "tsc")` -> However `ts_project` is strictly better and should be used instead. - -`ts_library` is an open-sourced version of the rule we use to compile TS code at Google. +`ts_library` is an open-sourced version of the rule used to compile TS code at Google. It should be familiar if your background is in Bazel idioms. It is very complex, involving code generation of the `tsconfig.json` file, a custom compiler binary, and a lot of extra features. It is also opinionated, and may not work with existing TypeScript code. For example: diff --git a/packages/typescript/internal/ts_project.bzl b/packages/typescript/internal/ts_project.bzl index 49b48f7b1d..7a094a5f66 100644 --- a/packages/typescript/internal/ts_project.bzl +++ b/packages/typescript/internal/ts_project.bzl @@ -597,7 +597,7 @@ def ts_project_macro( write_tsconfig( name = "_gen_tsconfig_%s" % name, config = tsconfig, - files = srcs, + files = [s for s in srcs if _is_ts_src(s, allow_js)], extends = Label("//%s:%s" % (native.package_name(), name)).relative(extends) if extends else None, out = "tsconfig_%s.json" % name, ) @@ -659,6 +659,26 @@ def ts_project_macro( typings_out_dir = declaration_dir if declaration_dir else out_dir tsbuildinfo_path = ts_build_info_file if ts_build_info_file else name + ".tsbuildinfo" + js_outs = [] + map_outs = [] + typings_outs = [] + typing_maps_outs = [] + + if not emit_declaration_only: + js_outs.extend(_out_paths(srcs, out_dir, root_dir, False, ".js")) + if source_map and not emit_declaration_only: + map_outs.extend(_out_paths(srcs, out_dir, root_dir, False, ".js.map")) + if declaration or composite: + typings_outs.extend(_out_paths(srcs, typings_out_dir, root_dir, allow_js, ".d.ts")) + if declaration_map: + typing_maps_outs.extend(_out_paths(srcs, typings_out_dir, root_dir, allow_js, ".d.ts.map")) + + if not len(js_outs) and not len(typings_outs): + fail("""ts_project target "//{}:{}" is configured to produce no outputs. + +Note that ts_project must know the srcs in advance in order to predeclare the outputs. +Check the srcs attribute to see that some .ts files are present (or .js files with allow_js=True). +""".format(native.package_name(), name)) ts_project( name = name, @@ -670,10 +690,10 @@ def ts_project_macro( declaration_dir = declaration_dir, out_dir = out_dir, root_dir = root_dir, - js_outs = _out_paths(srcs, out_dir, root_dir, False, ".js") if not emit_declaration_only else [], - map_outs = _out_paths(srcs, out_dir, root_dir, False, ".js.map") if source_map and not emit_declaration_only else [], - typings_outs = _out_paths(srcs, typings_out_dir, root_dir, allow_js, ".d.ts") if declaration or composite else [], - typing_maps_outs = _out_paths(srcs, typings_out_dir, root_dir, allow_js, ".d.ts.map") if declaration_map else [], + js_outs = js_outs, + map_outs = map_outs, + typings_outs = typings_outs, + typing_maps_outs = typing_maps_outs, buildinfo_out = tsbuildinfo_path if composite or incremental else None, tsc = tsc, link_workspace_root = link_workspace_root, diff --git a/packages/typescript/test/ts_project/empty_intermediate/BUILD.bazel b/packages/typescript/test/ts_project/empty_intermediate/BUILD.bazel index 66c24cb239..67df17b285 100644 --- a/packages/typescript/test/ts_project/empty_intermediate/BUILD.bazel +++ b/packages/typescript/test/ts_project/empty_intermediate/BUILD.bazel @@ -1,18 +1,24 @@ -load("//packages/typescript:index.bzl", "ts_project") +# Use the ts_project rule directly, not the wrapper macro. We don't want checking for empty outs. +load("//packages/typescript/internal:ts_project.bzl", "ts_project") ts_project( name = "tsconfig-a", srcs = ["a.d.ts"], + tsconfig = ":tsconfig-a.json", ) +# Just verify that the a.d.ts file is transitively propagated ts_project( name = "tsconfig-b", srcs = [], + tsconfig = ":tsconfig-b.json", deps = ["tsconfig-a"], ) ts_project( name = "tsconfig-c", srcs = ["c.ts"], + js_outs = ["c.js"], + tsconfig = ":tsconfig-c.json", deps = ["tsconfig-b"], ) diff --git a/packages/typescript/test/ts_project/json/BUILD.bazel b/packages/typescript/test/ts_project/json/BUILD.bazel index b14abdc6f9..be14cdba0e 100644 --- a/packages/typescript/test/ts_project/json/BUILD.bazel +++ b/packages/typescript/test/ts_project/json/BUILD.bazel @@ -25,7 +25,14 @@ ts_project( ts_project( name = "tsconfig-decl-only", srcs = SRCS, - emit_declaration_only = True, + tsconfig = { + "compilerOptions": { + "declaration": True, + "emitDeclarationOnly": True, + "resolveJsonModule": True, + "types": [], + }, + }, ) nodejs_test(