Skip to main content
Documentation for @aspect_rules_js@v3.0.0 View source
Setup steps, or extensions for pnpm. These are used in MODULE.bazel files to pin tooling versions, for example assuming
  • the desired version of Node.js is specified in a .nvmrc file
  • the desired version of pnpm is specified in the package.json#packageManager field
  • package manager preferences (especially hoist=false) is in .npmrc
  • pnpm dependencies were resolved and locked using pnpm-lock.yaml
then the following MODULE.bazel file can be used:
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node")
node.toolchain(node_version_from_nvmrc = "//:.nvmrc")
use_repo(node, "nodejs_toolchains")

pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm")
use_repo(pnpm, "pnpm")
pnpm.pnpm(pnpm_version_from = "//:package.json")

npm = use_extension("@aspect_rules_js//npm:extensions.bzl", "npm")
npm.npm_translate_lock(
    name = "npm",
    npmrc = "//:.npmrc",
    pnpm_lock = "//:pnpm-lock.yaml",
)
use_repo(npm, "npm")

Module extension: npm

Tag: npm_translate_lock

Import a pnpm lock file and create npm_import rules to fetch each package. These use Bazel’s downloader to fetch the packages. You can use this to redirect all fetches through a store like Artifactory. See Configuring Bazel’s Downloader for more info about how it works and how to configure it. The npm_translate_lock module extension tag is the primary user-facing API. It uses the lockfile format from pnpm because it gives us reliable semantics for how to dynamically lay out node_modules trees on disk in bazel-out. To create pnpm-lock.yaml, consider using pnpm import to preserve the versions pinned by your existing package-lock.json or yarn.lock file. If you don’t have an existing lock file, you can run npx pnpm install --lockfile-only. Advanced users may want to directly fetch a package from npm rather than start from a lockfile, npm_import does this.

Generated repository layout

  • A defs.bzl file containing some rules such as npm_link_all_packages, which are documented here.
  • BUILD files declaring targets for the packages listed as dependencies or devDependencies in package.json, so you can declare dependencies on those packages without having to repeat version information.
This macro creates a pnpm external repository, if the user didn’t create a repository named “pnpm” prior to calling npm_translate_lock. rules_js currently only uses this repository when npm_package_lock or yarn_lock are used. Set pnpm_version to None to inhibit this repository creation. For more about how to use npm_translate_lock, read pnpm and rules_js.
bins
dictionary: String → List of strings
default:"{}"
Binary files to create in node_modules/.bin for packages in this lock file.For a given package, this is typically derived from the “bin” attribute in the package.json file of that package.For example:
bins = {
    "@foo/bar": {
        "foo": "./foo.js",
        "bar": "./bar.js"
    },
}
Dicts of bins not additive. The most specific match wins.In the future, this field may be automatically populated from information in the pnpm lock file. That feature is currently blocked on https://github.com/pnpm/pnpm/issues/5131.Note: Bzlmod users must use an alternative syntax due to module extensions not supporting dict-of-dict attributes:
bins = {
    "@foo/bar": [
        "foo=./foo.js",
        "bar=./bar.js"
    ],
}
custom_postinstalls
dictionary: String → String
default:"{}"
” A map of package names or package names with their version (e.g., “my-package” or “my-package@v1.2.3”) to a custom postinstall script to apply to the downloaded npm package after its lifecycle scripts runs. If the version is left out of the package name, the script will run on every version of the npm package. If a custom postinstall scripts exists for a package as well as for a specific version, the script for the versioned package will be appended with && to the non-versioned package script.For example,
custom_postinstalls = {
    "@foo/bar": "echo something > somewhere.txt",
    "fum@0.0.1": "echo something_else > somewhere_else.txt",
},
Custom postinstalls are additive and joined with && when there are multiple matches for a package. More specific matches are appended to previous matches.
data
list of labels
default:"[]"
Data files required by this repository rule when auto-updating the pnpm lock file.Only needed when update_pnpm_lock is True. Read more: using update_pnpm_lock
external_repository_action_cache
string
default:".aspect/rules/external_repository_action_cache"
The location of the external repository action cache to write to when update_pnpm_lock = True.
generate_bzl_library_targets
boolean
default:"False"
lifecycle_hooks_envs
dictionary: String → List of strings
default:"{}"
Environment variables set for the lifecycle hooks actions on npm packages. The environment variables can be defined per package by package name or globally using ”*”. Variables are declared as key/value pairs of the form “key=value”. Multiple matches are additive.Read more: lifecycles
lifecycle_hooks
dictionary: String → List of strings
default:"{}"
A dict of package names to list of lifecycle hooks to run for that package.By default the preinstall, install and postinstall hooks are run if they exist. This attribute allows the default to be overridden for packages to run prepare.List of hooks are not additive. The most specific match wins.Read more: lifecycles
lifecycle_hooks_exclude
list of strings
default:"[]"
A list of package names or package names with their version (e.g., “my-package” or “my-package@v1.2.3”) to not run any lifecycle hooks on.Equivalent to adding <value>: [] to lifecycle_hooks.Read more: lifecycles
lifecycle_hooks_execution_requirements
dictionary: String → List of strings
default:"{}"
Execution requirements applied to the preinstall, install and postinstall lifecycle hooks on npm packages.The execution requirements can be defined per package by package name or globally using ”*”.Execution requirements are not additive. The most specific match wins.Read more: lifecycles
lifecycle_hooks_use_default_shell_env
dictionary: String → String
default:"{}"
The use_default_shell_env attribute of the lifecycle hooks actions on npm packages.See use_default_shell_envThis defaults to False to reduce the negative effects of use_default_shell_env.Read more: lifecycles
lifecycle_hooks_no_sandbox
boolean
default:"True"
If True, a “no-sandbox” execution requirement is added to all lifecycle hooks unless overridden by lifecycle_hooks_execution_requirements.Equivalent to adding "*": ["no-sandbox"] to lifecycle_hooks_execution_requirements.This defaults to True to limit the overhead of sandbox creation and copying the output TreeArtifacts out of the sandbox.Read more: lifecycles
name
name
default:"\"\""
no_dev
boolean
default:"False"
If True, devDependencies are not included
no_optional
boolean
default:"False"
If True, optionalDependencies are not installed.Currently npm_translate_lock behaves differently from pnpm in that it downloads all optionalDependencies while pnpm doesn’t download optionalDependencies that are not needed for the platform pnpm is run on. See https://github.com/pnpm/pnpm/pull/3672 for more context.
node_toolchain_prefix
string
default:"nodejs"
the prefix of the node toolchain to use when generating the pnpm lockfile.
npm_package_lock
label
default:"None"
The package-lock.json file written by npm install.Only one of npm_package_lock or yarn_lock may be set.
npm_package_target_name
string
default:"pkg"
The name of linked js_library, npm_package or JsInfo producing targets.When targets are linked as pnpm workspace packages, the name of the target must align with this value.The {dirname} placeholder is replaced with the directory name of the target.
npmrc
label
default:"None"
The .npmrc file, if any, to use.When set, the .npmrc file specified is parsed and npm auth tokens and basic authentication configuration specified in the file are passed to the Bazel downloader for authentication with private npm registries.In a future release, pnpm settings such as public-hoist-patterns will be used.
package_visibility
dictionary: String → List of strings
default:"{}"
A map of package names or package names with their version (e.g., “my-package” or “my-package@v1.2.3”) to a visibility list to use for the package’s generated node_modules link targets. Multiple matches are additive. If there are no matches then the package’s generated node_modules link targets default to public visibility (["//visibility:public"]).
patch_tool
label
default:"None"
The patch tool to use. If not specified, the patch from PATH is used.
patch_args
dictionary: String → List of strings
default:"{\"*\": [\"-p0\"]}"
A map of package names or package names with their version (e.g., “my-package” or “my-package@v1.2.3”) to a label list arguments to pass to the patch tool. The most specific match wins.Read more: patching
patches
dictionary: String → List of strings
default:"{}"
A map of package names or package names with their version (e.g., “my-package” or “my-package@v1.2.3”) to a label list of patches to apply to the downloaded npm package. Multiple matches are additive.These patches are applied after any patches in pnpm.patchedDependencies.Read more: patching
use_pnpm
label
default:"@pnpm//:package/bin/pnpm.cjs"
label of the pnpm entry point to use.
pnpm_lock
label
default:"None"
The pnpm-lock.yaml file, containing resolved and pinned package versions.
preupdate
list of labels
default:"[]"
Node.js scripts to run in this repository rule before auto-updating the pnpm lock file.Scripts are run sequentially in the order they are listed. The working directory is set to the root of the external repository. Make sure all files required by preupdate scripts are added to the data attribute.A preupdate script could, for example, transform resolutions in the root package.json file from a format that yarn understands such as @foo/**/bar to the equivalent @foo/*>bar that pnpm understands so that resolutions are compatible with pnpm when running pnpm import to update the pnpm lock file.Only needed when update_pnpm_lock is True. Read more: using update_pnpm_lock
public_hoist_packages
dictionary: String → List of strings
default:"{}"
A map of package names or package names with their version (e.g., “my-package” or “my-package@v1.2.3”) to a list of Bazel packages in which to hoist the package to the top-level of the node_modules tree when linking.This is similar to setting https://pnpm.io/npmrc#public-hoist-pattern in an .npmrc file outside of Bazel, however, wild-cards are not yet supported and npm_translate_lock will fail if there are multiple versions of a package that are to be hoisted.
public_hoist_packages = {
    "@foo/bar": [""] # link to the root package
    "fum@0.0.1": ["some/sub/package"]
},
List of public hoist packages are additive when there are multiple matches for a package. More specific matches are appended to previous matches.
quiet
boolean
default:"True"
Set to False to print info logs and output stdout & stderr of pnpm lock update actions to the console.
run_lifecycle_hooks
boolean
default:"True"
Sets a default value for lifecycle_hooks if * not already set. Set this to False to disable lifecycle hooks.
update_pnpm_lock
boolean
default:"False"
When True, the pnpm lock file will be updated automatically when any of its inputs have changed since the last update.Defaults to True when one of npm_package_lock or yarn_lock are set. Otherwise it defaults to False.Read more: using update_pnpm_lock
use_home_npmrc
boolean
default:"False"
Use the $HOME/.npmrc file (or $USERPROFILE/.npmrc when on Windows) if it exists.Settings from home .npmrc are merged with settings loaded from the .npmrc file specified in the npmrc attribute, if any. Where there are conflicting settings, the home .npmrc values will take precedence.WARNING: The repository rule will not be invalidated by changes to the home .npmrc file since there is no way to specify this file as an input to the repository rule. If changes are made to the home .npmrc you can force the repository rule to re-run and pick up the changes by running: bazel run @{name}//:sync where name is the name of the npm_translate_lock you want to re-run.Because of the repository rule invalidation issue, using the home .npmrc is not recommended. .npmrc settings should generally go in the npmrc in your repository so they are shared by all developers. The home .npmrc should be reserved for authentication settings for private npm repositories.
verify_node_modules_ignored
label
default:"None"
Bazel 7.x only (deprecated) - Verifies node_modules folders are ignored.This points to a .bazelignore file to verify that all nested node_modules directories pnpm will create are listed.Bazel 8+: Use ignore_directories(["**/node_modules"]) in REPO.bazel instead.See https://github.com/bazelbuild/bazel/issues/8106
verify_patches
label
default:"None"
Label to a patch list file.Use this together with the list_patches macro to guarantee that all patches in a patch folder are included in the patches attribute.For example:
verify_patches = "//patches:patches.list",
In your patches folder add a BUILD.bazel file containing.
load("@aspect_rules_js//npm:repositories.bzl", "list_patches")

