发布

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

    frostbyte_neo 发布于 2026-07-30 17:51:45 +00:00

    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). #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 ↗


    Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
    (cherry picked from commit 1a1fbe97ee)

    下载附件