Skip to content

fix(@angular/build): skip semantic diagnostics for declaration files#33400

Closed
arturovt wants to merge 1 commit into
angular:mainfrom
arturovt:fix/aot_compilation_skip_semantics
Closed

fix(@angular/build): skip semantic diagnostics for declaration files#33400
arturovt wants to merge 1 commit into
angular:mainfrom
arturovt:fix/aot_compilation_skip_semantics

Conversation

@arturovt

Copy link
Copy Markdown
Contributor

Declaration files don't produce semantic or template diagnostics, so calling getSemanticDiagnostics() on them was just wasted work. Move the isDeclarationFile guard to before that call so .d.ts files are skipped entirely.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request optimizes the AOT compilation process by moving the check for declaration files (sourceFile.isDeclarationFile) to occur before retrieving semantic diagnostics. This avoids unnecessary processing and profiling for declaration files, which do not contain semantic or template diagnostics. There are no review comments, so I have no feedback to provide.

@JoostK

JoostK commented Jun 17, 2026

Copy link
Copy Markdown
Member

I don't think this holds for skipLibCheck: false

Declaration files don't produce semantic or template diagnostics, so
calling getSemanticDiagnostics() on them was just wasted work. Move
the isDeclarationFile guard to before that call so .d.ts files are
skipped entirely.
@arturovt arturovt force-pushed the fix/aot_compilation_skip_semantics branch from 2be4035 to 2eef0c7 Compare June 17, 2026 21:53
@atscott

atscott commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Since getSemanticDiagnostics(sourceFile) already appears to fast-return for .d.ts files under skipLibCheck, this change looks like an extra short-circuit in front of an existing short-circuit. I’m not seeing evidence of any win here, but we do take on extra code paths and another embedded assumption about TS diagnostic behavior. Unless there’s profiling showing this matters, I’d wouldn’t recommend moving forward with this change.

@arturovt

arturovt commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

@atscott Measured on a real app (build time ~50s, ~N .d.ts files in node_modules, "N" because I don't know how many of them, when I log "continue" in that if-condition, it kills my terminal). NG_DIAGNOSTICS_TOTAL dropped from ~16s → ~12.9s (~19%). While TS does return emptyArray internally for these files, the call overhead across hundreds of declaration files is non-trivial. Please note I'm only learning in this direction, you can also point me whether I should do any additional profiling, I'm wondering whether ~20% is also a small win.

Also, DURATION[NG_DIAGNOSTICS_SEMANTIC] and other yield* expressions are NOT printed, is that a bug or expected?

@atscott

atscott commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

That performance difference seems likely due to build time variance.

I modified the Angular build performance tracker to log individual durations for every getSemanticDiagnostics call. I then compared the unpatched (baseline) and patched compilations of the web application with parallel TypeScript compilation disabled (NG_BUILD_PARALLEL_TS=0) to ensure accurate measurement. The build was then performed on a project with ~7000 source files.

Results Summary

Metric Baseline (Unpatched) Patched Difference (Saved) Change (%)
NG_DIAGNOSTICS_SEMANTIC calls 4,027 2,789 1,238 -30.74%
Total NG_DIAGNOSTICS_SEMANTIC duration 0.078985643s 0.062156157s 0.016829486s -21.31%
Average duration per call 0.000019614s 0.000022286s - -

Key Findings

1. Call Count is Correctly Reduced

The patch correctly skips declaration files before calling getSemanticDiagnostics(). This avoided 1,238 redundant calls (dropping from 4,027 to 2,789).

2. TypeScript Fast Path makes Calls Extremely Cheap

When skipLibCheck is enabled (the default), TypeScript's getSemanticDiagnostics() has an internal fast path that returns an empty array almost instantly for declaration files:

  • Average baseline call duration: ~19.6 microseconds (0.000019614s).
  • Because these calls are so cheap, the total time spent on them is negligible.

3. Absolute Savings are Negligible

Skipping 1,238 calls saved a total of 16.8 milliseconds (0.0168s).
This is only ~0.08% of the total diagnostics phase (NG_DIAGNOSTICS_TOTAL ~20s), which is completely imperceptible.

While the patch is technically correct in avoiding redundant calls, the actual performance benefit is in the range of milliseconds, not seconds. The change does not hurt, but it does not provide the claimed speedup.

@atscott atscott closed this Jun 18, 2026
@arturovt

Copy link
Copy Markdown
Contributor Author

@atscott could you tell why yield expressions aren’t logged to console? I mean perf profiling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants