@@ -24,6 +24,12 @@ import ts from 'typescript';
24
24
import angularApplicationPreset from '../../babel/presets/application' ;
25
25
import { requiresLinking } from '../../babel/webpack-loader' ;
26
26
import { loadEsmModule } from '../../utils/load-esm' ;
27
+ import {
28
+ logCumulativeDurations ,
29
+ profileAsync ,
30
+ profileSync ,
31
+ resetCumulativeDurations ,
32
+ } from './profiling' ;
27
33
import { BundleStylesheetOptions , bundleStylesheetFile , bundleStylesheetText } from './stylesheets' ;
28
34
29
35
interface EmitFileResult {
@@ -193,21 +199,23 @@ export function createCompilerPlugin(
193
199
options : compilerOptions ,
194
200
rootNames,
195
201
errors : configurationDiagnostics ,
196
- } = compilerCli . readConfiguration ( pluginOptions . tsconfig , {
197
- noEmitOnError : false ,
198
- suppressOutputPathCheck : true ,
199
- outDir : undefined ,
200
- inlineSources : pluginOptions . sourcemap ,
201
- inlineSourceMap : pluginOptions . sourcemap ,
202
- sourceMap : false ,
203
- mapRoot : undefined ,
204
- sourceRoot : undefined ,
205
- declaration : false ,
206
- declarationMap : false ,
207
- allowEmptyCodegenFiles : false ,
208
- annotationsAs : 'decorators' ,
209
- enableResourceInlining : false ,
210
- } ) ;
202
+ } = profileSync ( 'NG_READ_CONFIG' , ( ) =>
203
+ compilerCli . readConfiguration ( pluginOptions . tsconfig , {
204
+ noEmitOnError : false ,
205
+ suppressOutputPathCheck : true ,
206
+ outDir : undefined ,
207
+ inlineSources : pluginOptions . sourcemap ,
208
+ inlineSourceMap : pluginOptions . sourcemap ,
209
+ sourceMap : false ,
210
+ mapRoot : undefined ,
211
+ sourceRoot : undefined ,
212
+ declaration : false ,
213
+ declarationMap : false ,
214
+ allowEmptyCodegenFiles : false ,
215
+ annotationsAs : 'decorators' ,
216
+ enableResourceInlining : false ,
217
+ } ) ,
218
+ ) ;
211
219
212
220
if ( compilerOptions . target === undefined || compilerOptions . target < ts . ScriptTarget . ES2022 ) {
213
221
// If 'useDefineForClassFields' is already defined in the users project leave the value as is.
@@ -231,6 +239,9 @@ export function createCompilerPlugin(
231
239
build . onStart ( async ( ) => {
232
240
const result : OnStartResult = { } ;
233
241
242
+ // Reset debug performance tracking
243
+ resetCumulativeDurations ( ) ;
244
+
234
245
// Reset stylesheet resource output files
235
246
stylesheetResourceFiles = [ ] ;
236
247
@@ -307,11 +318,10 @@ export function createCompilerPlugin(
307
318
}
308
319
309
320
// Create the Angular specific program that contains the Angular compiler
310
- const angularProgram = new compilerCli . NgtscProgram (
311
- rootNames ,
312
- compilerOptions ,
313
- host ,
314
- previousAngularProgram ,
321
+ const angularProgram = profileSync (
322
+ 'NG_CREATE_PROGRAM' ,
323
+ ( ) =>
324
+ new compilerCli . NgtscProgram ( rootNames , compilerOptions , host , previousAngularProgram ) ,
315
325
) ;
316
326
previousAngularProgram = angularProgram ;
317
327
const angularCompiler = angularProgram . compiler ;
@@ -327,7 +337,7 @@ export function createCompilerPlugin(
327
337
) ;
328
338
previousBuilder = builder ;
329
339
330
- await angularCompiler . analyzeAsync ( ) ;
340
+ await profileAsync ( 'NG_ANALYZE_PROGRAM' , ( ) => angularCompiler . analyzeAsync ( ) ) ;
331
341
332
342
function * collectDiagnostics ( ) : Iterable < ts . Diagnostic > {
333
343
// Collect program level diagnostics
@@ -343,25 +353,36 @@ export function createCompilerPlugin(
343
353
continue ;
344
354
}
345
355
346
- yield * builder . getSyntacticDiagnostics ( sourceFile ) ;
347
- yield * builder . getSemanticDiagnostics ( sourceFile ) ;
356
+ yield * profileSync (
357
+ 'NG_DIAGNOSTICS_SYNTACTIC' ,
358
+ ( ) => builder . getSyntacticDiagnostics ( sourceFile ) ,
359
+ true ,
360
+ ) ;
361
+ yield * profileSync (
362
+ 'NG_DIAGNOSTICS_SEMANTIC' ,
363
+ ( ) => builder . getSemanticDiagnostics ( sourceFile ) ,
364
+ true ,
365
+ ) ;
348
366
349
- const angularDiagnostics = angularCompiler . getDiagnosticsForFile (
350
- sourceFile ,
351
- OptimizeFor . WholeProgram ,
367
+ const angularDiagnostics = profileSync (
368
+ 'NG_DIAGNOSTICS_TEMPLATE' ,
369
+ ( ) => angularCompiler . getDiagnosticsForFile ( sourceFile , OptimizeFor . WholeProgram ) ,
370
+ true ,
352
371
) ;
353
372
yield * angularDiagnostics ;
354
373
}
355
374
}
356
375
357
- for ( const diagnostic of collectDiagnostics ( ) ) {
358
- const message = convertTypeScriptDiagnostic ( diagnostic , host ) ;
359
- if ( diagnostic . category === ts . DiagnosticCategory . Error ) {
360
- ( result . errors ??= [ ] ) . push ( message ) ;
361
- } else {
362
- ( result . warnings ??= [ ] ) . push ( message ) ;
376
+ profileSync ( 'NG_DIAGNOSTICS_TOTAL' , ( ) => {
377
+ for ( const diagnostic of collectDiagnostics ( ) ) {
378
+ const message = convertTypeScriptDiagnostic ( diagnostic , host ) ;
379
+ if ( diagnostic . category === ts . DiagnosticCategory . Error ) {
380
+ ( result . errors ??= [ ] ) . push ( message ) ;
381
+ } else {
382
+ ( result . warnings ??= [ ] ) . push ( message ) ;
383
+ }
363
384
}
364
- }
385
+ } ) ;
365
386
366
387
fileEmitter = createFileEmitter (
367
388
builder ,
@@ -376,74 +397,87 @@ export function createCompilerPlugin(
376
397
377
398
build . onLoad (
378
399
{ filter : compilerOptions . allowJs ? / \. [ c m ] ? [ j t ] s x ? $ / : / \. [ c m ] ? t s x ? $ / } ,
379
- async ( args ) => {
380
- assert . ok ( fileEmitter , 'Invalid plugin execution order' ) ;
381
-
382
- const typescriptResult = await fileEmitter (
383
- pluginOptions . fileReplacements ?. [ args . path ] ?? args . path ,
384
- ) ;
385
- if ( ! typescriptResult ) {
386
- // No TS result indicates the file is not part of the TypeScript program.
387
- // If allowJs is enabled and the file is JS then defer to the next load hook.
388
- if ( compilerOptions . allowJs && / \. [ c m ] ? j s $ / . test ( args . path ) ) {
389
- return undefined ;
390
- }
391
-
392
- // Otherwise return an error
393
- return {
394
- errors : [
395
- {
396
- text : `File ' ${ args . path } ' is missing from the TypeScript compilation.` ,
397
- notes : [
400
+ ( args ) =>
401
+ profileAsync (
402
+ 'NG_EMIT_TS*' ,
403
+ async ( ) => {
404
+ assert . ok ( fileEmitter , 'Invalid plugin execution order' ) ;
405
+
406
+ const typescriptResult = await fileEmitter (
407
+ pluginOptions . fileReplacements ?. [ args . path ] ?? args . path ,
408
+ ) ;
409
+ if ( ! typescriptResult ) {
410
+ // No TS result indicates the file is not part of the TypeScript program.
411
+ // If allowJs is enabled and the file is JS then defer to the next load hook.
412
+ if ( compilerOptions . allowJs && / \. [ c m ] ? j s $ / . test ( args . path ) ) {
413
+ return undefined ;
414
+ }
415
+
416
+ // Otherwise return an error
417
+ return {
418
+ errors : [
398
419
{
399
- text : `Ensure the file is part of the TypeScript program via the 'files' or 'include' property.` ,
420
+ text : `File '${ args . path } ' is missing from the TypeScript compilation.` ,
421
+ notes : [
422
+ {
423
+ text : `Ensure the file is part of the TypeScript program via the 'files' or 'include' property.` ,
424
+ } ,
425
+ ] ,
400
426
} ,
401
427
] ,
402
- } ,
403
- ] ,
404
- } ;
405
- }
406
-
407
- const data = typescriptResult . content ?? '' ;
408
- // The pre-transformed data is used as a cache key. Since the cache is memory only,
409
- // the options cannot change and do not need to be represented in the key. If the
410
- // cache is later stored to disk, then the options that affect transform output
411
- // would need to be added to the key as well.
412
- let contents = babelDataCache . get ( data ) ;
413
- if ( contents === undefined ) {
414
- contents = await transformWithBabel ( args . path , data , pluginOptions ) ;
415
- babelDataCache . set ( data , contents ) ;
416
- }
417
-
418
- return {
419
- contents ,
420
- loader : 'js' ,
421
- } ;
422
- } ,
428
+ } ;
429
+ }
430
+
431
+ const data = typescriptResult . content ?? '' ;
432
+ // The pre-transformed data is used as a cache key. Since the cache is memory only,
433
+ // the options cannot change and do not need to be represented in the key. If the
434
+ // cache is later stored to disk, then the options that affect transform output
435
+ // would need to be added to the key as well.
436
+ let contents = babelDataCache . get ( data ) ;
437
+ if ( contents === undefined ) {
438
+ contents = await transformWithBabel ( args . path , data , pluginOptions ) ;
439
+ babelDataCache . set ( data , contents ) ;
440
+ }
441
+
442
+ return {
443
+ contents ,
444
+ loader : 'js' ,
445
+ } ;
446
+ } ,
447
+ true ,
448
+ ) ,
423
449
) ;
424
450
425
- build . onLoad ( { filter : / \. [ c m ] ? j s $ / } , async ( args ) => {
426
- // The filename is currently used as a cache key. Since the cache is memory only,
427
- // the options cannot change and do not need to be represented in the key. If the
428
- // cache is later stored to disk, then the options that affect transform output
429
- // would need to be added to the key as well as a check for any change of content.
430
- let contents = pluginOptions . sourceFileCache ?. babelFileCache . get ( args . path ) ;
431
- if ( contents === undefined ) {
432
- const data = await fs . readFile ( args . path , 'utf-8' ) ;
433
- contents = await transformWithBabel ( args . path , data , pluginOptions ) ;
434
- pluginOptions . sourceFileCache ?. babelFileCache . set ( args . path , contents ) ;
435
- }
451
+ build . onLoad ( { filter : / \. [ c m ] ? j s $ / } , ( args ) =>
452
+ profileAsync (
453
+ 'NG_EMIT_JS*' ,
454
+ async ( ) => {
455
+ // The filename is currently used as a cache key. Since the cache is memory only,
456
+ // the options cannot change and do not need to be represented in the key. If the
457
+ // cache is later stored to disk, then the options that affect transform output
458
+ // would need to be added to the key as well as a check for any change of content.
459
+ let contents = pluginOptions . sourceFileCache ?. babelFileCache . get ( args . path ) ;
460
+ if ( contents === undefined ) {
461
+ const data = await fs . readFile ( args . path , 'utf-8' ) ;
462
+ contents = await transformWithBabel ( args . path , data , pluginOptions ) ;
463
+ pluginOptions . sourceFileCache ?. babelFileCache . set ( args . path , contents ) ;
464
+ }
436
465
437
- return {
438
- contents,
439
- loader : 'js' ,
440
- } ;
441
- } ) ;
466
+ return {
467
+ contents,
468
+ loader : 'js' ,
469
+ } ;
470
+ } ,
471
+ true ,
472
+ ) ,
473
+ ) ;
442
474
443
475
build . onEnd ( ( result ) => {
444
476
if ( stylesheetResourceFiles . length ) {
445
477
result . outputFiles ?. push ( ...stylesheetResourceFiles ) ;
446
478
}
479
+
480
+ logCumulativeDurations ( ) ;
447
481
} ) ;
448
482
} ,
449
483
} ;
0 commit comments