Skip to content
This repository has been archived by the owner on Sep 16, 2021. It is now read-only.

Idiomatic install with @bazel/typescript and @bazel/karma npm packages #276

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .circleci/bazel.rc
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,11 @@ build --experimental_repository_cache=/home/circleci/bazel_repository_cache
# Limit Bazel to consuming 2560K of RAM
build --local_resources=2560,1.0,1.0
# Also limit Bazel's own JVM heap to stay within our 4G container limit
startup --host_jvm_args=-Xmx1g
startup --host_jvm_args=-Xmx2g
gregmagolan marked this conversation as resolved.
Show resolved Hide resolved
# Since the default CircleCI container has only 4G, limiting the memory
# is required to keep Bazel from exhausting the memory. These values
# are determined experimentally. If the Bazel process crashes without
# any error messages then the --local_resources and --host_jvm_args
# memory should be reduced. If the Bazel process errors out within
# a "JVM out of memory" error then the --host_jvm_args memory should
# be increased.
8 changes: 5 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ jobs:
- restore_cache:
key: *cache_key
- run: bazel info release
- run: bazel run @nodejs//:yarn
- run: bazel build ...
- run: bazel test ...

Expand All @@ -73,7 +72,6 @@ jobs:
- restore_cache:
key: *cache_key
- run: bazel --bazelrc=/dev/null info release
- run: bazel --bazelrc=/dev/null run @nodejs//:yarn
- run: bazel --bazelrc=/dev/null build ...
- run: bazel --bazelrc=/dev/null test ...

Expand All @@ -94,7 +92,11 @@ jobs:
- *hide_node_and_yarn_local_binaries
- restore_cache:
key: *cache_key
- run: bazel run @nodejs//:yarn
# Build the npm packages which are used in the e2e tests
- run: bazel build //internal:npm_package
- run: bazel build //internal/karma:npm_package
# Run yarn as e2e tests depend on self managed node_modules
- run: bazel run @nodejs//:bin/yarn
# Don't occupy the bazel server, as this test wants to run Bazel itself
- run: bazel run @nodejs//:yarn e2e --script_path=yarn_e2e.sh
- run: xvfb-run -a ./yarn_e2e.sh
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
.idea
node_modules
/bazel-*
/internal/e2e/package_karma/bazel-*
/internal/e2e/package_typescript/bazel-*
/internal/e2e/ts_auto_deps/bazel-*

internal/e2e/ts_auto_deps/simple/BUILD
internal/e2e/ts_auto_deps/simple/BUILD.bazel
50 changes: 34 additions & 16 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,13 @@ alias(
visibility = ["//visibility:public"],
)

exports_files(["LICENSE"])

gazelle(
name = "gazelle",
prefix = "github.com/bazelbuild/rules_typescript",
)

# The node_modules directory is created by `yarn install`
# WORKAROUND for https://github.com/bazelbuild/bazel/issues/374#issuecomment-296217940
filegroup(
name = "node_modules",
# Only include files needed for type-checking and runtime
srcs = glob([
"node_modules/**/*.js",
"node_modules/**/*.d.ts",
"node_modules/**/*.json",
] + [
# Needed because http-server has a bin with no .js extension
"node_modules/http-server/**",
]),
visibility = ["//visibility:public"],
)

# Runtime libraries needed by the protobufjs library.
# Any JS code produced by the ts_proto_library rule has a runtime dependency on these scripts.
js_library(
Expand All @@ -66,3 +52,35 @@ js_library(
},
visibility = ["//visibility:public"],
)

load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")

# A nodejs_binary for karma/karma to use by default in ts_web_test &
# ts_web_test_suite that depends on @npm//:@bazel/karma instead of the
# output of the //internal/karma/karma_concat_js ts_library rule. This
# default is for downstream users that depend on the @bazel/karma npm
# package. The generated @npm//:karma/karma target does not work
# as it does not have the additional data dependencies required.
nodejs_binary(
name = "karma/karma",
data = ["@npm//:@bazel/karma"],
install_source_map_support = False,
entry_point = "karma/bin/karma",
visibility = ["//visibility:public"],
)

# A nodejs_binary for @bazel/typescript/tsc_wrapped to use by default in
# ts_library that depends on @npm//:@bazel/typescript instead of the
# output of the //internal/tsc_wrapped ts_library rule. This
# default is for downstream users that depend on the @bazel/karma npm
# package. The generated @npm//:@bazel/typescript/tsc_wrapped target
# does not work because it does not have the node `--expose-gc` flag
# set which is required to support the call to `global.gc()`.
nodejs_binary(
name = "@bazel/typescript/tsc_wrapped",
entry_point = "@bazel/typescript/tsc_wrapped/tsc_wrapped.js",
install_source_map_support = False,
templated_args = ["--node_options=--expose-gc"],
data = ["@npm//:@bazel/typescript"],
visibility = ["//visibility:public"],
)
150 changes: 133 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,37 @@ http://tsetse.info/api/

First, install a current Bazel distribution.

Add the `@bazel/typescript` npm package to your `package.json` `devDependencies`.
Optionally add the `@bazel/karma` npm package if you would like to use the
`ts_web_test_suite` rule.

