Skip to content

Commit 326e923

Browse files
committed
refactor(@angular/cli): remove use of global require resolve
The global require function is not present in Node.js ESM mode. To support the eventual transition of the `@angular/cli` package to ESM, usage of the `require.resolve` function has been converted to use locally created `require` functions via `createRequire` from the `module` builtin.
1 parent 113e2c0 commit 326e923

File tree

4 files changed

+22
-18
lines changed

4 files changed

+22
-18
lines changed

packages/angular/cli/lib/init.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import 'symbol-observable';
1010
// symbol polyfill must go first
1111
import { promises as fs } from 'fs';
12+
import { createRequire } from 'module';
1213
import * as path from 'path';
1314
import { SemVer, major } from 'semver';
1415
import { colors } from '../src/utilities/color';
@@ -47,7 +48,8 @@ let forceExit = false;
4748
try {
4849
// No error implies a projectLocalCli, which will load whatever
4950
// version of ng-cli you have installed in a local package.json
50-
const projectLocalCli = require.resolve('@angular/cli', { paths: [process.cwd()] });
51+
const cwdRequire = createRequire(process.cwd() + '/');
52+
const projectLocalCli = cwdRequire.resolve('@angular/cli');
5153
cli = await import(projectLocalCli);
5254

5355
const globalVersion = new SemVer(VERSION.full);

packages/angular/cli/src/command-builder/utilities/schematic-engine-host.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { RuleFactory, SchematicsException, Tree } from '@angular-devkit/schemati
1010
import { FileSystemCollectionDesc, NodeModulesEngineHost } from '@angular-devkit/schematics/tools';
1111
import { readFileSync } from 'fs';
1212
import { parse as parseJson } from 'jsonc-parser';
13-
import nodeModule from 'module';
13+
import { createRequire } from 'module';
1414
import { dirname, resolve } from 'path';
1515
import { Script } from 'vm';
1616
import { assertIsError } from '../../utilities/error';
@@ -63,7 +63,8 @@ export class SchematicEngineHost extends NodeModulesEngineHost {
6363
// Mimic behavior of ExportStringRef class used in default behavior
6464
const fullPath = path[0] === '.' ? resolve(parentPath ?? process.cwd(), path) : path;
6565

66-
const schematicFile = require.resolve(fullPath, { paths: [parentPath] });
66+
const referenceRequire = createRequire(__filename);
67+
const schematicFile = referenceRequire.resolve(fullPath, { paths: [parentPath] });
6768

6869
if (shouldWrapSchematic(schematicFile, !!collectionDescription?.encapsulation)) {
6970
const schematicPath = dirname(schematicFile);
@@ -128,8 +129,8 @@ function wrap(
128129
moduleCache: Map<string, unknown>,
129130
exportName?: string,
130131
): () => unknown {
131-
const hostRequire = nodeModule.createRequire(__filename);
132-
const schematicRequire = nodeModule.createRequire(schematicFile);
132+
const hostRequire = createRequire(__filename);
133+
const schematicRequire = createRequire(schematicFile);
133134

134135
const customRequire = function (id: string) {
135136
if (legacyModules[id]) {

packages/angular/cli/src/commands/add/cli.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import { analytics, tags } from '@angular-devkit/core';
1010
import { NodePackageDoesNotSupportSchematics } from '@angular-devkit/schematics/tools';
11+
import { createRequire } from 'module';
1112
import npa from 'npm-package-arg';
1213
import { dirname, join } from 'path';
1314
import { compare, intersects, prerelease, satisfies, valid } from 'semver';
@@ -61,6 +62,7 @@ export class AddCommandModule
6162
longDescriptionPath = join(__dirname, 'long-description.md');
6263
protected override allowPrivateSchematics = true;
6364
private readonly schematicName = 'ng-add';
65+
private rootRequire = createRequire(this.context.root + '/');
6466

6567
override async builder(argv: Argv): Promise<Argv<AddCommandArgs>> {
6668
const localYargs = (await super.builder(argv))
@@ -276,9 +278,8 @@ export class AddCommandModule
276278
packageIdentifier.raw,
277279
registry ? [`--registry="${registry}"`] : undefined,
278280
);
279-
const resolvedCollectionPath = require.resolve(join(collectionName, 'package.json'), {
280-
paths: [tempNodeModules],
281-
});
281+
const tempRequire = createRequire(tempNodeModules + '/');
282+
const resolvedCollectionPath = tempRequire.resolve(join(collectionName, 'package.json'));
282283

283284
if (!success) {
284285
return 1;
@@ -341,7 +342,7 @@ export class AddCommandModule
341342

342343
private isPackageInstalled(name: string): boolean {
343344
try {
344-
require.resolve(join(name, 'package.json'), { paths: [this.context.root] });
345+
this.rootRequire.resolve(join(name, 'package.json'));
345346

346347
return true;
347348
} catch (e) {
@@ -400,9 +401,7 @@ export class AddCommandModule
400401
const { logger, root } = this.context;
401402
let installedPackage;
402403
try {
403-
installedPackage = require.resolve(join(name, 'package.json'), {
404-
paths: [root],
405-
});
404+
installedPackage = this.rootRequire.resolve(join(name, 'package.json'));
406405
} catch {}
407406

408407
if (installedPackage) {

packages/angular/cli/src/commands/update/cli.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { UnsuccessfulWorkflowExecution } from '@angular-devkit/schematics';
1010
import { NodeWorkflow } from '@angular-devkit/schematics/tools';
1111
import { SpawnSyncReturns, execSync, spawnSync } from 'child_process';
1212
import { existsSync, promises as fs } from 'fs';
13+
import { createRequire } from 'module';
1314
import npa from 'npm-package-arg';
1415
import pickManifest from 'npm-pick-manifest';
1516
import * as path from 'path';
@@ -483,7 +484,8 @@ export class UpdateCommandModule extends CommandModule<UpdateCommandArgs> {
483484
// Try to resolve from package location.
484485
// This avoids issues with package hoisting.
485486
try {
486-
migrations = require.resolve(migrations, { paths: [packagePath] });
487+
const packageRequire = createRequire(packagePath + '/');
488+
migrations = packageRequire.resolve(migrations);
487489
} catch (e) {
488490
assertIsError(e);
489491
if (e.code === 'MODULE_NOT_FOUND') {
@@ -717,6 +719,7 @@ export class UpdateCommandModule extends CommandModule<UpdateCommandArgs> {
717719
}[];
718720

719721
if (success && migrations) {
722+
const rootRequire = createRequire(this.context.root + '/');
720723
for (const migration of migrations) {
721724
// Resolve the package from the workspace root, as otherwise it will be resolved from the temp
722725
// installed CLI version.
@@ -728,15 +731,13 @@ export class UpdateCommandModule extends CommandModule<UpdateCommandArgs> {
728731
try {
729732
packagePath = path.dirname(
730733
// This may fail if the `package.json` is not exported as an entry point
731-
require.resolve(path.join(migration.package, 'package.json'), {
732-
paths: [this.context.root],
733-
}),
734+
rootRequire.resolve(path.join(migration.package, 'package.json')),
734735
);
735736
} catch (e) {
736737
assertIsError(e);
737738
if (e.code === 'MODULE_NOT_FOUND') {
738739
// Fallback to trying to resolve the package's main entry point
739-
packagePath = require.resolve(migration.package, { paths: [this.context.root] });
740+
packagePath = rootRequire.resolve(migration.package);
740741
} else {
741742
throw e;
742743
}
@@ -768,7 +769,8 @@ export class UpdateCommandModule extends CommandModule<UpdateCommandArgs> {
768769
// Try to resolve from package location.
769770
// This avoids issues with package hoisting.
770771
try {
771-
migrations = require.resolve(migration.collection, { paths: [packagePath] });
772+
const packageRequire = createRequire(packagePath + '/');
773+
migrations = packageRequire.resolve(migration.collection);
772774
} catch (e) {
773775
assertIsError(e);
774776
if (e.code === 'MODULE_NOT_FOUND') {

0 commit comments

Comments
 (0)