Skip to content

Commit c0694ca

Browse files
clydinalan-agius4
authored andcommitted
fix(@angular/cli): clean node modules directory prior to updating
Prior to performing the initial updated package installation during the `ng update` process, the workspace node modules directory will be removed. This cleaning increases the guarantees that the package manager will hoist packages into the correct locations and avoid peer dependency inconsistencies. (cherry picked from commit 6926b37)
1 parent 4ac556b commit c0694ca

File tree

3 files changed

+68
-4
lines changed

3 files changed

+68
-4
lines changed

packages/angular/cli/commands/update-impl.ts

+21-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { Command } from '../models/command';
1717
import { Arguments } from '../models/interface';
1818
import { SchematicEngineHost } from '../models/schematic-engine-host';
1919
import { colors } from '../utilities/color';
20-
import { runTempPackageBin } from '../utilities/install-package';
20+
import { installAllPackages, runTempPackageBin } from '../utilities/install-package';
2121
import { writeErrorToLogFile } from '../utilities/log-file';
2222
import { ensureCompatibleNpm, getPackageManager } from '../utilities/package-manager';
2323
import {
@@ -655,6 +655,26 @@ export class UpdateCommand extends Command<UpdateCommandSchema> {
655655
packages: packagesToUpdate,
656656
});
657657

658+
if (success) {
659+
try {
660+
// Remove existing node modules directory to provide a stronger guarantee that packages
661+
// will be hoisted into the correct locations.
662+
await fs.promises.rmdir(path.join(this.context.root, 'node_modules'), {
663+
recursive: true,
664+
maxRetries: 3,
665+
});
666+
} catch {}
667+
668+
const result = await installAllPackages(
669+
this.packageManager,
670+
options.force ? ['--force'] : [],
671+
this.context.root,
672+
);
673+
if (result !== 0) {
674+
return result;
675+
}
676+
}
677+
658678
if (success && options.createCommits) {
659679
const committed = this.commit(
660680
`Angular CLI update for packages - ${packagesToUpdate.join(', ')}`,

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

-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import { logging, tags } from '@angular-devkit/core';
1010
import { Rule, SchematicContext, SchematicsException, Tree } from '@angular-devkit/schematics';
11-
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
1211
import * as npa from 'npm-package-arg';
1312
import * as semver from 'semver';
1413
import { getNpmPackageJson } from './npm';
@@ -310,9 +309,7 @@ function _performUpdate(
310309
const newContent = JSON.stringify(packageJson, null, 2);
311310
if (packageJsonContent.toString() != newContent || migrateOnly) {
312311
if (!migrateOnly) {
313-
// If something changed, also hook up the task.
314312
tree.overwrite('/package.json', JSON.stringify(packageJson, null, 2));
315-
context.addTask(new NodePackageInstallTask());
316313
}
317314

318315
const externalMigrations: {}[] = [];

packages/angular/cli/utilities/install-package.ts

+47
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,55 @@ interface PackageManagerOptions {
1919
silent: string;
2020
saveDev: string;
2121
install: string;
22+
installAll?: string;
2223
prefix: string;
2324
noLockfile: string;
2425
}
2526

27+
export async function installAllPackages(
28+
packageManager: PackageManager = PackageManager.Npm,
29+
extraArgs: string[] = [],
30+
cwd = process.cwd(),
31+
): Promise<1 | 0> {
32+
const packageManagerArgs = getPackageManagerArguments(packageManager);
33+
34+
const installArgs: string[] = [];
35+
if (packageManagerArgs.installAll) {
36+
installArgs.push(packageManagerArgs.installAll);
37+
}
38+
installArgs.push(packageManagerArgs.silent);
39+
40+
const spinner = new Spinner();
41+
spinner.start('Installing packages...');
42+
43+
const bufferedOutput: { stream: NodeJS.WriteStream; data: Buffer }[] = [];
44+
45+
return new Promise((resolve, reject) => {
46+
const childProcess = spawn(packageManager, [...installArgs, ...extraArgs], {
47+
stdio: 'pipe',
48+
shell: true,
49+
cwd,
50+
}).on('close', (code: number) => {
51+
if (code === 0) {
52+
spinner.succeed('Packages successfully installed.');
53+
resolve(0);
54+
} else {
55+
spinner.stop();
56+
bufferedOutput.forEach(({ stream, data }) => stream.write(data));
57+
spinner.fail('Package install failed, see above.');
58+
reject(1);
59+
}
60+
});
61+
62+
childProcess.stdout?.on('data', (data: Buffer) =>
63+
bufferedOutput.push({ stream: process.stdout, data: data }),
64+
);
65+
childProcess.stderr?.on('data', (data: Buffer) =>
66+
bufferedOutput.push({ stream: process.stderr, data: data }),
67+
);
68+
});
69+
}
70+
2671
export async function installPackage(
2772
packageName: string,
2873
packageManager: PackageManager = PackageManager.Npm,
@@ -193,6 +238,7 @@ function getPackageManagerArguments(packageManager: PackageManager): PackageMana
193238
silent: '--silent',
194239
saveDev: '--save-dev',
195240
install: 'add',
241+
installAll: 'install',
196242
prefix: '--prefix',
197243
noLockfile: '--no-lockfile',
198244
};
@@ -201,6 +247,7 @@ function getPackageManagerArguments(packageManager: PackageManager): PackageMana
201247
silent: '--quiet',
202248
saveDev: '--save-dev',
203249
install: 'install',
250+
installAll: 'install',
204251
prefix: '--prefix',
205252
noLockfile: '--no-package-lock',
206253
};

0 commit comments

Comments
 (0)