Skip to content

fix(arborist): do not install inert optional extraneous shared dependencies#9221

Merged
wraithgar merged 1 commit intonpm:latestfrom
lovell:arborist-optional-set-remove-shared-extraneous
Apr 15, 2026
Merged

fix(arborist): do not install inert optional extraneous shared dependencies#9221
wraithgar merged 1 commit intonpm:latestfrom
lovell:arborist-optional-set-remove-shared-extraneous

Conversation

@lovell
Copy link
Copy Markdown
Contributor

@lovell lovell commented Apr 13, 2026

A shared dependency of two or more umet optional dependencies, where no other package in the tree also depends on that shared package, does not need to be installed.

This removes packages currently marked as extraneous from trees where one or more failed-optional (platform-specific) packages share a transitive dependency, with @emnapi/runtime being a good example of this.

Before:

$ node /path/to/cli/bin/npm-cli.js install sharp@0.35.0-rc.2
added 9 packages in 325ms

$ npm ls --all
├─┬ @emnapi/runtime@1.9.2 extraneous
│ └── tslib@2.8.1 deduped
├─┬ @img/sharp-wasm32@0.35.0-rc.2 extraneous
│ └── @emnapi/runtime@1.9.2 deduped
├─┬ sharp@0.35.0-rc.2
│ ├── @img/colour@1.1.0
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-darwin-arm64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-darwin-x64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-freebsd-wasm32@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-darwin-arm64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-darwin-x64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-arm@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-arm64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-ppc64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-riscv64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-s390x@1.3.0-rc.4
│ ├── @img/sharp-libvips-linux-x64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linuxmusl-arm64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linuxmusl-x64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-arm@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-arm64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-ppc64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-riscv64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-s390x@0.35.0-rc.2
│ ├─┬ @img/sharp-linux-x64@0.35.0-rc.2
│ │ └── @img/sharp-libvips-linux-x64@1.3.0-rc.4 deduped
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linuxmusl-arm64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linuxmusl-x64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-webcontainers-wasm32@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-win32-arm64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-win32-ia32@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-win32-x64@0.35.0-rc.2
│ ├── detect-libc@2.1.2
│ └── semver@7.7.4
└── tslib@2.8.1 extraneous

$ du -s node_modules/
28824	node_modules/

After:

$ node /path/to/cli/bin/npm-cli.js install sharp@0.35.0-rc.2
added 6 packages in 1s

$ npm ls --all
└─┬ sharp@0.35.0-rc.2
  ├── @img/colour@1.1.0
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-darwin-arm64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-darwin-x64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-freebsd-wasm32@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-darwin-arm64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-darwin-x64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-arm@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-arm64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-ppc64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-riscv64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-s390x@1.3.0-rc.4
  ├── @img/sharp-libvips-linux-x64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linuxmusl-arm64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linuxmusl-x64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-arm@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-arm64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-ppc64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-riscv64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-s390x@0.35.0-rc.2
  ├─┬ @img/sharp-linux-x64@0.35.0-rc.2
  │ └── @img/sharp-libvips-linux-x64@1.3.0-rc.4 deduped
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linuxmusl-arm64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linuxmusl-x64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-webcontainers-wasm32@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-win32-arm64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-win32-ia32@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-win32-x64@0.35.0-rc.2
  ├── detect-libc@2.1.2
  └── semver@7.7.4

$ du -s node_modules/
18336	node_modules/

References

Fixes #8832

A shared dependency of two or more umet optional dependencies,
where no other package in the tree also depends on that shared
package, does not need to be installed.

This removes packages currently marked as extraneous from trees
where some platform-specific packages share a dependency.
@wraithgar
Copy link
Copy Markdown
Member

The big "breaking change" to make sure we are aware of here is that the package lock is not altered in these cases. The package-lock still needs these listed, even if they are not reified.

I don't think this introduces that breaking change but it is something we want to check for.

@lovell
Copy link
Copy Markdown
Contributor Author

lovell commented Apr 14, 2026

Thank you for looking at this Gar.

The package-lock still needs these listed, even if they are not reified.

The lockfiles generated when installing sharp@0.35.0-rc.2 in an empty directory appear to be identical before and after the change in this PR.

$ sha256sum package-lock.json.*
36ec3b310f608214cf23aeecbec71f58d0cac4720b2fe4650aa1f8acca000b85  package-lock.json.after
36ec3b310f608214cf23aeecbec71f58d0cac4720b2fe4650aa1f8acca000b85  package-lock.json.before

@wraithgar wraithgar merged commit 1d058b0 into npm:latest Apr 15, 2026
44 of 48 checks passed
github-actions bot pushed a commit that referenced this pull request Apr 15, 2026
…encies (#9221)

A shared dependency of two or more umet optional dependencies, where no
other package in the tree also depends on that shared package, does not
need to be installed.

This removes packages currently marked as extraneous from trees where
one or more failed-optional (platform-specific) packages share a
transitive dependency, with `@emnapi/runtime` being a good example of
this.

Before:
```
$ node /path/to/cli/bin/npm-cli.js install sharp@0.35.0-rc.2
added 9 packages in 325ms

$ npm ls --all
├─┬ @emnapi/runtime@1.9.2 extraneous
│ └── tslib@2.8.1 deduped
├─┬ @img/sharp-wasm32@0.35.0-rc.2 extraneous
│ └── @emnapi/runtime@1.9.2 deduped
├─┬ sharp@0.35.0-rc.2
│ ├── @img/colour@1.1.0
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-darwin-arm64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-darwin-x64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-freebsd-wasm32@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-darwin-arm64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-darwin-x64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-arm@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-arm64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-ppc64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-riscv64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-s390x@1.3.0-rc.4
│ ├── @img/sharp-libvips-linux-x64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linuxmusl-arm64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linuxmusl-x64@1.3.0-rc.4
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-arm@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-arm64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-ppc64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-riscv64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-s390x@0.35.0-rc.2
│ ├─┬ @img/sharp-linux-x64@0.35.0-rc.2
│ │ └── @img/sharp-libvips-linux-x64@1.3.0-rc.4 deduped
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linuxmusl-arm64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linuxmusl-x64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-webcontainers-wasm32@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-win32-arm64@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-win32-ia32@0.35.0-rc.2
│ ├── UNMET OPTIONAL DEPENDENCY @img/sharp-win32-x64@0.35.0-rc.2
│ ├── detect-libc@2.1.2
│ └── semver@7.7.4
└── tslib@2.8.1 extraneous

$ du -s node_modules/
28824	node_modules/
```

After:
```
$ node /path/to/cli/bin/npm-cli.js install sharp@0.35.0-rc.2
added 6 packages in 1s

$ npm ls --all
└─┬ sharp@0.35.0-rc.2
  ├── @img/colour@1.1.0
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-darwin-arm64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-darwin-x64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-freebsd-wasm32@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-darwin-arm64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-darwin-x64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-arm@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-arm64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-ppc64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-riscv64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linux-s390x@1.3.0-rc.4
  ├── @img/sharp-libvips-linux-x64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linuxmusl-arm64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-libvips-linuxmusl-x64@1.3.0-rc.4
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-arm@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-arm64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-ppc64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-riscv64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linux-s390x@0.35.0-rc.2
  ├─┬ @img/sharp-linux-x64@0.35.0-rc.2
  │ └── @img/sharp-libvips-linux-x64@1.3.0-rc.4 deduped
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linuxmusl-arm64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-linuxmusl-x64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-webcontainers-wasm32@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-win32-arm64@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-win32-ia32@0.35.0-rc.2
  ├── UNMET OPTIONAL DEPENDENCY @img/sharp-win32-x64@0.35.0-rc.2
  ├── detect-libc@2.1.2
  └── semver@7.7.4

$ du -s node_modules/
18336	node_modules/
```

## References

Fixes #8832

(cherry picked from commit 1d058b0)
@github-actions
Copy link
Copy Markdown
Contributor

⚠️ Backport to release/v11 failed.

This usually means the cherry-pick had conflicts. Please create a manual backport:

git fetch origin release/v11
git checkout -b backport/v11/9221 origin/release/v11
git cherry-pick -x 1d058b0cc7161fa728cba2020a265a81e0ec7cdf
# resolve any conflicts, then:
git push origin backport/v11/9221
Error details
Resource not accessible by integration

wraithgar pushed a commit that referenced this pull request Apr 15, 2026
…encies (#9238)

Backport of #9221 to `release/v11`.

Co-authored-by: Lovell Fuller <lovell@users.noreply.github.com>
@lovell lovell deleted the arborist-optional-set-remove-shared-extraneous branch April 16, 2026 10:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] npm ls command listing EXTRANEOUS package for clean install

2 participants