From 2e2c426e7609de551dafb6360e6373333a278c4e Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Thu, 20 Aug 2026 21:11:02 +0000 Subject: [PATCH] fix(compiler-cli): deduplicate deferred imports across multiple blocks When @Component.deferredImports is defined as an object mapping block names to dependency arrays, deduplicate entries when aggregating block imports into the component-level flattened scope. This prevents duplicate directive/component collisions in DirectiveMatcher when multiple @defer blocks share dependencies. --- .../ngtsc/annotations/component/src/util.ts | 6 ++- .../compiler-cli/test/ngtsc/defer_spec.ts | 40 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/packages/compiler-cli/src/ngtsc/annotations/component/src/util.ts b/packages/compiler-cli/src/ngtsc/annotations/component/src/util.ts index 24bea974b2d..045ca3bea43 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/component/src/util.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/component/src/util.ts @@ -120,7 +120,11 @@ export function validateAndFlattenComponentImports( validateAndFlattenComponentImports(blockValue, propExpr, isDeferred); diagnostics.push(...blockDiagnostics); - flattened.push(...blockImports); + for (const blockImport of blockImports) { + if (!flattened.some((existing) => existing.node === blockImport.node)) { + flattened.push(blockImport); + } + } importsByBlock.set(blockName, blockImports); } return {imports: flattened, importsByBlock, diagnostics}; diff --git a/packages/compiler-cli/test/ngtsc/defer_spec.ts b/packages/compiler-cli/test/ngtsc/defer_spec.ts index f1d7d2f37f7..0d6559ebb0c 100644 --- a/packages/compiler-cli/test/ngtsc/defer_spec.ts +++ b/packages/compiler-cli/test/ngtsc/defer_spec.ts @@ -2547,6 +2547,46 @@ runInEachFileSystem(() => { "Directive 'DirB' (used on element 'div') was imported via `@Component.deferredImports` under block 'blockB', but is used in a `@defer` block configured for 'blockC'", ); }); + + it('should allow the same dependency across multiple defer blocks without duplicate symbol diagnostics', () => { + env.write( + 'dirs.ts', + ` + import { Directive } from '@angular/core'; + @Directive({ selector: '[dirA]' }) + export class DirA {} + `, + ); + + env.write( + '/test.ts', + ` + import { Component } from '@angular/core'; + import { DirA } from './dirs'; + + @Component({ + selector: 'test-cmp', + // @ts-ignore + deferredImports: { + blockA: [DirA], + blockB: [DirA], + }, + template: \` + @defer (name blockA) { +
+ } + @defer (name blockB) { +
+ } + \`, + }) + export class TestCmp {} + `, + ); + + const diags = env.driveDiagnostics(); + expect(diags.length).toBe(0); + }); }); }); });