Skip to content

Commit 57db27e

Browse files
committed
fix(@angular/cli): add packages with built-in schematics to devDependencies only
When running `ng add` on a package that does not provide a native `ng-add` schematic but is handled by a built-in schematic (e.g. `tailwindcss` or `@vitest/browser-*`), the CLI previously installed the package into `dependencies` before executing the built-in schematic. With this change, built-in schematics specify their target dependency section (`devDependencies`), so `ng add` installs them as `devDependencies` and omits them from `dependencies`. Closes #33701 (cherry picked from commit 035b9d5)
1 parent baed978 commit 57db27e

3 files changed

Lines changed: 47 additions & 13 deletions

File tree

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

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,29 @@ export default class AddCommandModule
224224
{
225225
title: 'Confirming installation',
226226
enabled: !skipConfirmation && !options.dryRun,
227+
skip: (context) => {
228+
if (context.hasSchematics) {
229+
return false;
230+
}
231+
232+
return `The ${color.blue(context.packageIdentifier.toString())} package does not provide \`ng add\` actions.`;
233+
},
227234
task: (context, task) => this.confirmInstallationTask(context, task),
228235
rendererOptions: { persistentOutput: true },
229236
},
230237
{
231238
title: 'Installing package',
232239
skip: (context) => {
240+
if (!context.hasSchematics) {
241+
const builtInSchematic =
242+
BUILT_IN_SCHEMATICS[
243+
context.packageIdentifier.name as keyof typeof BUILT_IN_SCHEMATICS
244+
];
245+
if (builtInSchematic) {
246+
return `Skipping package installation.`;
247+
}
248+
}
249+
233250
if (context.dryRun) {
234251
return `Skipping package installation. Would install package ${color.blue(
235252
context.packageIdentifier.toString(),
@@ -243,9 +260,7 @@ export default class AddCommandModule
243260
},
244261
// TODO: Rework schematic execution as a task and insert here
245262
],
246-
{
247-
/* options */
248-
},
263+
{/* options */},
249264
);
250265

251266
try {
@@ -290,9 +305,6 @@ export default class AddCommandModule
290305
const builtInSchematic =
291306
BUILT_IN_SCHEMATICS[packageName as keyof typeof BUILT_IN_SCHEMATICS];
292307
if (builtInSchematic) {
293-
logger.info(
294-
`The ${color.blue(packageName)} package does not provide \`ng add\` actions.`,
295-
);
296308
logger.info('The Angular CLI will use built-in actions to add it to your project.');
297309

298310
return this.executeSchematic({

tests/e2e/tests/commands/add/add-tailwindcss.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { expectFileToExist, expectFileToMatch, rimraf } from '../../../utils/fs';
1+
import assert from 'node:assert';
2+
import { expectFileToExist, expectFileToMatch, readFile, rimraf } from '../../../utils/fs';
23
import { getActivePackageManager, uninstallPackage } from '../../../utils/packages';
34
import { ng } from '../../../utils/process';
45

@@ -14,9 +15,19 @@ export default async function () {
1415
await ng('add', 'tailwindcss', '--skip-confirmation');
1516
await expectFileToExist('.postcssrc.json');
1617
await expectFileToMatch('src/styles.css', /@import 'tailwindcss';/);
17-
await expectFileToMatch('package.json', /"tailwindcss":/);
18-
await expectFileToMatch('package.json', /"@tailwindcss\/postcss":/);
19-
await expectFileToMatch('package.json', /"postcss":/);
18+
19+
const { dependencies, devDependencies } = JSON.parse(await readFile('package.json'));
20+
assert.strictEqual(
21+
dependencies?.tailwindcss,
22+
undefined,
23+
'tailwindcss should not be added to dependencies.',
24+
);
25+
assert.ok(devDependencies?.tailwindcss, 'tailwindcss should be added to devDependencies.');
26+
assert.ok(
27+
devDependencies?.['@tailwindcss/postcss'],
28+
'@tailwindcss/postcss should be added to devDependencies.',
29+
);
30+
assert.ok(devDependencies?.postcss, 'postcss should be added to devDependencies.');
2031

2132
// Ensure the project builds
2233
await ng('build', '--configuration=development');

tests/e2e/tests/commands/add/add-vitest-browser.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { expectFileToMatch } from '../../../utils/fs';
1+
import assert from 'node:assert';
2+
import { expectFileToMatch, readFile } from '../../../utils/fs';
23
import { uninstallPackage } from '../../../utils/packages';
34
import { ng } from '../../../utils/process';
45
import { applyVitestBuilder } from '../../../utils/vitest';
@@ -9,8 +10,18 @@ export default async function () {
910
try {
1011
await ng('add', '@vitest/browser-playwright', '--skip-confirmation');
1112

12-
await expectFileToMatch('package.json', /"@vitest\/browser-playwright":/);
13-
await expectFileToMatch('package.json', /"playwright":/);
13+
const { dependencies, devDependencies } = JSON.parse(await readFile('package.json'));
14+
assert.strictEqual(
15+
dependencies?.['@vitest/browser-playwright'],
16+
undefined,
17+
'@vitest/browser-playwright should not be added to dependencies.',
18+
);
19+
assert.ok(
20+
devDependencies?.['@vitest/browser-playwright'],
21+
'@vitest/browser-playwright should be added to devDependencies.',
22+
);
23+
assert.ok(devDependencies?.playwright, 'playwright should be added to devDependencies.');
24+
1425
await expectFileToMatch('tsconfig.spec.json', /"vitest\/globals"/);
1526
await expectFileToMatch('tsconfig.spec.json', /"@vitest\/browser-playwright"/);
1627
} finally {

0 commit comments

Comments
 (0)