Skip to content

fix(core): keep real dependencies when omitting peers from npm temp installs - #36518

Merged
FrozenPandaz merged 2 commits into
masterfrom
fix/core-legacy-peer-deps-temp-install
Jul 30, 2026
Merged

fix(core): keep real dependencies when omitting peers from npm temp installs#36518
FrozenPandaz merged 2 commits into
masterfrom
fix/core-legacy-peer-deps-temp-install

Conversation

@FrozenPandaz

Copy link
Copy Markdown
Contributor

Current Behavior

ensurePackage installs on-demand plugins into a temp dir. Since #36295 that install passes --omit=peer for npm, so peers resolve from the workspace instead of being duplicated into the temp dir.

npm flags a package as a peer if anything in the tree peer-depends on it — a real dependencies edge does not clear the flag. --omit=peer therefore also prunes packages that are genuine dependencies of the package being installed.

@nx/detox hard-depends on @nx/jest and @nx/eslint; @nx/web declares both as optional peers. So installing @nx/detox on npm silently drops both:

$ npm i -D @nx/detox@22.7.7 --omit=peer --ignore-scripts
$ ls node_modules/@nx
detox devkit js module-federation nx-darwin-arm64 react rollup vitest web workspace
# @nx/jest and @nx/eslint are missing

They are still written to package-lock.json with "peer": true, are absent from node_modules/.package-lock.json, and the install exits 0 with no warning.

Generating a React Native app with Detox then fails. Observed on 22.7.x, where ensure-dependencies.ts imports @nx/jest/src/utils/versions:

NX  Cannot find module '@nx/jest/src/utils/versions'

Require stack:
- <tmp>/node_modules/@nx/detox/src/generators/application/lib/ensure-dependencies.js

On master the same file imports @nx/jest/internal instead — a different subpath of the same pruned package, so it fails the same way.

This is not Detox-specific: 14 first-party plugins hard-depend on @nx/jest or @nx/eslint, and several deep-import @nx/eslint/src/* at runtime. Any of them fetched on demand in an npm workspace can lose a dependency it needs.

Expected Behavior

npm uses --legacy-peer-deps instead. That ignores peerDependencies — the intent of #36295 — without pruning real dependencies:

$ npm i -D @nx/detox@22.7.7 --legacy-peer-deps --ignore-scripts
$ ls node_modules/@nx
detox devkit eslint jest js module-federation nx-darwin-arm64 react rollup vite vitest web workspace

bun does not over-prune (verified against the same tree), so bun keeps --omit=peer. pnpm and yarn are unchanged.

Related Issue(s)

N/A — regression from #36295, which has not been released yet.

Notes for reviewers

CI will not exercise this change. Two independent reasons:

  1. The macOS Detox e2e only runs when the diff touches packages/detox, packages/react-native, packages/expo, or their e2e projects (scripts/check-react-native-changes.js). fix(core): omit peer dependencies when installing packages to a temp dir #36295 touched only packages/nx, so the gate skipped it — and it skips this PR too.
  2. Even when that job does run, master's e2e uses a shared base workspace that preinstalls the plugins (<e2e>/nx/proj-backup/npm/node_modules/@nx/ contains detox, jest, eslint, react-native). So ensurePackage short-circuits on require('@nx/detox') and the temp-install path never executes at all.

Verified locally instead. The end-to-end run was done on 22.7.x, which has no shared base workspace and so genuinely fetches @nx/detox on demand — same branch, same e2e, only the flag differing:

temp dir node_modules/@nx/ contents result
--omit=peer detox devkit js module-federation nx-darwin-arm64 react rollup vitest web workspace 4 tests failed
--legacy-peer-deps detox devkit eslint jest js module-federation nx-darwin-arm64 react rollup vite vitest web workspace 4 tests passed

ensurePackage never calls cleanup(), so these temp dirs survive and are the reliable signal — Fetching ... log lines are absent from passing runs either way because runCLI swallows child stdout on success.

Also run:

  • nx run e2e-detox:e2e-macos-local on 22.7.x with this change — 2 suites / 4 tests pass
  • nx test nx --testPathPatterns=src/utils/package-json.spec.ts — passes
  • tsc -p packages/nx/tsconfig.lib.json --noEmit — clean
  • nx prepush — passes
  • the two npm i runs above, against published 22.7.7

Needs backporting to 22.7.x, which carries the same flag via 74311e713d and is the active patch line. Neither line has released --omit=peer yet (nx@22.7.7 still ships the old flag-less install command), so there is no user impact today.


Polygraph View session ↗

…nstalls

npm marks a package as a peer if anything in the tree peer-depends on it,
so `--omit=peer` also prunes packages that are genuine dependencies of the
package being installed. `ensurePackage` fetches plugins into a temp dir,
so an on-demand plugin lost deps it needs at runtime.

Use `--legacy-peer-deps` for npm instead: peers are still not installed,
but real dependencies are. Bun does not have this behavior, so it keeps
`--omit=peer`.
@netlify

netlify Bot commented Jul 30, 2026

Copy link
Copy Markdown

Deploy Preview for nx-docs ready!

Name Link
🔨 Latest commit 7fbc1cc
🔍 Latest deploy log https://app.netlify.com/projects/nx-docs/deploys/6a6acc457d298e000782cab9
😎 Deploy Preview https://deploy-preview-36518--nx-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Jul 30, 2026

Copy link
Copy Markdown

Deploy Preview for nx-dev ready!

Name Link
🔨 Latest commit 7fbc1cc
🔍 Latest deploy log https://app.netlify.com/projects/nx-dev/deploys/6a6acc45d45ef900085f3d15
😎 Deploy Preview https://deploy-preview-36518--nx-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@nx-cloud

nx-cloud Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 8fcd3f3

Command Status Duration Result
nx affected --targets=lint,test,build,e2e,e2e-c... ✅ Succeeded 10m 20s View ↗
nx run-many -t check-imports check-lock-files c... ✅ Succeeded 4s View ↗
nx-cloud record -- pnpm nx-cloud conformance:check ✅ Succeeded 46s View ↗
nx build workspace-plugin ✅ Succeeded <1s View ↗
nx-cloud record -- nx sync:check ✅ Succeeded 15s View ↗
nx-cloud record -- nx format:check ✅ Succeeded 4s View ↗

☁️ Nx Cloud last updated this comment at 2026-07-30 04:14:34 UTC

@polygraph-app
polygraph-app Bot marked this pull request as ready for review July 30, 2026 02:52
@polygraph-app
polygraph-app Bot requested a review from a team as a code owner July 30, 2026 02:52
@polygraph-app
polygraph-app Bot requested a review from AgentEnder July 30, 2026 02:52

@nx-cloud nx-cloud Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nx Cloud has identified a flaky task in your failed CI:

🔂 Since the failure was identified as flaky, we triggered a CI rerun by adding an empty commit to this branch.

Nx Cloud View detailed reasoning in Nx Cloud ↗

🔔 Heads up, your workspace has pending recommendations ↗ to auto-apply fixes for similar failures.


🎓 Learn more about Self-Healing CI on nx.dev

@FrozenPandaz
FrozenPandaz merged commit 1a1fbe9 into master Jul 30, 2026
18 checks passed
@FrozenPandaz
FrozenPandaz deleted the fix/core-legacy-peer-deps-temp-install branch July 30, 2026 14:57
FrozenPandaz added a commit that referenced this pull request Jul 30, 2026
…nstalls (#36518)

## Current Behavior

`ensurePackage` installs on-demand plugins into a temp dir. Since #36295
that install passes `--omit=peer` for npm, so peers resolve from the
workspace instead of being duplicated into the temp dir.

npm flags a package as a peer if **anything** in the tree peer-depends
on it — a real `dependencies` edge does not clear the flag.
`--omit=peer` therefore also prunes packages that are genuine
dependencies of the package being installed.

`@nx/detox` hard-depends on `@nx/jest` and `@nx/eslint`; `@nx/web`
declares both as optional peers. So installing `@nx/detox` on npm
silently drops both:

```console
$ npm i -D @nx/detox@22.7.7 --omit=peer --ignore-scripts
$ ls node_modules/@nx
detox devkit js module-federation nx-darwin-arm64 react rollup vitest web workspace
# @nx/jest and @nx/eslint are missing
```

They are still written to `package-lock.json` with `"peer": true`, are
absent from `node_modules/.package-lock.json`, and the install exits 0
with no warning.

Generating a React Native app with Detox then fails. Observed on 22.7.x,
where `ensure-dependencies.ts` imports `@nx/jest/src/utils/versions`:

```
NX  Cannot find module '@nx/jest/src/utils/versions'

Require stack:
- <tmp>/node_modules/@nx/detox/src/generators/application/lib/ensure-dependencies.js
```

On master the same file imports `@nx/jest/internal` instead — a
different subpath of the same pruned package, so it fails the same way.

This is not Detox-specific: 14 first-party plugins hard-depend on
`@nx/jest` or `@nx/eslint`, and several deep-import `@nx/eslint/src/*`
at runtime. Any of them fetched on demand in an npm workspace can lose a
dependency it needs.

## Expected Behavior

npm uses `--legacy-peer-deps` instead. That ignores `peerDependencies` —
the intent of #36295 — without pruning real dependencies:

```console
$ npm i -D @nx/detox@22.7.7 --legacy-peer-deps --ignore-scripts
$ ls node_modules/@nx
detox devkit eslint jest js module-federation nx-darwin-arm64 react rollup vite vitest web workspace
```

bun does not over-prune (verified against the same tree), so bun keeps
`--omit=peer`. pnpm and yarn are unchanged.

## Related Issue(s)

N/A — regression from #36295, which has not been released yet.

## Notes for reviewers

**CI will not exercise this change.** Two independent reasons:

1. The macOS Detox e2e only runs when the diff touches `packages/detox`,
`packages/react-native`, `packages/expo`, or their e2e projects
(`scripts/check-react-native-changes.js`). #36295 touched only
`packages/nx`, so the gate skipped it — and it skips this PR too.
2. Even when that job does run, master's e2e uses a shared base
workspace that preinstalls the plugins
(`<e2e>/nx/proj-backup/npm/node_modules/@nx/` contains detox, jest,
eslint, react-native). So `ensurePackage` short-circuits on
`require('@nx/detox')` and the temp-install path never executes at all.

Verified locally instead. The end-to-end run was done on **22.7.x**,
which has no shared base workspace and so genuinely fetches `@nx/detox`
on demand — same branch, same e2e, only the flag differing:

| temp dir | `node_modules/@nx/` contents | result |
| --- | --- | --- |
| `--omit=peer` | detox devkit js module-federation nx-darwin-arm64
react rollup vitest web workspace | 4 tests failed |
| `--legacy-peer-deps` | detox devkit **eslint jest** js
module-federation nx-darwin-arm64 react rollup vite vitest web workspace
| 4 tests passed |

`ensurePackage` never calls `cleanup()`, so these temp dirs survive and
are the reliable signal — `Fetching ...` log lines are absent from
passing runs either way because `runCLI` swallows child stdout on
success.

Also run:

- `nx run e2e-detox:e2e-macos-local` on 22.7.x with this change — 2
suites / 4 tests pass
- `nx test nx --testPathPatterns=src/utils/package-json.spec.ts` —
passes
- `tsc -p packages/nx/tsconfig.lib.json --noEmit` — clean
- `nx prepush` — passes
- the two `npm i` runs above, against published 22.7.7

**Needs backporting to 22.7.x**, which carries the same flag via
`74311e713d` and is the active patch line. Neither line has released
`--omit=peer` yet (`nx@22.7.7` still ships the old flag-less install
command), so there is no user impact today.

<!-- polygraph-session-start -->
---
<p><picture><source media="(prefers-color-scheme: dark)"
srcset="https://static.ops.cloud.nx.app/polygraph/session-logo-v4-dark.svg"><img
src="https://static.ops.cloud.nx.app/polygraph/session-logo-v4-light.svg"
width="16" height="22" align="middle" alt="Polygraph"></picture> <a
href="https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/Fix-npm-temp-install-pruning-real-dependencies-via---omitpeer-f7aff304">View
session ↗</a></p>
<!-- polygraph-session-end -->

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
(cherry picked from commit 1a1fbe9)
polygraph-snapshot-app Bot pushed a commit that referenced this pull request Aug 11, 2026
…nstalls (#36518)

## Current Behavior

`ensurePackage` installs on-demand plugins into a temp dir. Since #36295
that install passes `--omit=peer` for npm, so peers resolve from the
workspace instead of being duplicated into the temp dir.

npm flags a package as a peer if **anything** in the tree peer-depends
on it — a real `dependencies` edge does not clear the flag.
`--omit=peer` therefore also prunes packages that are genuine
dependencies of the package being installed.

`@nx/detox` hard-depends on `@nx/jest` and `@nx/eslint`; `@nx/web`
declares both as optional peers. So installing `@nx/detox` on npm
silently drops both:

```console
$ npm i -D @nx/detox@22.7.7 --omit=peer --ignore-scripts
$ ls node_modules/@nx
detox devkit js module-federation nx-darwin-arm64 react rollup vitest web workspace
# @nx/jest and @nx/eslint are missing
```

They are still written to `package-lock.json` with `"peer": true`, are
absent from `node_modules/.package-lock.json`, and the install exits 0
with no warning.

Generating a React Native app with Detox then fails. Observed on 22.7.x,
where `ensure-dependencies.ts` imports `@nx/jest/src/utils/versions`:

```
NX  Cannot find module '@nx/jest/src/utils/versions'

Require stack:
- <tmp>/node_modules/@nx/detox/src/generators/application/lib/ensure-dependencies.js
```

On master the same file imports `@nx/jest/internal` instead — a
different subpath of the same pruned package, so it fails the same way.

This is not Detox-specific: 14 first-party plugins hard-depend on
`@nx/jest` or `@nx/eslint`, and several deep-import `@nx/eslint/src/*`
at runtime. Any of them fetched on demand in an npm workspace can lose a
dependency it needs.

## Expected Behavior

npm uses `--legacy-peer-deps` instead. That ignores `peerDependencies` —
the intent of #36295 — without pruning real dependencies:

```console
$ npm i -D @nx/detox@22.7.7 --legacy-peer-deps --ignore-scripts
$ ls node_modules/@nx
detox devkit eslint jest js module-federation nx-darwin-arm64 react rollup vite vitest web workspace
```

bun does not over-prune (verified against the same tree), so bun keeps
`--omit=peer`. pnpm and yarn are unchanged.

## Related Issue(s)

N/A — regression from #36295, which has not been released yet.

## Notes for reviewers

**CI will not exercise this change.** Two independent reasons:

1. The macOS Detox e2e only runs when the diff touches `packages/detox`,
`packages/react-native`, `packages/expo`, or their e2e projects
(`scripts/check-react-native-changes.js`). #36295 touched only
`packages/nx`, so the gate skipped it — and it skips this PR too.
2. Even when that job does run, master's e2e uses a shared base
workspace that preinstalls the plugins
(`<e2e>/nx/proj-backup/npm/node_modules/@nx/` contains detox, jest,
eslint, react-native). So `ensurePackage` short-circuits on
`require('@nx/detox')` and the temp-install path never executes at all.

Verified locally instead. The end-to-end run was done on **22.7.x**,
which has no shared base workspace and so genuinely fetches `@nx/detox`
on demand — same branch, same e2e, only the flag differing:

| temp dir | `node_modules/@nx/` contents | result |
| --- | --- | --- |
| `--omit=peer` | detox devkit js module-federation nx-darwin-arm64
react rollup vitest web workspace | 4 tests failed |
| `--legacy-peer-deps` | detox devkit **eslint jest** js
module-federation nx-darwin-arm64 react rollup vite vitest web workspace
| 4 tests passed |

`ensurePackage` never calls `cleanup()`, so these temp dirs survive and
are the reliable signal — `Fetching ...` log lines are absent from
passing runs either way because `runCLI` swallows child stdout on
success.

Also run:

- `nx run e2e-detox:e2e-macos-local` on 22.7.x with this change — 2
suites / 4 tests pass
- `nx test nx --testPathPatterns=src/utils/package-json.spec.ts` —
passes
- `tsc -p packages/nx/tsconfig.lib.json --noEmit` — clean
- `nx prepush` — passes
- the two `npm i` runs above, against published 22.7.7

**Needs backporting to 22.7.x**, which carries the same flag via
`74311e713d` and is the active patch line. Neither line has released
`--omit=peer` yet (`nx@22.7.7` still ships the old flag-less install
command), so there is no user impact today.

<!-- polygraph-session-start -->
---
<p><picture><source media="(prefers-color-scheme: dark)"
srcset="https://static.ops.cloud.nx.app/polygraph/session-logo-v4-dark.svg"><img
src="https://static.ops.cloud.nx.app/polygraph/session-logo-v4-light.svg"
width="16" height="22" align="middle" alt="Polygraph"></picture> <a
href="https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/Fix-npm-temp-install-pruning-real-dependencies-via---omitpeer-f7aff304">View
session ↗</a></p>
<!-- polygraph-session-end -->

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
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.

2 participants