blob: 52fa556316dd60f5dcd02e74444a8354f7704e6c [file] [log] [blame] [view]
spomorski97a932f2018-06-04 10:16:44 -07001---
2layout: documentation
3title: Building JavaScript Outputs
4---
5
6# Building JavaScript Outputs
7
8Bazel supports an incremental and customizable means of building and testing
9JavaScript outputs from JavaScript, TypeScript, and Angular sources.
10
11**Note:** This document describes Bazel features and workflows that are useful,
12but the Bazel team has not fully verified and does not officially support
13these features and workflows.
14
spomorski03ca7d12018-06-05 11:32:48 -070015## Contents
spomorski97a932f2018-06-04 10:16:44 -070016
spomorski03ca7d12018-06-05 11:32:48 -070017* [Overview](#overview)
18* [Setting up your environment](#setting-up-your-environment)
19 * [Step 1: Installing Bazel](#step-1-installing-bazel)
20 * [Step 2: Installing iBazel](#step-2-installing-ibazel)
21 * [Step 3: Configuring the `bazel.rc` file](#step-3-configuring-the-bazel-rc-file)
22 * [Step 4: (Optional) Setting up Continuous Integration (CI)](#step-4-optional-setting-up-continuous-integration-ci)
23* [Building JavaScript inputs](#building-javascript)
24* [Building TypeScript inputs](#building-typescript)
25 * [Compiling TypeScript inputs (`ts_library`)](#compiling-typescript-inputs-ts_library)
26 * [Running a development server (`ts_devserver`)](#running-a-development-server-ts_devserver)
27 * [Testing TypeScript code (`ts_web_test`)](#testing-typescript-code-ts_web_test)
28* [Building Angular inputs](#building-angular-inputs)
29
30## Overview
spomorski97a932f2018-06-04 10:16:44 -070031
32Bazel rules for building JavaScript outputs are split into three layers, since
33you can use JavaScript without TypeScript, and TypeScript without Angular.
34This document assumes you are already familiar with Bazel and uses the
35[Angular for Bazel sample project](https://github.com/alexeagle/angular-bazel-example)
36to illustrate the recommended configuration. You can use the sample project as a
37starting point and add your own code to it to start building with Bazel.
spomorski97a932f2018-06-04 10:16:44 -070038
39If you're new to Bazel, take a look at the ["Getting Started"](https://docs.bazel.build/versions/master/getting-started.html)
40material before proceeding.
41
spomorski03ca7d12018-06-05 11:32:48 -070042## Setting up your environment
spomorski97a932f2018-06-04 10:16:44 -070043
44To set up your environment for building JavaScript outputs with Bazel, do the
45following:
46
spomorski03ca7d12018-06-05 11:32:48 -070047### Step 1: Installing Bazel
spomorski97a932f2018-06-04 10:16:44 -070048
49If you have not already done so, [Install Bazel](https://docs.bazel.build/versions/master/install.html).
50
spomorski03ca7d12018-06-05 11:32:48 -070051### Step 2: Installing iBazel
spomorski97a932f2018-06-04 10:16:44 -070052
53iBazel, or iterative Bazel, is a "watchdog" version of Bazel that automatically
54runs whenever your source files change. Use it to auto-run your tests and
55auto-refresh the code served by the development server.
56
57[Install iBazel](https://github.com/bazelbuild/bazel-watcher) globally using
58your package manager of choice. The global installation is required so that
59iBazel is in your PATH variable. Also install a specific version of iBazel into
60your project so that your whole team updates together. For example:
61
62```
63npm install --save-dev @bazel/ibazel
64npm install --global @bazel/ibazel
65```
66or
67
68```
69yarn add -D @bazel/ibazel
70yarn global add @bazel/ibazel
71```
72
73To use `ibazel`, simply replace `bazel` with `ibazel` in your Bazel commands.
74
spomorski03ca7d12018-06-05 11:32:48 -070075### Step 3: Configuring the `bazel.rc` file
spomorski97a932f2018-06-04 10:16:44 -070076
77Any Bazel build flag or option that can be placed on the command line can also
Wayou Liuccbd3e62018-08-10 07:03:11 -070078be set in the project's [`bazel.rc` file](https://docs.bazel.build/versions/master/user-manual.html#bazelrc)
spomorski97a932f2018-06-04 10:16:44 -070079so that it is applied every time Bazel builds or tests the project.
80
81Based on how you want to share Bazel settings across your project and team(s),
82you can use any combination of the following techniques:
83
84* **To use the same Bazel settings for the project**, create a `tools/bazel.rc`
85 file at the root of the Bazel workspace. Adding it to the workspace will
86 check the file into version control and propagate it to others working on
87 the project as well as the CI system.
88
89* **To personalize Bazel settings for the project but not share them,**
90 create a `.bazel.rc` file at the root of the project and add the file to
91 your `.gitignore` list.
92
93* **To personalize Bazel settings for all of your projects on your
94 local machine,** create a `.bazel.rc` file in your home directory.
95
96Here's an example `tools/bazel.rc` file to share with your team. Modify this
97template as needed.
98
99```
100###############################
101# Directory structure #
102###############################
103
104# Globally cache downloaded artifacts.
105build --experimental_repository_cache=~/.bazel_cache/
106test --experimental_repository_cache=~/.bazel_cache/
107run --experimental_repository_cache=~/.bazel_cache/
108
109# Don't create bazel-* symlinks in the WORKSPACE directory. These
110# symlinks require .gitignore and may scare users. Instead, run
111# `bazel info bazel-bin` to find out where the outputs are stored.
112build --symlink_prefix=/
113
114# Another good choice is to create a dist/ directory. Then you can
115# use build --symlink_prefix=dist/ to get folders like dist/bin.
116# Be aware that this setup will still create a bazel-out symlink in
117# your project directory, which you may need to exclude from the
118# editor's search path.
119
120###############################
121# Output #
122###############################
123
124# A more useful default output mode for bazel query, which
125# prints "ng_module rule //foo:bar" instead of just "//foo:bar".
126query --output=label_kind
127
128# By default, failing tests don't print any output, it's logged to a
129# file instead.
130
131test --test_output=errors
132
133# Show which actions are running under which workers and print all
134# the actions running in parallel. This shows that Bazel runs on all
135# cores of a CPU.
136build --experimental_ui
137test --experimental_ui
138
139###############################
140# Typescript / Angular / Sass #
141###############################
142# Make TypeScript and Angular compilation fast, by keeping a few
143# copies of the compiler running as daemons, and cache SourceFile
144# ASTs to reduce parse time.
145build --strategy=TypeScriptCompile=worker --strategy=AngularTemplateCompile=worker
146
147# Enable debugging tests with --config=debug
148test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results
149```
150
spomorski03ca7d12018-06-05 11:32:48 -0700151### Step 4: (Optional) Setting up Continuous Integration (CI)
spomorski97a932f2018-06-04 10:16:44 -0700152
153For building JavaScript outputs with Bazel in a CI setting, it's useful to use a
154container as the environment. The [ngcontainer Docker image](https://hub.docker.com/r/angular/ngcontainer/)
155is a ready-to-use environment you can use that makes your builds reproducible in
156other environments, such as your local machine. This reproducibility is
157especially convenient on CircleCI, which lets you choose a Docker image as the
158environment for your build. See the example [CircleCI configuration](https://github.com/alexeagle/angular-bazel-example/blob/master/.circleci/config.yml)
159in the sample project to learn more.
160
161**Tip:** When building in a CI environment, add settings to your `bazel.rc` file
162that are specific to CI using the `build:ci` and or `test:ci` prefixes. With
163this configuration, you can enable those CI-specific options by simply adding
164the `--config=ci` argument to your Bazel/iBazel commands.
165
spomorski03ca7d12018-06-05 11:32:48 -0700166## Building JavaScript
spomorski97a932f2018-06-04 10:16:44 -0700167
168Use the <code>[rules_nodejs](https://github.com/bazelbuild/rules_nodejs)</code>
169rules to build NodeJS applications and execute JavaScript code within Bazel. You
170can execute JavaScript tools in the Bazel toolchain, binary programs, or tests.
171The NodeJS rules add the NodeJS runtime to your Bazel project.
172
173Most notable NodeJS rules include:
174
175* `nodejs_binary` - builds an executable program based on JavaScript source
176 files and an entry point path relative to the output root. To provide extra
177 inputs to be read at runtime, put them in the data attribute.
178
179* `jasmine_node_test` - runs JavaScript spec files through the Jasmine test
180 framework. See the [node_js API documentation](https://bazelbuild.github.io/rules_nodejs/)
181 for more information.
182
spomorski03ca7d12018-06-05 11:32:48 -0700183## Building TypeScript
spomorski97a932f2018-06-04 10:16:44 -0700184
185Use the <code>[rules_typescript](https://github.com/bazelbuild/rules_typescript)</code>
186rules to build JavaScript outputs from TypeScript inputs.
187
188To set up your Bazel project for building TypeScript inputs, do the following:
189
1901. Make Bazel aware of the TypeScript build rules by adding the following entry
191 to your `WORKSPACE` file:
192
193 ```
194 http_archive(
195 name = "build_bazel_rules_typescript",
196 url = "https://github.com/bazelbuild/rules_typescript/archive/v0.13.0.zip",
197 strip_prefix = "rules_typescript-0.13.0",
198 )
199
200 load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace")
201
202 ts_setup_workspace()
203
204 ```
205
2062. Add the `--strategy` settings to your `bazel.rc` file as shown in the
207 example `.bazel.rc` file in ["Configuring the bazel.rc file"](#step-3-configuring-the-bazel-rc-file).
208
209
spomorski03ca7d12018-06-05 11:32:48 -0700210### Compiling TypeScript inputs (`ts_library`)
spomorski97a932f2018-06-04 10:16:44 -0700211
212The `ts_library` rule compiles one package of TypeScript code at a time. Each
213library compiles independently using the `.d.ts` declaration files from its
214dependencies. Thus, Bazel will only rebuild a package if the API the package
215depends on changes.
216
217The `ts_library `rule, by default, outputs a `.d.ts` file for each `.ts` source
218file input into it, plus an ES5 (devmode) `.js` file to be used as inputs for
219rule targets that depend on the current target, including transitively.
220
221**Tip:** You can try out the `ts_library` rule by running bazel build src in
222the [sample project](https://github.com/alexeagle/angular-bazel-example/wiki).
223
224**Note:** We recommend standardizing your TypeScript settings into a single
225`tsconfig.json` file or as few `tsconfig.json` files as possible.
226
227Note the following:
228
229* Bazel controls parts of the `tsconfig.json `file that define locations of
230 input and output files, manage dependencies on typings, and produce
231 JavaScript output that's readable by downstream tooling. Currently, this
232 format is unbundled UMD modules, wrapping noth named (non-anonymous) AMD
233 modules and `commonjs` modules.
234
235* Bazel may introduce new requirements for your TypeScript code. For example,
236 Bazel uses the `-declarations` flag to produce `.d.ts` outputs required by
237 dependent rule targets; your code may require adjustment to not produce
238 errors when the `-declarations` flag is in use.
239
240* If your TypeScript builds are slow, consider granularizing the affected rule
241 target(s) into smaller sub-targets and declaring dependencies between them
242 appropriately.
243
spomorski03ca7d12018-06-05 11:32:48 -0700244### Running a development server (`ts_devserver`)
spomorski97a932f2018-06-04 10:16:44 -0700245
246The `ts_devserver` rule brings up a development server from your application
247sources. It's intended for use with the `ibazel run` command so that the server
248picks up your code changes immediately. The rule injects a `livereload` script
249into the browser, which causes the page to auto-refresh with the latest changes
250at the completion of each build.
251
252**Tip:** You can test-drive the development server feature by running
253`ibazel run src: devserver` on the [sample project](https://github.com/alexeagle/angular-bazel-example/wiki).
254
255
spomorski03ca7d12018-06-05 11:32:48 -0700256### Testing TypeScript code (`ts_web_test`)
spomorski97a932f2018-06-04 10:16:44 -0700257
258Use the `ts_web_test` rule to execute the Karma test runner. This rule works
259best with ibazel so that both the test runner and the browser pick up your
260changes at the completion of each build. For faster builds, Bazel bundles your
261code and its dependencies into a single JavaScript file delivered to the browser
262when the test runner executes.
263
264If you need to match lots of tests with a target pattern such as bazel test //…
265or using CI, run the `ts_web_test` rule with the regular `bazel test` command
266instead. Bazel will then launch a headless Chrome instance and exit after a
267single run.
268
269**Tip:** You can test-drive the `ts_web_test` rule by running `ibazel run` or
270`bazel run` on the `src/hello-world:test` target in the [sample project](https://github.com/alexeagle/angular-bazel-example/wiki).
271
272
spomorski03ca7d12018-06-05 11:32:48 -0700273## Building Angular inputs
spomorski97a932f2018-06-04 10:16:44 -0700274
spomorski03ca7d12018-06-05 11:32:48 -0700275Bazel can build JavaScript outputs from Angular. For instructions, see [Building Angular with Bazel](https://github.com/alexeagle/angular-bazel-example/wiki/Angular-rules).
spomorski97a932f2018-06-04 10:16:44 -0700276