list_patches(
    name = "patches",
    out = "patches.list",
)
Once you have created this file, you need to create an empty patches.list file before generating the first list. You can do this by running
touch patches/patches.list
Finally, write the patches file at least once to make sure all patches are listed. This can be done by running bazel run //patches:patches_update.See the list_patches documentation for further info. NOTE: if you would like to customize the patches directory location, you can set a flag in the .npmrc. Here is an example of what this might look like
# Set the directory for pnpm when patching
# https://github.com/pnpm/pnpm/issues/6508#issuecomment-1537242124
patches-dir=bazel/js/patches
If you do this, you will have to update the verify_patches path to be this path instead of //patches like above.
yarn_lock
label
default:"None"
The yarn.lock file written by yarn install.Only one of npm_package_lock or yarn_lock may be set.

Tag: npm_import

Import a single npm package into Bazel. Normally you’d want to use npm_translate_lock to import all your packages at once. It generates npm_import rules. You can create these manually if you want to have exact control. Bazel will only fetch the given package from an external registry if the package is required for the user-requested targets to be build/tested. For example, in MODULE.bazel:
npm.npm_import(
    name = "npm__at_types_node__15.12.2",
    package = "@types/node",
    version = "15.12.2",
    integrity = "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==",
)
use_repo(npm, "npm__at_types_node__15.12.2")
use_repo(npm, "npm__at_types_node__15.12.2__links")
This is similar to Bazel rules in other ecosystems named “_import” like apple_bundle_import, scala_import, java_import, and py_import. go_repository is also a model for this rule.
The name of this repository should contain the version number, so that multiple versions of the same package don’t collide. (Note that the npm ecosystem always supports multiple versions of a library depending on where it is required, unlike other languages like Go or Python.) To consume the downloaded package in rules, it must be “linked” into the link package in the package’s BUILD.bazel file:
load("@npm__at_types_node__15.12.2__links//:defs.bzl", npm_link_types_node = "npm_link_imported_package")

