fix(angular-rspack): speed up watch-mode rebuilds#35282
fix(angular-rspack): speed up watch-mode rebuilds#35282leosvelperez wants to merge 1 commit intomasterfrom
Conversation
✅ Deploy Preview for nx-dev ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for nx-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
View your CI Pipeline Execution ↗ for commit d0151f0
☁️ Nx Cloud last updated this comment at |
Rebuilds transformed ALL Angular-emitted files through JavaScriptTransformer eagerly in buildAndAnalyze, even when only one file changed. Now transform lazily in the loader (esbuild's onLoad pattern) so only files Rspack actually requests are transformed. Also align component stylesheet bundler with Angular CLI by enabling incremental caching in watch mode, and move JavaScriptTransformer.close() from the per-build emit hook to the shutdown hook so worker threads persist across rebuilds.
|
Hey @leosvelperez! I was very excited about your changes and when reading them I thought 'this is it!' so wanted to try things out as fast as possible. I couldn't find any build artifacts in the Nx CI pipeline so built everything from scratch and dropped the updated versions of Unfortunately I'm not seeing the performance difference you're mentioning :/ I'll do some averaging for rebuild times with the new implementation and then roll-back and compare with what it was before, but if there is a change it's definitely not close to the expected I also still observe a long delay between saving a file and actually seeing the CLI pick up the file change, maybe that's where a lot of time is lost? I have an app that takes Sometimes I'm also seeing a situation in which even when I change and save a file, nothing is picked up by the CLI. I'm not sure if after a very (!) long time the change gets picked up, or if that was after I hit Control+C but it did pick it up eventually. Very long time is 2min+, longer than the initial build. Is there a chance something else (an earlier relevant change) is missing in your branch? If not, is there a published pre-release version I can use instead of what I built, to exclude the fact I may have made a mistake? Apart from that: I'll gladly provide you with any information you might need from my setup to be able to debug this issue further. |
|
I second that this PR is fairly important for the plugin. Is there any concern on addtional memory usage with the rawEmitCache ? Coming from a rather large repository space, this was my first thought; perhaps it's unfounded since this in only for local development? |
|
Failed to publish a PR release of this pull request, triggered by @leosvelperez. |
|
@Timebutt I tested it against the repro you provided (https://github.com/Timebutt/ng-bundler-benchmark/tree/add-local-dev-configurations), but there was a bug in the benchmark script I used. I've rerun everything manually with more care, and you're right: this isn't improving anything. I'm closing it and will keep investigating. |
|
@leosvelperez unsure if this helps, but from my experience the first watch mode rebuild is slow but it's significantly faster on additional updates |
Current Behavior
Watch-mode rebuilds in
@nx/angular-rspackare significantly slower than expected — often several times slower than the Angular CLI's esbuild-based dev server on the same project. On large apps, a single-file change can take 10+ seconds to rebuild even though only one file changed.Three root causes:
buildAndAnalyzeeagerly runsJavaScriptTransformer.transformData()on every file returned byemitAffectedFiles(). Due to Angular's.ngtypecheck.tsshim version mismatch between the first build (placeholder content) and subsequent rebuilds (real analysis content), TypeScript's incremental builder reports all ~7800 files as affected — so all ~7800 files go through the expensive transform on every rebuild.ComponentStylesheetBundleris constructed withincremental: false, which disables result caching, selective invalidation, and esbuild's incremental rebuild mode for component styles.JavaScriptTransformer.close()is called in theemithook, which fires on every compilation — tearing down and re-spawning the worker thread pool on each rebuild.Expected Behavior
Watch-mode rebuilds perform on par with the Angular CLI's esbuild pipeline. A single-file change should only transform the changed file and reuse cached output for everything else.
Changes:
buildAndAnalyzenow stores raw emitted content in arawEmitCacheand invalidates matching transformed cache entries only when the raw content actually changed. The Angular transform loader runstransformData()lazily when Rspack requests a module, mirroring esbuild'sonLoadpattern. Files Rspack doesn't re-process are never re-transformed.ComponentStylesheetBundleris now constructed withincremental: !!options.watchandinvalidate(modifiedFiles)is called on rebuilds, matching the Angular CLI'ssetup-bundling.jsbehavior.JavaScriptTransformer.close()moved from the per-buildemithook to theshutdownhook so workers live across rebuilds (mirrors esbuild plugin'sonDispose).Measured on a benchmark app with ~7800 files (Angular 21.2):
Related Issue(s)
Fixes #34936