spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 1 | --- |
| 2 | layout: documentation |
| 3 | title: Building JavaScript Outputs |
| 4 | --- |
| 5 | |
| 6 | # Building JavaScript Outputs |
| 7 | |
| 8 | Bazel supports an incremental and customizable means of building and testing |
Googler | d355b55 | 2019-04-24 11:33:05 -0700 | [diff] [blame] | 9 | JavaScript outputs from JavaScript and TypeScript sources. |
| 10 | |
| 11 | It can also support build steps needed for frameworks like Angular. |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 12 | |
| 13 | **Note:** This document describes Bazel features and workflows that are useful, |
| 14 | but the Bazel team has not fully verified and does not officially support |
| 15 | these features and workflows. |
| 16 | |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 17 | ## Contents |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 18 | |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 19 | * [Overview](#overview) |
| 20 | * [Setting up your environment](#setting-up-your-environment) |
| 21 | * [Step 1: Installing Bazel](#step-1-installing-bazel) |
| 22 | * [Step 2: Installing iBazel](#step-2-installing-ibazel) |
| 23 | * [Step 3: Configuring the `bazel.rc` file](#step-3-configuring-the-bazel-rc-file) |
Googler | d355b55 | 2019-04-24 11:33:05 -0700 | [diff] [blame] | 24 | * [Step 4: Setup linting (optional)](#step-4-linting) |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 25 | * [Building JavaScript inputs](#building-javascript) |
| 26 | * [Building TypeScript inputs](#building-typescript) |
| 27 | * [Compiling TypeScript inputs (`ts_library`)](#compiling-typescript-inputs-ts_library) |
| 28 | * [Running a development server (`ts_devserver`)](#running-a-development-server-ts_devserver) |
| 29 | * [Testing TypeScript code (`ts_web_test`)](#testing-typescript-code-ts_web_test) |
| 30 | * [Building Angular inputs](#building-angular-inputs) |
| 31 | |
| 32 | ## Overview |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 33 | |
| 34 | Bazel rules for building JavaScript outputs are split into three layers, since |
| 35 | you can use JavaScript without TypeScript, and TypeScript without Angular. |
| 36 | This document assumes you are already familiar with Bazel and uses the |
Googler | d355b55 | 2019-04-24 11:33:05 -0700 | [diff] [blame] | 37 | [Angular for Bazel sample project](https://github.com/angular/angular-bazel-example) |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 38 | to illustrate the recommended configuration. You can use the sample project as a |
| 39 | starting point and add your own code to it to start building with Bazel. |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 40 | |
Jingwen Chen | 0f4544d | 2018-12-14 16:28:16 -0800 | [diff] [blame] | 41 | If you're new to Bazel, take a look at the ["Getting |
| 42 | Started"](getting-started.html) material before proceeding. |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 43 | |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 44 | ## Setting up your environment |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 45 | |
| 46 | To set up your environment for building JavaScript outputs with Bazel, do the |
| 47 | following: |
| 48 | |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 49 | ### Step 1: Installing Bazel |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 50 | |
Googler | d355b55 | 2019-04-24 11:33:05 -0700 | [diff] [blame] | 51 | You can either [Install Bazel](install.html) following the same steps that you |
| 52 | would for backend development, or you can install NodeJS with npm and run |
| 53 | `npm install -g @bazel/bazel`. |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 54 | |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 55 | ### Step 2: Installing iBazel |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 56 | |
| 57 | iBazel, or iterative Bazel, is a "watchdog" version of Bazel that automatically |
| 58 | runs whenever your source files change. Use it to auto-run your tests and |
| 59 | auto-refresh the code served by the development server. |
| 60 | |
| 61 | [Install iBazel](https://github.com/bazelbuild/bazel-watcher) globally using |
| 62 | your package manager of choice. The global installation is required so that |
| 63 | iBazel is in your PATH variable. Also install a specific version of iBazel into |
| 64 | your project so that your whole team updates together. For example: |
| 65 | |
| 66 | ``` |
| 67 | npm install --save-dev @bazel/ibazel |
| 68 | npm install --global @bazel/ibazel |
| 69 | ``` |
| 70 | or |
| 71 | |
| 72 | ``` |
| 73 | yarn add -D @bazel/ibazel |
| 74 | yarn global add @bazel/ibazel |
| 75 | ``` |
| 76 | |
| 77 | To use `ibazel`, simply replace `bazel` with `ibazel` in your Bazel commands. |
| 78 | |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 79 | ### Step 3: Configuring the `bazel.rc` file |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 80 | |
| 81 | Any Bazel build flag or option that can be placed on the command line can also |
wyv | 3a634fa | 2020-05-15 06:47:26 -0700 | [diff] [blame] | 82 | be set in the project's [`bazel.rc` file](guide.html#bazelrc) |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 83 | so that it is applied every time Bazel builds or tests the project. |
| 84 | |
| 85 | Based on how you want to share Bazel settings across your project and team(s), |
| 86 | you can use any combination of the following techniques: |
| 87 | |
| 88 | * **To use the same Bazel settings for the project**, create a `tools/bazel.rc` |
| 89 | file at the root of the Bazel workspace. Adding it to the workspace will |
| 90 | check the file into version control and propagate it to others working on |
| 91 | the project as well as the CI system. |
| 92 | |
| 93 | * **To personalize Bazel settings for the project but not share them,** |
| 94 | create a `.bazel.rc` file at the root of the project and add the file to |
| 95 | your `.gitignore` list. |
| 96 | |
| 97 | * **To personalize Bazel settings for all of your projects on your |
| 98 | local machine,** create a `.bazel.rc` file in your home directory. |
| 99 | |
| 100 | Here's an example `tools/bazel.rc` file to share with your team. Modify this |
| 101 | template as needed. |
| 102 | |
| 103 | ``` |
| 104 | ############################### |
| 105 | # Directory structure # |
| 106 | ############################### |
| 107 | |
Googler | d355b55 | 2019-04-24 11:33:05 -0700 | [diff] [blame] | 108 | # Artifacts are typically placed in a directory called "dist" |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 109 | # Be aware that this setup will still create a bazel-out symlink in |
Googler | d355b55 | 2019-04-24 11:33:05 -0700 | [diff] [blame] | 110 | # your project directory, which you must exclude from version control and your |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 111 | # editor's search path. |
Googler | d355b55 | 2019-04-24 11:33:05 -0700 | [diff] [blame] | 112 | build --symlink_prefix=dist/ |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 113 | |
| 114 | ############################### |
| 115 | # Output # |
| 116 | ############################### |
| 117 | |
| 118 | # A more useful default output mode for bazel query, which |
| 119 | # prints "ng_module rule //foo:bar" instead of just "//foo:bar". |
| 120 | query --output=label_kind |
| 121 | |
| 122 | # By default, failing tests don't print any output, it's logged to a |
| 123 | # file instead. |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 124 | test --test_output=errors |
| 125 | |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 126 | ############################### |
| 127 | # Typescript / Angular / Sass # |
| 128 | ############################### |
| 129 | # Make TypeScript and Angular compilation fast, by keeping a few |
| 130 | # copies of the compiler running as daemons, and cache SourceFile |
| 131 | # ASTs to reduce parse time. |
| 132 | build --strategy=TypeScriptCompile=worker --strategy=AngularTemplateCompile=worker |
| 133 | |
| 134 | # Enable debugging tests with --config=debug |
| 135 | test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results |
| 136 | ``` |
| 137 | |
Googler | d355b55 | 2019-04-24 11:33:05 -0700 | [diff] [blame] | 138 | ### Step 4: Linting |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 139 | |
Googler | d355b55 | 2019-04-24 11:33:05 -0700 | [diff] [blame] | 140 | Add the `buildifier` dependency to your project: |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 141 | |
Googler | d355b55 | 2019-04-24 11:33:05 -0700 | [diff] [blame] | 142 | ```sh |
| 143 | npm install --save-dev @bazel/buildifier |
| 144 | ``` |
| 145 | |
| 146 | or if you prefer Yarn, |
| 147 | |
| 148 | ```sh |
| 149 | yarn add -D @bazel/buildifier |
| 150 | ``` |
| 151 | |
| 152 | then add scripts to your `package.json` that run Buildifier. |
| 153 | We've selected a set of enabled warnings here, you could add and remove from |
| 154 | this list. |
| 155 | |
| 156 | ```json |
| 157 | "scripts": { |
| 158 | "bazel:format": "find . -type f \\( -name \"*.bzl\" -or -name WORKSPACE -or -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" | xargs buildifier -v --warnings=attr-cfg,attr-license,attr-non-empty,attr-output-default,attr-single-file,constant-glob,ctx-actions,ctx-args,depset-iteration,depset-union,dict-concatenation,duplicated-name,filetype,git-repository,http-archive,integer-division,load,load-on-top,native-build,native-package,out-of-order-load,output-group,package-name,package-on-top,positional-args,redefined-variable,repository-name,same-origin-load,string-iteration,unsorted-dict-items,unused-variable", |
| 159 | "bazel:lint": "yarn bazel:format --lint=warn", |
| 160 | "bazel:lint-fix": "yarn bazel:format --lint=fix" |
| 161 | } |
| 162 | ``` |
| 163 | |
| 164 | > The Bazel team is aware that this configuration is not ergonomic. Follow https://github.com/bazelbuild/buildtools/issues/479 |
| 165 | |
| 166 | > Also the Buildifier tool is not available on Windows. Follow https://github.com/bazelbuild/buildtools/issues/375 |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 167 | |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 168 | ## Building JavaScript |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 169 | |
Attila Ol?h | f355615 | 2018-11-26 13:18:26 -0800 | [diff] [blame] | 170 | Use the [`rules_nodejs`](https://github.com/bazelbuild/rules_nodejs) |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 171 | rules to build NodeJS applications and execute JavaScript code within Bazel. You |
| 172 | can execute JavaScript tools in the Bazel toolchain, binary programs, or tests. |
| 173 | The NodeJS rules add the NodeJS runtime to your Bazel project. |
| 174 | |
Googler | d355b55 | 2019-04-24 11:33:05 -0700 | [diff] [blame] | 175 | See the documentation on that site for setup steps and to configure targets. |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 176 | |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 177 | ## Building TypeScript |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 178 | |
Googler | d355b55 | 2019-04-24 11:33:05 -0700 | [diff] [blame] | 179 | See the https://www.npmjs.com/package/@bazel/typescript package. |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 180 | |
| 181 | |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 182 | ### Compiling TypeScript inputs (`ts_library`) |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 183 | |
| 184 | The `ts_library` rule compiles one package of TypeScript code at a time. Each |
| 185 | library compiles independently using the `.d.ts` declaration files from its |
| 186 | dependencies. Thus, Bazel will only rebuild a package if the API the package |
| 187 | depends on changes. |
| 188 | |
| 189 | The `ts_library `rule, by default, outputs a `.d.ts` file for each `.ts` source |
| 190 | file input into it, plus an ES5 (devmode) `.js` file to be used as inputs for |
| 191 | rule targets that depend on the current target, including transitively. |
| 192 | |
| 193 | **Tip:** You can try out the `ts_library` rule by running bazel build src in |
| 194 | the [sample project](https://github.com/alexeagle/angular-bazel-example/wiki). |
| 195 | |
| 196 | **Note:** We recommend standardizing your TypeScript settings into a single |
| 197 | `tsconfig.json` file or as few `tsconfig.json` files as possible. |
| 198 | |
| 199 | Note the following: |
| 200 | |
| 201 | * Bazel controls parts of the `tsconfig.json `file that define locations of |
| 202 | input and output files, manage dependencies on typings, and produce |
| 203 | JavaScript output that's readable by downstream tooling. Currently, this |
| 204 | format is unbundled UMD modules, wrapping noth named (non-anonymous) AMD |
| 205 | modules and `commonjs` modules. |
| 206 | |
| 207 | * Bazel may introduce new requirements for your TypeScript code. For example, |
| 208 | Bazel uses the `-declarations` flag to produce `.d.ts` outputs required by |
| 209 | dependent rule targets; your code may require adjustment to not produce |
| 210 | errors when the `-declarations` flag is in use. |
| 211 | |
| 212 | * If your TypeScript builds are slow, consider granularizing the affected rule |
| 213 | target(s) into smaller sub-targets and declaring dependencies between them |
| 214 | appropriately. |
| 215 | |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 216 | ### Running a development server (`ts_devserver`) |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 217 | |
| 218 | The `ts_devserver` rule brings up a development server from your application |
| 219 | sources. It's intended for use with the `ibazel run` command so that the server |
| 220 | picks up your code changes immediately. The rule injects a `livereload` script |
| 221 | into the browser, which causes the page to auto-refresh with the latest changes |
| 222 | at the completion of each build. |
| 223 | |
| 224 | **Tip:** You can test-drive the development server feature by running |
| 225 | `ibazel run src: devserver` on the [sample project](https://github.com/alexeagle/angular-bazel-example/wiki). |
| 226 | |
| 227 | |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 228 | ### Testing TypeScript code (`ts_web_test`) |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 229 | |
| 230 | Use the `ts_web_test` rule to execute the Karma test runner. This rule works |
| 231 | best with ibazel so that both the test runner and the browser pick up your |
| 232 | changes at the completion of each build. For faster builds, Bazel bundles your |
| 233 | code and its dependencies into a single JavaScript file delivered to the browser |
| 234 | when the test runner executes. |
| 235 | |
| 236 | If you need to match lots of tests with a target pattern such as bazel test //… |
| 237 | or using CI, run the `ts_web_test` rule with the regular `bazel test` command |
| 238 | instead. Bazel will then launch a headless Chrome instance and exit after a |
| 239 | single run. |
| 240 | |
| 241 | **Tip:** You can test-drive the `ts_web_test` rule by running `ibazel run` or |
| 242 | `bazel run` on the `src/hello-world:test` target in the [sample project](https://github.com/alexeagle/angular-bazel-example/wiki). |
| 243 | |
| 244 | |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 245 | ## Building Angular inputs |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 246 | |
spomorski | 03ca7d1 | 2018-06-05 11:32:48 -0700 | [diff] [blame] | 247 | Bazel can build JavaScript outputs from Angular. For instructions, see [Building Angular with Bazel](https://github.com/alexeagle/angular-bazel-example/wiki/Angular-rules). |
spomorski | 97a932f | 2018-06-04 10:16:44 -0700 | [diff] [blame] | 248 | |