发布

  • fix(core): use workspace root for package manager detection in script targets (#35550)

    frostbyte_neo 发布于 2026-05-04 20:57:17 +00:00

    Current Behavior

    readTargetsFromPackageJson (in
    packages/nx/src/utils/package-json.ts) receives a workspaceRoot
    argument but never passes it to package manager detection:

    for (const script of includedScripts) {
      packageManagerCommand ??= getPackageManagerCommand(); // ← no workspaceRoot
      res[script] = buildTargetFromScript(script, scripts, packageManagerCommand);
    }
    

    Two consequences:

    1. Wrong package managerdetectPackageManager() defaults dir = '', so the lockfile probe runs in the CWD, not the workspace. When that
      finds nothing it falls back to npm_config_user_agent, so the inferred
      runCommand (npm run X vs pnpm run X vs yarn X) on script targets
      ends up depending on whoever invoked the nx process rather than on the
      workspace's actual lockfile.

    2. Module-level cachelet packageManagerCommand (cleared with
      ??=) memoizes the first detection result across all subsequent calls
      in the process. So even if the first call had the right workspaceRoot,
      every later call inherits that detection regardless of its
      workspaceRoot. This is also why
      packages/nx/src/plugins/package-json/create-nodes.spec.ts had four
      pre-existing snapshot failures locally (pnpm run … instead of the
      expected npm run …) — the first test in any process locked detection
      to the host's PM.

    This is a follow-up to #35116, which moved package manager detection
    into the createNodes callback for the inferred plugins but missed this
    code path.

    Expected Behavior

    • Drop the module-level cache.
    • Thread workspaceRoot into both detectPackageManager and
      getPackageManagerCommand, so the lockfile probe runs in the right
      directory.
    if (includedScripts.length > 0) {
      const packageManagerCommand = getPackageManagerCommand(
        detectPackageManager(workspaceRoot),
        workspaceRoot
      );
      for (const script of includedScripts) {
        res[script] = buildTargetFromScript(script, scripts, packageManagerCommand);
      }
    }
    

    The packages/nx/src/plugins/package-json/create-nodes.spec.ts fixture
    now seeds package-lock.json into memfs in a beforeEach, matching the
    pattern #35116 established for plugin specs. Without the lockfile the
    detector still falls back to the env var; with it, every test
    deterministically picks npm, matching the existing snapshots.

    Verification

    Before this PR: 4 failures in
    packages/nx/src/plugins/package-json/create-nodes.spec.ts:

    ✕ should build projects from package.json files
    ✕ should store js package metadata
    ✕ should add a script target if the sibling project.json file does not exist
    ✕ should add a script target if the sibling project.json exists but does not have a conflicting target
    
    Tests: 4 failed, 7 passed, 11 total
    

    After this PR:

    Tests: 11 passed, 11 total
    

    Related Issue(s)

    Follow-up to #35116.

    下载附件