From fc20e693aac7d48d436def97ff9c5196e2dc0bfc Mon Sep 17 00:00:00 2001 From: Jack Hsu Date: Tue, 7 Feb 2023 15:57:02 -0500 Subject: [PATCH] fix(core): update ensurePackage util with workaround for bad module cache (#14786) --- .../devkit/src/utils/package-json.spec.ts | 10 ++++ packages/devkit/src/utils/package-json.ts | 49 ++++++++++++++----- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/packages/devkit/src/utils/package-json.spec.ts b/packages/devkit/src/utils/package-json.spec.ts index 641cd70a0f502..bf052b1a53c28 100644 --- a/packages/devkit/src/utils/package-json.spec.ts +++ b/packages/devkit/src/utils/package-json.spec.ts @@ -456,6 +456,16 @@ describe('ensurePackage', () => { tree = createTree(); }); + it('should return successfully when package is present', async () => { + writeJson(tree, 'package.json', {}); + + await expect( + ensurePackage(tree, '@nrwl/devkit', '>=15.0.0', { + throwOnMissing: true, + }) + ).resolves.toBeUndefined(); // return void + }); + it('should throw when dependencies are missing', async () => { writeJson(tree, 'package.json', {}); diff --git a/packages/devkit/src/utils/package-json.ts b/packages/devkit/src/utils/package-json.ts index fc45bf8a10cef..c2e9ef61f70e9 100644 --- a/packages/devkit/src/utils/package-json.ts +++ b/packages/devkit/src/utils/package-json.ts @@ -1,11 +1,12 @@ +import { execSync } from 'child_process'; import { readJson, updateJson } from 'nx/src/generators/utils/json'; -import { installPackagesTask } from '../tasks/install-packages-task'; import type { Tree } from 'nx/src/generators/tree'; import { GeneratorCallback } from 'nx/src/config/misc-interfaces'; import { clean, coerce, gt, satisfies } from 'semver'; import { getPackageManagerCommand } from 'nx/src/utils/package-manager'; -import { execSync } from 'child_process'; -import { readModulePackageJson } from 'nx/src/utils/package-json'; +import { workspaceRoot } from 'nx/src/utils/workspace-root'; + +import { installPackagesTask } from '../tasks/install-packages-task'; const UNIDENTIFIED_VERSION = 'UNIDENTIFIED_VERSION'; const NON_SEMVER_TAGS = { @@ -389,19 +390,12 @@ export async function ensurePackage( throwOnMissing?: boolean; } = {} ): Promise { - let version: string; - // Read package and version from root package.json file. const dev = options.dev ?? true; const throwOnMissing = options.throwOnMissing ?? !!process.env.NX_DRY_RUN; // NX_DRY_RUN is set in `packages/nx/src/command-line/generate.ts` const pmc = getPackageManagerCommand(); - // Try to resolve the actual version from resolved module. - try { - version = readModulePackageJson(pkg).packageJson.version; - } catch { - // ignore - } + let version = getPackageVersion(pkg); // Otherwise try to read in from package.json. This is needed for E2E tests to pass. if (!version) { @@ -410,7 +404,15 @@ export async function ensurePackage( version = packageJson[field]?.[pkg]; } - if (!satisfies(version, requiredVersion)) { + if ( + // Special case: When running Nx unit tests, the version read from package.json is "0.0.1". + !( + pkg.startsWith('@nrwl/') && + (version === '0.0.1' || requiredVersion === '0.0.1') + ) && + // Normal case + !satisfies(version, requiredVersion, { includePrerelease: true }) + ) { const installCmd = `${ dev ? pmc.addDev : pmc.add } ${pkg}@${requiredVersion}`; @@ -426,3 +428,26 @@ export async function ensurePackage( } } } + +/** + * Use another process to resolve the package.json path of the package (if it exists). + * Cannot use `require.resolve` here since there is an unclearable internal cache used by Node that can lead to issues + * when resolving the package after installation. + * + * See: https://github.com/nodejs/node/issues/31803 + */ +function getPackageVersion(pkg: string): undefined | string { + try { + return execSync( + `node -e "console.log(require('${pkg}/package.json').version)"`, + { + cwd: workspaceRoot, + stdio: ['pipe', 'pipe', 'ignore'], + } + ) + .toString() + .trim(); + } catch (e) { + return undefined; + } +}