npm_link_types_node()
This links @types/node into the node_modules of this package with the target name :node_modules/@types/node. A :node_modules/@types/node/dir filegroup target is also created that provides the directory artifact of the npm package. These targets can be used to create entry points for binary target or to access files within the npm package. NB: You can choose any target name for the link target but we recommend using the node_modules/@scope/name and node_modules/name convention for readability. When using npm_translate_lock, you can link all the npm dependencies in the lock file for a package:
load("@npm//:defs.bzl", "npm_link_all_packages")

npm_link_all_packages()
This creates :node_modules/name and :node_modules/@scope/name targets for all direct npm dependencies in the package. It also creates :node_modules/name/dir and :node_modules/@scope/name/dir filegroup targets that provide the directory artifacts of their npm packages. These targets can be used to create entry points for binary targets or to access files within the npm package. If you have a mix of npm_link_all_packages and npm_link_imported_package functions to call you can pass the npm_link_imported_package link functions to the imported_links attribute of npm_link_all_packages to link them all in one call. For example,
load("@npm//:defs.bzl", "npm_link_all_packages")
load("@npm__at_types_node__15.12.2__links//:defs.bzl", npm_link_types_node = "npm_link_imported_package")

npm_link_all_packages(
    imported_links = [
        npm_link_types_node,
    ]
)
This has the added benefit of adding the imported_links to the convenience :node_modules target which includes all direct dependencies in that package. NB: You can pass an name to npm_link_all_packages and this will change the targets generated to “{name}/@scope/name” and “{name}/name”. We recommend using “node_modules” as the convention for readability. To change the proxy URL we use to fetch, configure the Bazel downloader:
  1. Make a file containing a rewrite rule like rewrite (registry.npmjs.org)/(.*) artifactory.build.internal.net/artifactory/$1/$2
  2. To understand the rewrites, see UrlRewriterConfig in Bazel sources.
  3. Point bazel to the config with a line in .bazelrc like common —experimental_downloader_config=.bazel_downloader_config
