Skip to content
Merged
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: 6 additions & 3 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,6 @@ npm.npm_translate_lock(
"//npm/private/test/vendored/is-odd:package.json",
"//npm/private/test/vendored/semver-max:package.json",
],
exclude_package_contents = {
"chalk": ["**/README*"],
},
generate_bzl_library_targets = True,
lifecycle_hooks = {
# We fetch @kubernetes/client-node from source and it has a `prepare` lifecycle hook that needs to be run
Expand Down Expand Up @@ -215,6 +212,12 @@ npm.npm_translate_lock(
verify_node_modules_ignored = "//:.bazelignore",
verify_patches = "//examples/npm_deps/patches:patches",
)

# Configure package exclusions using tag class
npm.npm_exclude_package_contents(
package = "chalk",
patterns = ["**/README*"],
)
use_repo(
npm,
"npm",
Expand Down
2 changes: 1 addition & 1 deletion docs/npm_translate_lock.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 12 additions & 4 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,19 +175,27 @@ If you are experiencing slower than expected builds, you can try disabling or re
Npm packages sometimes include unnecessary files such as tests, test data etc. Large files or a large number of files
can effect performance and are sometimes worth explicitly excluding content.

In these cases you can add such packages and the respective files/folders you want to exclude to your npm_translate_lock
rule in the `exclude_package_contents` attribute like so:
In these cases you can add such packages and the respective files/folders you want to exclude.

**For WORKSPACE builds:**
```starlark
npm.npm_translate_lock(
npm_translate_lock(
...
exclude_package_contents = {
"resolve": ["**/test/*"],
},
)
```

This example will remove the test folder.
**For Bzlmod builds (MODULE.bazel):**
```starlark
npm.npm_exclude_package_contents(
package = "resolve",
patterns = ["**/test/*"],
)
```

These examples will remove the test folder from the "resolve" package.

You can use this to remove whatever you find to be not needed for your project.

Expand Down
4 changes: 3 additions & 1 deletion e2e/npm_translate_lock/snapshots/wksp/repositories.bzl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 12 additions & 7 deletions e2e/npm_translate_lock_exclude_package_contents/MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,20 @@ npm = use_extension(
npm.npm_translate_lock(
name = "npm",
data = ["//:package.json"],
exclude_package_contents = {
"is-odd@3.0.1": [
"**/README*",
"",
"**/LICENSE*",
],
},
npmrc = "//:.npmrc",
pnpm_lock = "//:pnpm-lock.yaml",
verify_node_modules_ignored = "//:.bazelignore",
)
npm.npm_exclude_package_contents(
package = "*",
use_defaults = True,
)
npm.npm_exclude_package_contents(
package = "is-odd@3.0.1",
patterns = [
"**/README*",
"**/LICENSE*",
],
use_defaults = True,
)
use_repo(npm, "npm")
4 changes: 2 additions & 2 deletions e2e/npm_translate_lock_exclude_package_contents/WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ load("@aspect_rules_js//npm:repositories.bzl", "npm_translate_lock")
npm_translate_lock(
name = "npm",
exclude_package_contents = {
"*": True, # Use default exclusions for all packages
"is-odd@3.0.1": [
"**/README*",
"",
"**/LICENSE*",
],
], # Custom exclusions for specific package
},
npmrc = "//:.npmrc",
pnpm_lock = "//:pnpm-lock.yaml",
Expand Down
Empty file.
54 changes: 50 additions & 4 deletions npm/extensions.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ load("@aspect_bazel_lib//lib:repo_utils.bzl", "repo_utils")
load("@aspect_bazel_lib//lib:utils.bzl", bazel_lib_utils = "utils")
load("@bazel_features//:features.bzl", "bazel_features")
load("//npm:repositories.bzl", "npm_import", "pnpm_repository", _DEFAULT_PNPM_VERSION = "DEFAULT_PNPM_VERSION", _LATEST_PNPM_VERSION = "LATEST_PNPM_VERSION")
load("//npm/private:exclude_package_contents_default.bzl", "exclude_package_contents_default")
load("//npm/private:npm_import.bzl", "npm_import_lib", "npm_import_links_lib")
load("//npm/private:npm_translate_lock.bzl", "npm_translate_lock_lib", "npm_translate_lock_rule")
load("//npm/private:npm_translate_lock_helpers.bzl", npm_translate_lock_helpers = "helpers")
Expand All @@ -24,16 +25,19 @@ def _npm_extension_impl(module_ctx):
# ctx.actions.declare_symlink was added in Bazel 6
fail("A minimum version of Bazel 6 required to use rules_js")

# Collect all exclude_package_contents tags and build exclusion dictionary
exclude_package_contents_config = _build_exclude_package_contents_config(module_ctx)

for mod in module_ctx.modules:
for attr in mod.tags.npm_translate_lock:
_npm_translate_lock_bzlmod(attr)
_npm_translate_lock_bzlmod(attr, exclude_package_contents_config)

# We cannot read the pnpm_lock file before it has been bootstrapped.
# See comment in e2e/update_pnpm_lock_with_import/test.sh.
if attr.pnpm_lock:
if hasattr(module_ctx, "watch"):
module_ctx.watch(attr.pnpm_lock)
_npm_lock_imports_bzlmod(module_ctx, attr)
_npm_lock_imports_bzlmod(module_ctx, attr, exclude_package_contents_config)

for i in mod.tags.npm_import:
_npm_import_bzlmod(i)
Expand All @@ -44,7 +48,29 @@ def _npm_extension_impl(module_ctx):
)
return module_ctx.extension_metadata()

def _npm_translate_lock_bzlmod(attr):
def _build_exclude_package_contents_config(module_ctx):
"""Build exclude_package_contents configuration from tags across all modules."""
exclusions = {}

for mod in module_ctx.modules:
for exclude_tag in mod.tags.npm_exclude_package_contents:
# Process the package in the tag
package = exclude_tag.package
if package in exclusions:
fail("Duplicate exclude_package_contents tag for package: {}".format(package))

exclusions[package] = []

# Add default exclusions if requested
if exclude_tag.use_defaults:
exclusions[package].extend(exclude_package_contents_default)

# Add custom patterns
exclusions[package].extend(exclude_tag.patterns)

return exclusions

def _npm_translate_lock_bzlmod(attr, exclude_package_contents_config):
npm_translate_lock_rule(
name = attr.name,
bins = attr.bins,
Expand Down Expand Up @@ -74,10 +100,11 @@ def _npm_translate_lock_bzlmod(attr):
verify_node_modules_ignored = attr.verify_node_modules_ignored,
verify_patches = attr.verify_patches,
yarn_lock = attr.yarn_lock,
exclude_package_contents = exclude_package_contents_config,
bzlmod = True,
)

def _npm_lock_imports_bzlmod(module_ctx, attr):
def _npm_lock_imports_bzlmod(module_ctx, attr, exclude_package_contents_config):
state = npm_translate_lock_state.new(attr.name, module_ctx, attr, True)

importers, packages = translate_to_transitive_closure(
Expand Down Expand Up @@ -131,6 +158,7 @@ WARNING: Cannot determine home directory in order to load home `.npmrc` file in
registries = registries,
default_registry = state.default_registry(),
npm_auth = npm_auth,
exclude_package_contents_config = exclude_package_contents_config,
)

system_tar = detect_system_tar(module_ctx)
Expand Down Expand Up @@ -218,6 +246,7 @@ def _npm_translate_lock_attrs():

# Args not supported or unnecessary in bzlmod
attrs.pop("repositories_bzl_filename")
attrs.pop("exclude_package_contents") # Use tag classes only for MODULE.bazel

return attrs

Expand All @@ -237,11 +266,28 @@ def _npm_import_attrs():

return attrs

def _npm_exclude_package_contents_attrs():
return {
"package": attr.string(
doc = "Package name to apply exclusions to. Supports wildcards like '*' for all packages.",
mandatory = True,
),
"patterns": attr.string_list(
doc = "List of glob patterns to exclude from the specified package.",
default = [],
),
"use_defaults": attr.bool(
doc = "Whether to use default exclusion patterns for the specified package. Defaults are as to Yarn autoclean: https://github.com/yarnpkg/yarn/blob/7cafa512a777048ce0b666080a24e80aae3d66a9/src/cli/commands/autoclean.js#L16",
default = False,
),
}

npm = module_extension(
implementation = _npm_extension_impl,
tag_classes = {
"npm_translate_lock": tag_class(attrs = _npm_translate_lock_attrs()),
"npm_import": tag_class(attrs = _npm_import_attrs()),
"npm_exclude_package_contents": tag_class(attrs = _npm_exclude_package_contents_attrs()),
},
)

Expand Down
1 change: 1 addition & 0 deletions npm/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ bzl_library(
name = "npm_translate_lock",
srcs = ["npm_translate_lock.bzl"],
deps = [
":exclude_package_contents_default.bzl",
":list_sources",
":npm_translate_lock_generate",
":npm_translate_lock_helpers",
Expand Down
53 changes: 53 additions & 0 deletions npm/private/exclude_package_contents_default.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""A default files exclude list for common packages.

Based on Yarn autoclean; see
https://github.com/yarnpkg/yarn/blob/7cafa512a777048ce0b666080a24e80aae3d66a9/src/cli/commands/autoclean.js#L16
"""

exclude_package_contents_default = [
# test directories
"**/__tests__/**",
"**/test/**",
"**/tests/**",
"**/powered-test/**",

# asset directories
"**/docs/**",
"**/doc/**",
"**/website/**",
"**/images/**",
"**/assets/**",

# examples
"**/example/**",
"**/examples/**",

# code coverage directories
"**/coverage/**",
"**/.nyc_output/**",

# build scripts (files)
"Makefile",
"Gulpfile.js",
"Gruntfile.js",

# configs (files)
"appveyor.yml",
"circle.yml",
"codeship-services.yml",
"codeship-steps.yml",
"wercker.yml",
".tern-project",
".gitattributes",
".editorconfig",
".*ignore",
".eslintrc",
".jshintrc",
".flowconfig",
".documentup.json",
".yarn-metadata.json",
".travis.yml",

# misc (files)
"*.md",
]
44 changes: 39 additions & 5 deletions npm/private/npm_translate_lock.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Advanced users may want to directly fetch a package from npm rather than start f
load("@aspect_bazel_lib//lib:utils.bzl", bazel_lib_utils = "utils")
load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_file")
load("@bazel_skylib//lib:paths.bzl", "paths")
load(":exclude_package_contents_default.bzl", "exclude_package_contents_default")
load(":list_sources.bzl", "list_sources")
load(":npm_translate_lock_generate.bzl", "generate_repository_files")
load(":npm_translate_lock_helpers.bzl", "helpers")
Expand All @@ -43,6 +44,31 @@ RULES_JS_FROZEN_PNPM_LOCK_ENV = "ASPECT_RULES_JS_FROZEN_PNPM_LOCK"
DEFAULT_REPOSITORIES_BZL_FILENAME = "repositories.bzl"
DEFAULT_DEFS_BZL_FILENAME = "defs.bzl"

def _normalize_exclude_package_contents(exclude_package_contents):
"""Normalize exclude_package_contents dictionary for string_list_dict format."""
if not exclude_package_contents:
return {}

result = {}
for package, value in exclude_package_contents.items():
if type(value) == "bool":
if value == True:
# True means use default exclusions
result[package] = exclude_package_contents_default
else:
# False means no exclusions
result[package] = []
elif type(value) == "list":
# Lists must contain only strings
for item in value:
if type(item) != "string":
fail("exclude_package_contents list values must be strings. Got: {} in package '{}'".format(type(item), package))
result[package] = value
else:
fail("exclude_package_contents values must be boolean or string list. Got: {} for package '{}'".format(type(value), package))

return result

_ATTRS = {
"additional_file_contents": attr.string_list_dict(),
"bins": attr.string_list_dict(),
Expand Down Expand Up @@ -284,18 +310,26 @@ def npm_translate_lock(

Read more: [patching](/docs/pnpm.md#patching)

exclude_package_contents: 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 patterns to exclude from the package's generated node_modules link targets. Multiple matches are additive.
exclude_package_contents: Configuration for excluding package contents (WORKSPACE only).

For MODULE.bazel, use the `exclude_package_contents` tag class instead.

The configuration is a dictionary that maps package names (or package names with their version, e.g., "my-package" or "my-package@v1.2.3") to exclusion rules.

Values can be:
- `True`: Use default exclusions
- List of strings: Multiple exclusion patterns

Versions must match if used.

For example,
Example:

```
exclude_package_contents = {
"*": True, # Use defaults for all packages
"@foo/bar": ["**/test/**"],
"@foo/car@2.0.0": ["**/README*"],
},
}
```
patch_tool: The patch tool to use. If not specified, the `patch` from `PATH` is used.

Expand Down Expand Up @@ -591,7 +625,7 @@ def npm_translate_lock(
npmrc = npmrc,
use_home_npmrc = use_home_npmrc,
patches = patches,
exclude_package_contents = exclude_package_contents,
exclude_package_contents = _normalize_exclude_package_contents(exclude_package_contents),
patch_tool = patch_tool,
patch_args = patch_args,
custom_postinstalls = custom_postinstalls,
Expand Down
2 changes: 1 addition & 1 deletion npm/private/npm_translate_lock_generate.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ def _gen_npm_import(rctx, system_tar, _import, link_workspace):
maybe_replace_package = ("""
replace_package = "%s",""" % _import.replace_package) if _import.replace_package else ""
maybe_exclude_package_contents = ("""
exclude_package_contents = %s,""" % _import.exclude_package_contents) if _import.exclude_package_contents != None else ""
exclude_package_contents = %s,""" % starlark_codegen_utils.to_list_attr(_import.exclude_package_contents)) if _import.exclude_package_contents != None else ""

return _NPM_IMPORT_TMPL.format(
link_packages = starlark_codegen_utils.to_dict_attr(_import.link_packages, 2, quote_value = False),
Expand Down
Loading
Loading