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); + }); }); }); });