Read more: Configuring Bazel’s Downloader.
package
string
required
Name of the npm package, such as acorn or @types/node
root_package
string
default:"\"\""
The root package where the node_modules package store is linked to. Typically this is the package that the pnpm-lock.yaml file is located when using npm_translate_lock.
version
string
required
Version of the npm package, such as 8.4.0
exclude_package_contents
list of strings
default:"[]"
List of glob patterns to exclude from the linked package.This is useful for excluding files that are not needed in the linked package.For example:
exclude_package_contents = ["**/tests/**"]
exclude_package_contents_presets
list of strings
default:"[\"basic\"]"
commit
string
default:"\"\""
Specific commit to be checked out if url is a git repository.
custom_postinstall
string
default:"\"\""
Custom string postinstall script to run on the installed npm package.Runs after any existing lifecycle hooks if any are enabled.
extra_build_content
string
default:"\"\""
Additional content to append on the generated BUILD file at the root of the created repository, either as a string or a list of lines to concatenate.
extract_full_archive
boolean
default:"False"
integrity
string
default:"\"\""
Expected checksum of the file downloaded, in Subresource Integrity format. This must match the checksum of the file downloaded.This is the same as appears in the pnpm-lock.yaml, yarn.lock or package-lock.json file.It is a security risk to omit the checksum as remote files can change.At best omitting this field will make your build non-hermetic.It is optional to make development easier but should be set before shipping.
lifecycle_hooks
list of strings
default:"[]"
List of lifecycle hook package.json scripts to run for this package if they exist.
npm_auth
string
default:"\"\""
Auth token to authenticate with npm. When using Bearer authentication.
npm_auth_basic
string
default:"\"\""
Auth token to authenticate with npm. When using Basic authentication.This is typically the base64 encoded string “username:password”.
npm_auth_password
string
default:"\"\""
Auth password to authenticate with npm. When using Basic authentication.
npm_auth_username
string
default:"\"\""
Auth username to authenticate with npm. When using Basic authentication.
patch_tool
label
default:"None"
The patch tool to use. If not specified, the patch from PATH is used.
patch_args
list of strings
default:"[\"-p0\"]"
Arguments to pass to the patch tool.-p1 will usually be needed for patches generated by git.
patches
list of labels
default:"[]"
Patch files to apply onto the downloaded npm package.
url
string
default:"\"\""
Optional url for this package. If unset, a default npm registry url is generated from the package name and version.May start with git+ssh:// or git+https:// to indicate a git repository. For example,
git+ssh://git@github.com/org/repo.git
If url is configured as a git repository, the commit attribute must be set to the desired commit.
bins
dictionary: String → String
default:"{}"
Dictionary of node_modules/.bin binary files to create mapped to their node entry points.This is typically derived from the “bin” attribute in the package.json file of the npm package being linked.For example:
bins = {
    "foo": "./foo.js",
    "bar": "./bar.js",
}
In the future, this field may be automatically populated by npm_translate_lock from information in the pnpm lock file. That feature is currently blocked on https://github.com/pnpm/pnpm/issues/5131.
deps
dictionary: String → String
default:"{}"
A dict other npm packages this one depends on where the key is the package name and value is the version
lifecycle_build_target
boolean
default:"False"
lifecycle_hooks_env
list of strings
default:"[]"
Environment variables set for the lifecycle hooks action for this npm package if there is one.Environment variables are defined by providing an array of “key=value” entries.For example:
lifecycle_hooks_env: ["PREBULT_BINARY=https://downloadurl"],
lifecycle_hooks_execution_requirements
list of strings
default:"[\"no-sandbox\"]"
Execution requirements when running the lifecycle hooks.For example:
lifecycle_hooks_execution_requirements: ["no-sandbox", "requires-network"]
This defaults to [“no-sandbox”] to limit the overhead of sandbox creation and copying the output TreeArtifact out of the sandbox.
lifecycle_hooks_use_default_shell_env
boolean
default:"False"
If True, the use_default_shell_env attribute of lifecycle hook actions is set to True.See use_default_shell_envThis defaults to False to reduce the negative effects of use_default_shell_env.
package_visibility
list of strings
default:"[\"//visibility:public\"]"
Visibility of generated node_module link targets.
replace_package
string
default:"\"\""
Use the specified npm_package target when linking instead of the fetched sources for this npm package.The injected npm_package target may optionally contribute transitive npm package dependencies on top of the transitive dependencies specified in the pnpm lock file for the same package, however, these transitive dependencies must not collide with pnpm lock specified transitive dependencies.Any patches specified for this package will be not applied to the injected npm_package target. They will be applied, however, to the fetches sources so they can still be useful for patching the fetched package.json file, which is used to determine the generated bin entries for the package.NB: lifecycle hooks and custom_postinstall scripts, if implicitly or explicitly enabled, will be run on the injected npm_package. These may be disabled explicitly using the lifecycle_hooks attribute.
name
name
default:"\"\""
lifecycle_hooks_no_sandbox
boolean
default:"False"
run_lifecycle_hooks
boolean
default:"False"

