Skip to content

Commit fc20e69

Browse files
authored
fix(core): update ensurePackage util with workaround for bad module cache (#14786)
1 parent 03e04e7 commit fc20e69

File tree

2 files changed

+47
-12
lines changed

2 files changed

+47
-12
lines changed

packages/devkit/src/utils/package-json.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,16 @@ describe('ensurePackage', () => {
456456
tree = createTree();
457457
});
458458

459+
it('should return successfully when package is present', async () => {
460+
writeJson(tree, 'package.json', {});
461+
462+
await expect(
463+
ensurePackage(tree, '@nrwl/devkit', '>=15.0.0', {
464+
throwOnMissing: true,
465+
})
466+
).resolves.toBeUndefined(); // return void
467+
});
468+
459469
it('should throw when dependencies are missing', async () => {
460470
writeJson(tree, 'package.json', {});
461471

packages/devkit/src/utils/package-json.ts

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
import { execSync } from 'child_process';
12
import { readJson, updateJson } from 'nx/src/generators/utils/json';
2-
import { installPackagesTask } from '../tasks/install-packages-task';
33
import type { Tree } from 'nx/src/generators/tree';
44
import { GeneratorCallback } from 'nx/src/config/misc-interfaces';
55
import { clean, coerce, gt, satisfies } from 'semver';
66
import { getPackageManagerCommand } from 'nx/src/utils/package-manager';
7-
import { execSync } from 'child_process';
8-
import { readModulePackageJson } from 'nx/src/utils/package-json';
7+
import { workspaceRoot } from 'nx/src/utils/workspace-root';
8+
9+
import { installPackagesTask } from '../tasks/install-packages-task';
910

1011
const UNIDENTIFIED_VERSION = 'UNIDENTIFIED_VERSION';
1112
const NON_SEMVER_TAGS = {
@@ -389,19 +390,12 @@ export async function ensurePackage(
389390
throwOnMissing?: boolean;
390391
} = {}
391392
): Promise<void> {
392-
let version: string;
393-
394393
// Read package and version from root package.json file.
395394
const dev = options.dev ?? true;
396395
const throwOnMissing = options.throwOnMissing ?? !!process.env.NX_DRY_RUN; // NX_DRY_RUN is set in `packages/nx/src/command-line/generate.ts`
397396
const pmc = getPackageManagerCommand();
398397

399-
// Try to resolve the actual version from resolved module.
400-
try {
401-
version = readModulePackageJson(pkg).packageJson.version;
402-
} catch {
403-
// ignore
404-
}
398+
let version = getPackageVersion(pkg);
405399

406400
// Otherwise try to read in from package.json. This is needed for E2E tests to pass.
407401
if (!version) {
@@ -410,7 +404,15 @@ export async function ensurePackage(
410404
version = packageJson[field]?.[pkg];
411405
}
412406

413-
if (!satisfies(version, requiredVersion)) {
407+
if (
408+
// Special case: When running Nx unit tests, the version read from package.json is "0.0.1".
409+
!(
410+
pkg.startsWith('@nrwl/') &&
411+
(version === '0.0.1' || requiredVersion === '0.0.1')
412+
) &&
413+
// Normal case
414+
!satisfies(version, requiredVersion, { includePrerelease: true })
415+
) {
414416
const installCmd = `${
415417
dev ? pmc.addDev : pmc.add
416418
} ${pkg}@${requiredVersion}`;
@@ -426,3 +428,26 @@ export async function ensurePackage(
426428
}
427429
}
428430
}
431+
432+
/**
433+
* Use another process to resolve the package.json path of the package (if it exists).
434+
* Cannot use `require.resolve` here since there is an unclearable internal cache used by Node that can lead to issues
435+
* when resolving the package after installation.
436+
*
437+
* See: https://github.com/nodejs/node/issues/31803
438+
*/
439+
function getPackageVersion(pkg: string): undefined | string {
440+
try {
441+
return execSync(
442+
`node -e "console.log(require('${pkg}/package.json').version)"`,
443+
{
444+
cwd: workspaceRoot,
445+
stdio: ['pipe', 'pipe', 'ignore'],
446+
}
447+
)
448+
.toString()
449+
.trim();
450+
} catch (e) {
451+
return undefined;
452+
}
453+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy