Skip to content

Commit 0a38129

Browse files
authored
fix(core): resolve published nx migrate package resolution (#35013)
## Current Behavior When `nx migrate latest` runs, it installs the target version of `nx` into a temporary directory and executes that published CLI. During migration, Nx checks whether `nx` is already installed in the workspace by resolving `nx/package.json`. This used to resolve through the workspace-oriented lookup paths, so migrate correctly detected the workspace-installed `nx` package and expanded the first-party Nx package group. That changed recently with `chore(core): build nx to local dist and use nodenext (#34111)`. As part of that work, the published `nx` package gained an `exports` map. In Node, a package with `name: "nx"` and `exports` can self-reference by package name. As a result, when code running inside the temporary published `nx` package resolves `nx/package.json`, Node now resolves that request back to the temporary package itself. The resolved path points outside the workspace root, so migrate's existing safety check treats `nx` as not installed in the workspace. Once that happens, migrate only updates `nx` and never expands the rest of the first-party Nx package group. Separately, provenance package-group lookup assumes a source-layout-relative path to `package.json`, which does not hold for published artifacts built into local `dist/`. ## Expected Behavior Published temporary migrate CLIs should still resolve the workspace-installed `nx` package when migrate determines what is installed in the workspace. That preserves the existing package-group migration behavior even after the recent `exports`-based packaging change. Provenance package-group lookup should resolve the manifest of the currently running `nx` package in a way that works for published artifacts as well as source checkouts.
1 parent 55f8888 commit 0a38129

2 files changed

Lines changed: 33 additions & 13 deletions

File tree

packages/nx/src/command-line/migrate/migrate.ts

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { exec, execSync, type StdioOptions } from 'child_process';
33
import { prompt } from 'enquirer';
44
import { handleImport } from '../../utils/handle-import';
55
import { dirname, join } from 'path';
6+
import { createRequire } from 'module';
67
import { joinPathFragments } from '../../utils/path';
78
import {
89
clean,
@@ -898,20 +899,46 @@ function createInstalledPackageVersionsResolver(
898899
root: string
899900
): MigratorOptions['getInstalledPackageVersion'] {
900901
const cache: Record<string, string> = {};
902+
const nxRequires = getNxRequirePaths(root).map((path) =>
903+
createRequire(join(path, 'package.json'))
904+
);
901905

902906
function getInstalledPackageVersion(
903907
packageName: string,
904908
overrides?: Record<string, string>
905909
): string | null {
906-
try {
907-
if (overrides?.[packageName]) {
908-
return overrides[packageName];
910+
if (overrides?.[packageName]) {
911+
return overrides[packageName];
912+
}
913+
914+
if (packageName === 'nx') {
915+
const nxVersion =
916+
cache[packageName] ??
917+
(() => {
918+
for (const req of nxRequires) {
919+
try {
920+
const packageJsonPath = req.resolve('nx/package.json');
921+
if (packageJsonPath.startsWith(workspaceRoot)) {
922+
return readJsonFile<PackageJson>(packageJsonPath).version;
923+
}
924+
} catch {}
925+
}
926+
927+
return getInstalledPackageVersion('@nrwl/workspace', overrides);
928+
})();
929+
930+
if (nxVersion) {
931+
cache[packageName] = nxVersion;
909932
}
910933

934+
return nxVersion;
935+
}
936+
937+
try {
911938
if (!cache[packageName]) {
912939
const { packageJson, path } = readModulePackageJson(
913940
packageName,
914-
getNxRequirePaths()
941+
getNxRequirePaths(root)
915942
);
916943
// old workspaces would have the temp installation of nx in the cache,
917944
// so the resolved package is not the one we need
@@ -923,14 +950,6 @@ function createInstalledPackageVersionsResolver(
923950

924951
return cache[packageName];
925952
} catch {
926-
// Support migrating old workspaces without nx package
927-
if (packageName === 'nx') {
928-
cache[packageName] = getInstalledPackageVersion(
929-
'@nrwl/workspace',
930-
overrides
931-
);
932-
return cache[packageName];
933-
}
934953
return null;
935954
}
936955
}

packages/nx/src/utils/provenance.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { execSync } from 'child_process';
2+
import { createRequire } from 'module';
23
import { join } from 'path';
34
import { promisify } from 'util';
45
import { readJsonFile } from './fileutils';
@@ -168,7 +169,7 @@ export class ProvenanceError extends Error {
168169
}
169170

170171
export function getNxPackageGroup(): string[] {
171-
const packageJsonPath = join(__dirname, '../../package.json');
172+
const packageJsonPath = createRequire(__filename).resolve('nx/package.json');
172173
const packageJson = readJsonFile(packageJsonPath);
173174

174175
if (!packageJson['nx-migrations']?.packageGroup) {

0 commit comments

Comments
 (0)