Skip to content

Commit

Permalink
feat(typescript): add ts_project rule (#1710)
Browse files Browse the repository at this point in the history
This is a very thin layer on top of vanilla tsc
  • Loading branch information
alexeagle authored Mar 24, 2020
1 parent 7afaa48 commit 26f6698
Show file tree
Hide file tree
Showing 33 changed files with 559 additions and 50 deletions.
3 changes: 3 additions & 0 deletions examples/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ example_integration_test(
name = "examples_react_webpack",
# TODO: add some tests in the example
bazel_commands = ["build ..."],
npm_packages = {
"//packages/typescript:npm_package": "@bazel/typescript",
},
# TODO(alexeagle): somehow this is broken by the new node-patches based node_patches script
# ERROR: D:/temp/tmp-6900sejcsrcttpdb/BUILD.bazel:37:1: output 'app.bundle.js' was not created
tags = ["no-bazelci-windows"],
Expand Down
20 changes: 3 additions & 17 deletions examples/react_webpack/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
load("@npm//http-server:index.bzl", "http_server")
load("@npm//sass:index.bzl", "sass")
load("@npm//typescript:index.bzl", "tsc")
load("@npm//webpack-cli:index.bzl", webpack = "webpack_cli")
load("@npm_bazel_typescript//:index.bzl", "ts_project")

sass(
name = "styles",
Expand All @@ -13,22 +13,8 @@ sass(
data = ["styles.scss"],
)

tsc(
name = "compile",
outs = ["index.js"],
args = [
"$(execpath index.tsx)",
"$(execpath types.d.ts)",
"--outDir",
"$(RULEDIR)",
"--lib",
"es2015,dom",
"--jsx",
"react",
],
data = [
"index.tsx",
"types.d.ts",
ts_project(
deps = [
"@npm//@types",
"@npm//csstype",
],
Expand Down
4 changes: 4 additions & 0 deletions examples/react_webpack/WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ yarn_install(
package_json = "//:package.json",
yarn_lock = "//:yarn.lock",
)

load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")

install_bazel_dependencies()
1 change: 1 addition & 0 deletions examples/react_webpack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"@bazel/bazelisk": "^1.3.0",
"@bazel/buildifier": "^0.29.0",
"@bazel/ibazel": "^0.12.2",
"@bazel/typescript": "^1.4.1",
"@types/react": "^16.9.5",
"@types/react-dom": "^16.9.1",
"css-loader": "^3.2.0",
Expand Down
6 changes: 6 additions & 0 deletions examples/react_webpack/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"compilerOptions": {
"jsx": "react",
"lib": ["ES2015", "DOM"]
}
}
52 changes: 19 additions & 33 deletions packages/typescript/docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,33 @@

The TypeScript rules integrate the TypeScript compiler with Bazel.

Looking for Karma rules `ts_web_test` and `karma_web_test`?
These are now documented in the README at http://npmjs.com/package/@bazel/karma

## Alternatives

This package provides Bazel wrappers around the TypeScript compiler, and are how we compile TS code at Google.

These rules are opinionated, for example:

- Your TS code must compile under the `--declaration` flag so that downstream libraries depend only on types, not implementation. This makes Bazel faster by avoiding cascading rebuilds in cases where the types aren't changed.
- We control the output format and module syntax so that downstream rules can rely on them.
This package provides Bazel wrappers around the TypeScript compiler.

They are also fast and optimized:
At a high level, there are two alternatives provided: `ts_project` and `ts_library`.
This section describes the trade-offs between these rules.

- We keep a running TypeScript compile running as a daemon, using Bazel workers. This process avoids re-parse and re-JIT of the >1MB `typescript.js` and keeps cached bound ASTs for input files which saves time.
`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 understand this is a tradeoff. If you want to use the plain TypeScript compiler provided by the TS team at Microsoft, you can do this by calling its CLI directly. For example,
> 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.
```python
load("@npm//typescript:index.bzl", "tsc")
`ts_library` is an open-sourced version of the rule we use 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:

srcs = glob(["*.ts"])
deps = ["@npm//@types/node"]
- Your TS code must compile under the `--declaration` flag so that downstream libraries depend only on types, not implementation. This makes Bazel faster by avoiding cascading rebuilds in cases where the types aren't changed.
- We control the output format and module syntax so that downstream rules can rely on them.

tsc(
name = "compile",
data = srcs + deps,
outs = [s.replace(".ts", ext) for ext in [".js", ".d.ts"] for s in srcs],
args = [
"--outDir",
"$(RULEDIR)",
"--lib",
"es2017,dom",
"--downlevelIteration",
"--declaration",
] + [
"$(location %s)" % s
for s in srcs
],
)
```
On the other hand, `ts_library` is also fast and optimized.
We keep a running TypeScript compile running as a daemon, using Bazel workers.
This process avoids re-parse and re-JIT of the >1MB `typescript.js` and keeps cached bound ASTs for input files which saves time.
We also produce JS code which can be loaded faster (using named AMD module format) and which can be consumed by the Closure Compiler (via integration with [tsickle](https://github.com/angular/tsickle)).

## Installation

Expand Down
2 changes: 2 additions & 0 deletions packages/typescript/src/index.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ Users should not load files under "/internal"

load("//internal:build_defs.bzl", _ts_library = "ts_library_macro")
load("//internal:ts_config.bzl", _ts_config = "ts_config")
load("//internal:ts_project.bzl", _ts_project = "ts_project_macro")
load("//internal:ts_repositories.bzl", _ts_setup_workspace = "ts_setup_workspace")
load("//internal/devserver:ts_devserver.bzl", _ts_devserver = "ts_devserver_macro")

ts_setup_workspace = _ts_setup_workspace
ts_library = _ts_library
ts_config = _ts_config
ts_devserver = _ts_devserver
ts_project = _ts_project
# If adding rules here also add to index.docs.bzl
2 changes: 2 additions & 0 deletions packages/typescript/src/index.docs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ So this is a copy of index.bzl with macro indirection removed.

load("//internal:build_defs.bzl", _ts_library = "ts_library")
load("//internal:ts_config.bzl", _ts_config = "ts_config")
load("//internal:ts_project.bzl", _ts_project = "ts_project_macro")
load("//internal:ts_repositories.bzl", _ts_setup_workspace = "ts_setup_workspace")
load("//internal/devserver:ts_devserver.bzl", _ts_devserver = "ts_devserver")

ts_setup_workspace = _ts_setup_workspace
ts_library = _ts_library
ts_config = _ts_config
ts_project = _ts_project
ts_devserver = _ts_devserver
# DO NOT ADD MORE rules here unless they appear in the generated docsite.
# Run yarn stardoc to re-generate the docsite.
1 change: 1 addition & 0 deletions packages/typescript/src/internal/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ filegroup(
srcs = [
"build_defs.bzl",
"ts_config.bzl",
"ts_project.bzl",
"ts_repositories.bzl",
"//internal/devserver:package_contents",
],
Expand Down
Loading

0 comments on commit 26f6698

Please sign in to comment.