From 1fc0c737364b57f8c80d075b841a27f288171a47 Mon Sep 17 00:00:00 2001 From: MeAkib Date: Thu, 22 Oct 2026 08:32:12 +0600 Subject: [PATCH] feat(@schematics/angular): enable npm `engine-strict` in new workspaces npm only warns when a dependency's `engines` doesn't match the installed Node.js version, while Yarn and pnpm fail. Generate an `.npmrc` with `engine-strict=true` for new workspaces that use npm, so installs with an unsupported Node.js version fail instead of printing an easy-to-miss warning. Closes #31271 --- .../workspace/files/__dot__npmrc.template | 1 + packages/schematics/angular/workspace/index.ts | 2 ++ .../schematics/angular/workspace/index_spec.ts | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 packages/schematics/angular/workspace/files/__dot__npmrc.template diff --git a/packages/schematics/angular/workspace/files/__dot__npmrc.template b/packages/schematics/angular/workspace/files/__dot__npmrc.template new file mode 100644 index 000000000000..b6f27f135954 --- /dev/null +++ b/packages/schematics/angular/workspace/files/__dot__npmrc.template @@ -0,0 +1 @@ +engine-strict=true diff --git a/packages/schematics/angular/workspace/index.ts b/packages/schematics/angular/workspace/index.ts index 85205042f3e3..75226e28e843 100644 --- a/packages/schematics/angular/workspace/index.ts +++ b/packages/schematics/angular/workspace/index.ts @@ -48,6 +48,8 @@ export default function (options: WorkspaceOptions): Rule { return mergeWith( apply(url('./files'), [ options.minimal ? filter((path) => !path.endsWith('editorconfig.template')) : noop(), + // Unlike other package managers, npm only warns about unsupported `engines` by default. + packageManager !== 'npm' ? filter((path) => !path.endsWith('npmrc.template')) : noop(), applyTemplates({ utils: strings, ...options, diff --git a/packages/schematics/angular/workspace/index_spec.ts b/packages/schematics/angular/workspace/index_spec.ts index a13a7d3e1bb7..32df370e6add 100644 --- a/packages/schematics/angular/workspace/index_spec.ts +++ b/packages/schematics/angular/workspace/index_spec.ts @@ -40,6 +40,24 @@ describe('Workspace Schematic', () => { ); }); + it('should enable npm `engine-strict` in .npmrc when using npm', async () => { + const tree = await schematicRunner.runSchematic('workspace', { + ...defaultOptions, + packageManager: 'npm', + }); + expect(tree.readContent('/.npmrc')).toBe('engine-strict=true\n'); + }); + + for (const packageManager of ['yarn', 'pnpm', 'bun', undefined] as const) { + it(`should not create an .npmrc when the package manager is ${packageManager}`, async () => { + const tree = await schematicRunner.runSchematic('workspace', { + ...defaultOptions, + packageManager, + }); + expect(tree.exists('/.npmrc')).toBeFalse(); + }); + } + it('should set the name in package.json', async () => { const tree = await schematicRunner.runSchematic('workspace', defaultOptions); const pkg = JSON.parse(tree.readContent('/package.json'));