Tag: npm_exclude_package_contents

Configuration for excluding package contents from npm packages. This tag can be used multiple times to specify different exclusion patterns for different package specifiers. More specific package matches override less specific ones (the wildcard ”*” is only used if no specific package match is found). By default, presets is set to ["basic"] which excludes common files such as *.md and development-related files. Multiple presets can be combined. Example:
npm.npm_exclude_package_contents(
    package = "*",
    patterns = ["**/docs/**"],
)
npm.npm_exclude_package_contents(
    package = "my-package@1.2.3",
    # Overrides the "*" config for this specific package
    presets = ["yarn_autoclean"],
)
package
string
required
Package name to apply exclusions to. Supports wildcards like ’*’ for all packages.
patterns
list of strings
default:"[]"
List of glob patterns to exclude from the specified package.
presets
list of strings
default:"[\"basic\"]"
Which preset exclusion patterns to include. Multiple presets can be combined. Valid values:

Tag: npm_replace_package

Replace a package with a custom target. This allows replacing packages declared in package.json with custom implementations. Multiple npm_replace_package tags can be used to replace different packages. Targets must produce JsInfo or NpmPackageInfo providers such as js_library or npm_package targets. The injected package targets may optionally contribute transitive npm package dependencies on top of the transitive dependencies specified in the pnpm lock file for their respective packages, however, these transitive dependencies must not collide with pnpm lock specified transitive dependencies. Any patches specified for the packages will be not applied to the injected package targets. They will be applied, however, to the fetched sources for their respective packages so they can still be useful for patching the fetched package.json files, which are used to determine the generated bin entries for packages. NB: lifecycle hooks and custom_postinstall scripts, if implicitly or explicitly enabled, will be run on the injected package targets. These may be disabled explicitly using the lifecycle_hooks attribute. Example:
npm.npm_replace_package(
    package = "chalk@5.3.0",
    replacement = "@chalk_501//:pkg",
)
package
string
required
The package name and version to replace (e.g., ‘chalk@5.3.0’)
replacement
label
required
The target to use as replacement for this package

Module extension: pnpm

Tag: pnpm

name
name
default:"pnpm"
Name of the generated repository, allowing more than one pnpm version to be registered. Overriding the default is only permitted in the root module.
include_npm
boolean
default:"False"
If true, include the npm package along with the pnpm binary.
pnpm_version
string
default:"10.28.2"
pnpm version to use. The string latest will be resolved to LATEST_PNPM_VERSION.
pnpm_version_from
label
default:"None"
Label to a package.json file to read the pnpm version from.It should appear as an attribute like "packageManager": "pnpm@10.20.0"
pnpm_version_integrity
string
default:"\"\""