rules_js in your Bazel project.
For installation and package management setup, see the JavaScript & TypeScript overview.
Link node_modules
After importing yourpnpm-lock.yaml, you need to link npm packages into a node_modules tree that the Node.js runtime can use. If you use pnpm workspaces, the node_modules tree contains first-party packages from your monorepo as well as third-party packages from npm.
Bazel doesn’t use the
node_modules installed in your source tree, so you don’t need to run pnpm install before running Bazel commands. This means that changes you make to files under node_modules in your source tree aren’t reflected in Bazel results.npm packages into the Bazel package containing the package.json file.
If you use pnpm workspaces, you need to do this for each npm package in your monorepo.
In BUILD.bazel:
bazel build ..., then check the bazel-bin folder.
The output should be something like this:
- npm_import: Import all packages from the
pnpm-lock.yamlfile, or import individual packages. - npm_link_package: Link npm package(s) into the
bazel-bin/[path/to/package]/node_modulestree so that the Node.js runtime can resolve them.
pnpm workspaces
If you use pnpm workspaces, define which directories contain packages in apnpm-workspace.yaml file at the root of your repository.
The following example finds all projects under apps or packages at any depth, and anything directly under tools:
Source files in bazel-bin
The Node.js module resolution algorithm requires that you co-locate all files—sources, generated code, and dependencies—in a common filesystem tree:- dependencies in
bazel-bin/[path/to/package]/node_modules - generated and source files in
bazel-bin/[path/to/package]
Note that other Bazel rulesets accommodate tooling by teaching it to mix a source folder and an output folder. This isn’t possible with Node.js without breaking compatibility of many tools, so
rules_js copies sources to bazel-bin instead.js_library take care of copying their sources to bazel-bin automatically. However, this only works when those sources are under the same BUILD file as the target that does the copying. If you have a source file in another BUILD file, you need to explicitly copy it
with a rule like copy_to_bin.
Use binaries published to npm
rules_js automatically mirrors the bin field from the package.json file of your npm dependencies to a Starlark API you can load from in your BUILD file or macro.
For example, if you depend on the typescript npm package in your root package.json, you can access the tsc bin entry in a BUILD:
typescript npm package from a nested package.json such as myapp/package.json, load the bin entry from the nested package:
bazel build: js_run_binarybazel test: js_testbazel run: js_binary
| Rule | Underlying Rule | Invoked with | To |
|---|---|---|---|
tsc | js_run_binary | bazel build | produce outputs |
tsc_binary | js_binary | bazel run | side-effects |
tsc_test | js_test | bazel test | assert exit 0 |
Inspect the npm workspace
To inspect what’s in the@npm workspace, start with a bazel query such as:
npm packages.
These queries only work when you pass
generate_bzl_library_targets = True to npm_translate_lock. If you get no results, confirm that the settings in your MODULE.bazel file are correct and try again.bazel query to view the definition of a specific target:
Macros
Bazel macros are a critical part of making your BUILD files more maintainable. You can think of macros as a way to create your own build system by piping existing tools together, like a Unix pipeline that composes command-line utilities. Make sure to follow the Macros section of the Starlark Style Guide when writing a macro, since some anti-patterns can make your BUILD files difficult to change in the future. As an example, the followingtsc.bzl file wraps the preceding typescript_bin.tsc rule, setting default arguments and the working directory:
BUILD files become shorter and more consistent:
Document macros with Stardoc
You can use Stardoc to produce API documentation from Starlark code. Aspect recommends producing Markdown output, and checking those.md files into your source repository so they’re easy to browse at the same revision as the sources.
As a best practice, create bzl_library targets for your Starlark files as it lets users of your code generate their own documentation.
Aspect’s bazel-lib provides stardoc_with_diff_test and update_docs, helpers that run Stardoc and verify that your checked-in docs stay up to date.
Continuing the preceding example, that includes a macro in tsc.bzl, you’d write this to document it in BUILD:
bzl_library for the tsc.bzl macro, then uses stardoc_with_diff_test to generate a Markdown doc and fail the build if the checked-in copy is out of date. The update_docs target lets you regenerate all docs with bazel run //:docs.
Find a similar example in examples/macro.
Debugging
Add the debug settings from therules_nodejs common.bazelrc to your project’s .bazelrc file to enable --config=debug for Node.js programs.
For example, you can debug the js_test target with:
Debugging with Chrome DevTools
Go tochrome://inspect/ in Chrome to find the debugging session and connect to it with Chrome DevTools.
See Debugging Node.js with Chrome DevTools
to understand the basics of using the DevTools with Node.
Debugging with Visual Studio Code
You can add a.vscode/launch.json configuration file
to launch into a debugging session directly from the
Run & Debug window.
See the JavaScript/TypeScript Bazel Starter for an example.
