@@ -377,10 +377,11 @@ export class AngularWebpackPlugin {
377
377
}
378
378
379
379
private loadConfiguration ( compilation : WebpackCompilation ) {
380
- const { options : compilerOptions , rootNames, errors } = readConfiguration (
381
- this . pluginOptions . tsconfig ,
382
- this . pluginOptions . compilerOptions ,
383
- ) ;
380
+ const {
381
+ options : compilerOptions ,
382
+ rootNames,
383
+ errors,
384
+ } = readConfiguration ( this . pluginOptions . tsconfig , this . pluginOptions . compilerOptions ) ;
384
385
compilerOptions . enableIvy = true ;
385
386
compilerOptions . noEmitOnError = false ;
386
387
compilerOptions . suppressOutputPathCheck = true ;
@@ -425,51 +426,57 @@ export class AngularWebpackPlugin {
425
426
const typeScriptProgram = angularProgram . getTsProgram ( ) ;
426
427
augmentProgramWithVersioning ( typeScriptProgram ) ;
427
428
428
- const builder = ts . createEmitAndSemanticDiagnosticsBuilderProgram (
429
- typeScriptProgram ,
430
- host ,
431
- this . builder ,
432
- ) ;
433
-
434
- // Save for next rebuild
429
+ let builder : ts . BuilderProgram | ts . EmitAndSemanticDiagnosticsBuilderProgram ;
435
430
if ( this . watchMode ) {
436
- this . builder = builder ;
431
+ builder = this . builder = ts . createEmitAndSemanticDiagnosticsBuilderProgram (
432
+ typeScriptProgram ,
433
+ host ,
434
+ this . builder ,
435
+ ) ;
437
436
this . ngtscNextProgram = angularProgram ;
437
+ } else {
438
+ // When not in watch mode, the startup cost of the incremental analysis can be avoided by
439
+ // using an abstract builder that only wraps a TypeScript program.
440
+ builder = ts . createAbstractBuilder ( typeScriptProgram , host ) ;
438
441
}
439
442
440
443
// Update semantic diagnostics cache
441
444
const affectedFiles = new Set < ts . SourceFile > ( ) ;
442
- // eslint-disable-next-line no-constant-condition
443
- while ( true ) {
444
- const result = builder . getSemanticDiagnosticsOfNextAffectedFile ( undefined , ( sourceFile ) => {
445
- // If the affected file is a TTC shim, add the shim's original source file.
446
- // This ensures that changes that affect TTC are typechecked even when the changes
447
- // are otherwise unrelated from a TS perspective and do not result in Ivy codegen changes.
448
- // For example, changing @Input property types of a directive used in another component's
449
- // template.
450
- if (
451
- ignoreForDiagnostics . has ( sourceFile ) &&
452
- sourceFile . fileName . endsWith ( '.ngtypecheck.ts' )
453
- ) {
454
- // This file name conversion relies on internal compiler logic and should be converted
455
- // to an official method when available. 15 is length of `.ngtypecheck.ts`
456
- const originalFilename = sourceFile . fileName . slice ( 0 , - 15 ) + '.ts' ;
457
- const originalSourceFile = builder . getSourceFile ( originalFilename ) ;
458
- if ( originalSourceFile ) {
459
- affectedFiles . add ( originalSourceFile ) ;
445
+
446
+ // Analyze affected files when in watch mode for incremental type checking
447
+ if ( 'getSemanticDiagnosticsOfNextAffectedFile' in builder ) {
448
+ // eslint-disable-next-line no-constant-condition
449
+ while ( true ) {
450
+ const result = builder . getSemanticDiagnosticsOfNextAffectedFile ( undefined , ( sourceFile ) => {
451
+ // If the affected file is a TTC shim, add the shim's original source file.
452
+ // This ensures that changes that affect TTC are typechecked even when the changes
453
+ // are otherwise unrelated from a TS perspective and do not result in Ivy codegen changes.
454
+ // For example, changing @Input property types of a directive used in another component's
455
+ // template.
456
+ if (
457
+ ignoreForDiagnostics . has ( sourceFile ) &&
458
+ sourceFile . fileName . endsWith ( '.ngtypecheck.ts' )
459
+ ) {
460
+ // This file name conversion relies on internal compiler logic and should be converted
461
+ // to an official method when available. 15 is length of `.ngtypecheck.ts`
462
+ const originalFilename = sourceFile . fileName . slice ( 0 , - 15 ) + '.ts' ;
463
+ const originalSourceFile = builder . getSourceFile ( originalFilename ) ;
464
+ if ( originalSourceFile ) {
465
+ affectedFiles . add ( originalSourceFile ) ;
466
+ }
467
+
468
+ return true ;
460
469
}
461
470
462
- return true ;
463
- }
471
+ return false ;
472
+ } ) ;
464
473
465
- return false ;
466
- } ) ;
474
+ if ( ! result ) {
475
+ break ;
476
+ }
467
477
468
- if ( ! result ) {
469
- break ;
478
+ affectedFiles . add ( result . affected as ts . SourceFile ) ;
470
479
}
471
-
472
- affectedFiles . add ( result . affected as ts . SourceFile ) ;
473
480
}
474
481
475
482
// Collect non-semantic diagnostics
@@ -581,16 +588,18 @@ export class AngularWebpackPlugin {
581
588
host : CompilerHost ,
582
589
diagnosticsReporter : DiagnosticsReporter ,
583
590
) {
584
- const builder = ts . createEmitAndSemanticDiagnosticsBuilderProgram (
585
- rootNames ,
586
- compilerOptions ,
587
- host ,
588
- this . builder ,
589
- ) ;
590
-
591
- // Save for next rebuild
591
+ let builder ;
592
592
if ( this . watchMode ) {
593
- this . builder = builder ;
593
+ builder = this . builder = ts . createEmitAndSemanticDiagnosticsBuilderProgram (
594
+ rootNames ,
595
+ compilerOptions ,
596
+ host ,
597
+ this . builder ,
598
+ ) ;
599
+ } else {
600
+ // When not in watch mode, the startup cost of the incremental analysis can be avoided by
601
+ // using an abstract builder that only wraps a TypeScript program.
602
+ builder = ts . createAbstractBuilder ( rootNames , compilerOptions , host ) ;
594
603
}
595
604
596
605
const diagnostics = [
0 commit comments