From 5c0f1f2fdb62121c75100bc51bd6622e344a5500 Mon Sep 17 00:00:00 2001 From: Matthieu Riegler Date: Mon, 1 Dec 2025 13:49:51 +0100 Subject: [PATCH 1/2] fix(@schematics/angular): remove `experimentalDecorators` from new projects `experimentalDecorators: true` was required to use constructor DI. With recommendation now to use `inject` for DI, new projects don't need the experimental decorators anymore. --- .../schematics/angular/workspace/files/tsconfig.json.template | 1 - .../build/library/lib-unused-decorated-class-treeshake.ts | 2 +- tests/e2e/tests/i18n/setup.ts | 4 ++-- tests/e2e/tests/vitest/tslib-resolution.ts | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/schematics/angular/workspace/files/tsconfig.json.template b/packages/schematics/angular/workspace/files/tsconfig.json.template index 799cff73365a..4c1bfeb03a61 100644 --- a/packages/schematics/angular/workspace/files/tsconfig.json.template +++ b/packages/schematics/angular/workspace/files/tsconfig.json.template @@ -10,7 +10,6 @@ "noFallthroughCasesInSwitch": true,<% } %> "skipLibCheck": true, "isolatedModules": true, - "experimentalDecorators": true, "importHelpers": true, "target": "ES2022", "module": "preserve" diff --git a/tests/e2e/tests/build/library/lib-unused-decorated-class-treeshake.ts b/tests/e2e/tests/build/library/lib-unused-decorated-class-treeshake.ts index 33b221a32efe..91a4c41a4d65 100644 --- a/tests/e2e/tests/build/library/lib-unused-decorated-class-treeshake.ts +++ b/tests/e2e/tests/build/library/lib-unused-decorated-class-treeshake.ts @@ -14,7 +14,7 @@ export default async function () { 'projects/my-lib/src/lib/my-lib.ts', ` function something() { - return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { + return function (originalMethod: any, context: ClassMethodDecoratorContext) { console.log("someDecorator"); }; } diff --git a/tests/e2e/tests/i18n/setup.ts b/tests/e2e/tests/i18n/setup.ts index 8eade4e2783c..bfe3c91c4353 100644 --- a/tests/e2e/tests/i18n/setup.ts +++ b/tests/e2e/tests/i18n/setup.ts @@ -130,7 +130,7 @@ export async function setupI18nConfig() { await writeFile( 'src/app/app.ts', ` - import { Component, Inject, LOCALE_ID } from '@angular/core'; + import { Component, inject, LOCALE_ID } from '@angular/core'; import { DatePipe } from '@angular/common'; import { RouterOutlet } from '@angular/router'; @@ -140,7 +140,7 @@ export async function setupI18nConfig() { templateUrl: './app.html' }) export class App { - constructor(@Inject(LOCALE_ID) public locale: string) { } + locale = inject(LOCALE_ID); title = 'i18n'; jan = new Date(2000, 0, 1); minutes = 3; diff --git a/tests/e2e/tests/vitest/tslib-resolution.ts b/tests/e2e/tests/vitest/tslib-resolution.ts index 759d5e2b5728..71903687fb0f 100644 --- a/tests/e2e/tests/vitest/tslib-resolution.ts +++ b/tests/e2e/tests/vitest/tslib-resolution.ts @@ -14,7 +14,7 @@ export default async function () { 'src/app/custom-decorator.ts', ` export function MyDecorator() { - return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { + return function (originalMethod: any, context: ClassMethodDecoratorContext) { // do nothing }; } From 398d297bed88ae2eaaf74aab5040813b3dae555d Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 28 Apr 2026 10:15:04 +0000 Subject: [PATCH 2/2] fixup! fix(@schematics/angular): remove `experimentalDecorators` from new projects --- .../lib-unused-decorated-class-treeshake.ts | 49 ------------------- .../e2e/tests/build/ts-standard-decorators.ts | 37 -------------- 2 files changed, 86 deletions(-) delete mode 100644 tests/e2e/tests/build/library/lib-unused-decorated-class-treeshake.ts delete mode 100644 tests/e2e/tests/build/ts-standard-decorators.ts diff --git a/tests/e2e/tests/build/library/lib-unused-decorated-class-treeshake.ts b/tests/e2e/tests/build/library/lib-unused-decorated-class-treeshake.ts deleted file mode 100644 index 91a4c41a4d65..000000000000 --- a/tests/e2e/tests/build/library/lib-unused-decorated-class-treeshake.ts +++ /dev/null @@ -1,49 +0,0 @@ -import assert from 'node:assert'; -import { appendToFile, expectFileToExist, expectFileToMatch, readFile } from '../../../utils/fs'; -import { ng } from '../../../utils/process'; -import { libraryConsumptionSetup } from './setup'; -import { updateJsonFile } from '../../../utils/project'; -import { expectToFail } from '../../../utils/utils'; - -export default async function () { - await ng('cache', 'off'); - await libraryConsumptionSetup(); - - // Add an unused class as part of the public api. - await appendToFile( - 'projects/my-lib/src/lib/my-lib.ts', - ` - function something() { - return function (originalMethod: any, context: ClassMethodDecoratorContext) { - console.log("someDecorator"); - }; - } - - export class ExampleClass { - @something() - method() {} - } - `, - ); - - // build the lib - await ng('build', 'my-lib', '--configuration=production'); - const packageJson = JSON.parse(await readFile('dist/my-lib/package.json')); - assert.equal(packageJson.sideEffects, false); - - // build the app - await ng('build', 'test-project', '--configuration=production', '--output-hashing=none'); - // Output should not contain `ExampleClass` as the library is marked as side-effect free. - await expectFileToExist('dist/test-project/browser/main.js'); - await expectToFail(() => expectFileToMatch('dist/test-project/browser/main.js', 'someDecorator')); - - // Mark library as side-effectful. - await updateJsonFile('dist/my-lib/package.json', (packageJson) => { - packageJson.sideEffects = true; - }); - - // build the app - await ng('build', 'test-project', '--configuration=production', '--output-hashing=none'); - // Output should contain `ExampleClass` as the library is marked as side-effectful. - await expectFileToMatch('dist/test-project/browser/main.js', 'someDecorator'); -} diff --git a/tests/e2e/tests/build/ts-standard-decorators.ts b/tests/e2e/tests/build/ts-standard-decorators.ts deleted file mode 100644 index 05d056675d3b..000000000000 --- a/tests/e2e/tests/build/ts-standard-decorators.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { getGlobalVariable } from '../../utils/env'; -import { ng } from '../../utils/process'; -import { updateJsonFile, updateTsConfig } from '../../utils/project'; -import { executeBrowserTest } from '../../utils/puppeteer'; - -export default async function () { - // Update project to disable experimental decorators - await updateTsConfig((json) => { - json['compilerOptions']['experimentalDecorators'] = false; - }); - - // Default production build - await ng('build'); - - // Production build with JIT - await updateJsonFile('angular.json', (json) => { - // Remove bundle budgets to avoid a build error due to the expected increased output size - // of a JIT production build. - json.projects['test-project'].architect.build.configurations.production.budgets = []; - }); - - if (!getGlobalVariable('argv')['esbuild']) { - await ng('build', '--no-aot', '--no-build-optimizer'); - } - - // Default development build - await ng('build', '--configuration=development'); - - // Development build with JIT - await ng('build', '--configuration=development', '--no-aot'); - - // Unit tests (JIT only) - await ng('test', '--no-watch'); - - // Ensure application functions in a browser - await executeBrowserTest(); -}