```
{
...
"devDependencies": {
"@bazel/typescript": "0.18.0",
"@bazel/karma": "0.18.0",
...
},
...
}
```

Create a `BUILD.bazel` file in your project root:

```python
package(default_visibility = ["//visibility:public"])
exports_files(["tsconfig.json"])

# NOTE: this will move to node_modules/BUILD in a later release
filegroup(name = "node_modules", srcs = glob([
"node_modules/**/*.js",
"node_modules/**/*.d.ts",
"node_modules/**/*.json",
]))
```

Next create a `WORKSPACE` file in your project root (or edit the existing one)
containing:

```python
# Include @bazel/typescript in package.json#devDependencies
local_repository(
http_archive(
name = "build_bazel_rules_typescript",
path = "node_modules/@bazel/typescript",
url = "https://github.com/bazelbuild/rules_typescript/archive/0.18.0.zip",
strip_prefix = "rules_typescript-0.18.0",
)

# Fetch our Bazel dependencies that aren't distributed on npm
Expand All @@ -49,9 +58,20 @@ rules_typescript_dependencies()
load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace")
ts_setup_workspace()

# Point to the package.json file so Bazel can run the package manager for you.
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")
node_repositories(package_json = ["//:package.json"])
# Setup the NodeJS toolchain
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories", "yarn_install")
node_repositories()

# Setup Bazel managed npm dependencies with the `yarn_install` rule.
# The name of this rule should be set to `npm` so that `ts_library` and `ts_web_test_suite`
# can find your npm dependencies by default in the `@npm` workspace. You may
# also use the `npm_install` rule with a `package-lock.json` file if you prefer.
# See https://github.com/bazelbuild/rules_nodejs#dependencies for more info.
yarn_install(
name = "npm",
package_json = "//:package.json",
yarn_lock = "//:yarn.lock",
)

# Setup Go toolchain
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
Expand All @@ -67,14 +87,73 @@ browser_repositories(
)
```

We recommend using the Yarn package manager, because it has a built-in command
to verify the integrity of your `node_modules` directory.
You can run the version Bazel has already installed:
# Self-managed npm dependencies

We recommend you use Bazel managed dependencies but if you would like
Bazel to also install a `node_modules` in your workspace you can also
point the `node_repositories` repository rule in your WORKSPACE file to
your `package.json`.

```python
node_repositories(package_json = ["//:package.json"])
```

You can then run `yarn` in your workspace with:

```sh
$ bazel run @nodejs//:yarn
```

To use your workspace `node_modules` folder as a dependency in `ts_library` and
other rules, add the following to your root `BUILD.bazel` file:

```python
filegroup(
name = "node_modules",
srcs = glob(
include = [
"node_modules/**/*.js",
"node_modules/**/*.d.ts",
"node_modules/**/*.json",
"node_modules/.bin/*",
],
exclude = [
# Files under test & docs may contain file names that
# are not legal Bazel labels (e.g.,
# node_modules/ecstatic/test/public/中文/檔案.html)
"node_modules/**/test/**",
"node_modules/**/docs/**",
# Files with spaces in the name are not legal Bazel labels
"node_modules/**/* */**",
"node_modules/**/* *",
],
),
)

# Create a tsc_wrapped compiler rule to use in the ts_library
# compiler attribute when using self-managed dependencies
nodejs_binary(
name = "@bazel/typescript/tsc_wrapped",
entry_point = "@bazel/typescript/tsc_wrapped/tsc_wrapped.js",
# The --expose-gc node option is required for tsc_wrapped
templated_args = ["--node_options=--expose-gc"],
# Point bazel to your node_modules to find the entry point
node_modules = ["//:node_modules"],
)

# Create a karma rule to use in ts_web_test_suite karma
# attribute when using self-managed dependencies
nodejs_binary(
name = "karma/karma",
entry_point = "karma/bin/karma",
# Point bazel to your node_modules to find the entry point
node_modules = ["//:node_modules"],
)
```

See https://github.com/bazelbuild/rules_nodejs#dependencies for more information on
managing npm dependencies with Bazel.

## Usage

### Compiling TypeScript: `ts_library`
Expand All @@ -95,7 +174,44 @@ ts_library(
)
```

Then build it:
If your ts_library target has npm dependencies you can specify these
with fine grained npm dependency targets created by the `yarn_install` or
`npm_install` rules:

```python
ts_library(
name = "my_code",
srcs = glob(["*.ts"]),
deps = [
"@npm//:@types/node",
"@npm//:@types/foo",
"@npm//:foo",
"//path/to/other:library",
],
)
```

You can also you the `@npm//:@types` target which will include all
packages in the `@types` scope as dependencies.

If you are using self-managed npm dependencies, you can use the
`node_modules` attribute in `ts_library` and point it to the
`//:node_modules` filegroup defined in your root `BUILD.bazel` file.
You'll also need to override the `compiler` attribute if you do this
as the Bazel-managed deps and self-managed cannot be used together
in the same rule.

```python
ts_library(
name = "my_code",
srcs = glob(["*.ts"]),
deps = ["//path/to/other:library"],
node_modules = "//:node_modules",
compiler = "//:@bazel/typescript/tsc_wrapped",
)
```

To build a `ts_library` target run:

`bazel build //path/to/package:target`

Expand Down
Loading