diff --git a/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts b/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts index da81f81919a..3c5072882f4 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts @@ -10,7 +10,7 @@ import {AnimationTriggerNames, compileClassMetadata, compileComponentFromMetadat import ts from 'typescript'; import {Cycle, CycleAnalyzer, CycleHandlingStrategy} from '../../../cycles'; -import {ErrorCode, FatalDiagnosticError, makeDiagnostic} from '../../../diagnostics'; +import {ErrorCode, FatalDiagnosticError, makeDiagnostic, makeRelatedInformation} from '../../../diagnostics'; import {absoluteFrom, relative} from '../../../file_system'; import {assertSuccessfulReferenceEmit, ImportedFile, ModuleResolver, Reference, ReferenceEmitter} from '../../../imports'; import {DependencyTracker} from '../../../incremental/api'; @@ -260,7 +260,12 @@ export class ComponentDecoratorHandler implements } diagnostics.push(makeDiagnostic( ErrorCode.COMPONENT_NOT_STANDALONE, component.get('imports')!, - `'imports' is only valid on a component that is standalone.`)); + `'imports' is only valid on a component that is standalone.`, + [makeRelatedInformation( + node.name, `Did you forget to add 'standalone: true' to this @Component?`)])); + // Poison the component so that we don't spam further template type-checking errors that + // result from misconfigured imports. + isPoisoned = true; } else if (component.has('imports')) { const expr = component.get('imports')!; const imported = this.evaluator.evaluate(expr); diff --git a/packages/compiler-cli/test/ngtsc/standalone_spec.ts b/packages/compiler-cli/test/ngtsc/standalone_spec.ts index d8c03cd618a..9a50ff8cc83 100644 --- a/packages/compiler-cli/test/ngtsc/standalone_spec.ts +++ b/packages/compiler-cli/test/ngtsc/standalone_spec.ts @@ -353,6 +353,32 @@ runInEachFileSystem(() => { expect(diags).toContain(`Type 'number' is not assignable to type 'string'.`); expect(diags).toContain(`Type 'boolean' is not assignable to type 'string'.`); }); + + it('should not spam errors if imports is misconfigured', () => { + env.write('test.ts', ` + import {Component, Input} from '@angular/core'; + + @Component({ + standalone: true, + selector: 'dep-cmp', + template: '', + }) + export class DepCmp {} + + @Component({ + // missing standalone: true, would ordinarily cause template type-checking errors + // as well as an error about imports on a non-standalone component. + imports: [DepCmp], + selector: 'test-cmp', + template: '', + }) + export class TestCmp {} + `); + + const diags = env.driveDiagnostics(); + expect(diags.length).toBe(1); + expect(diags[0].messageText).toContain('imports'); + }); }); describe('NgModule-side', () => {