From 9d7138efa4d881e17cc4bdc0ef55dece480467d4 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Tue, 8 Sep 2026 16:00:16 +0200 Subject: [PATCH 1/3] perf(@angular/build): read rendered module length once per module in chunk optimizer When converting the chunk optimizer output into an esbuild-compatible metafile, the rendered length of each module was read inside the loop over the module's original inputs. The `renderedLength` property of a rolldown rendered module is a lazy getter that transfers the full module code from native memory on every access. Since each module in this pass is an entire esbuild output chunk, a main chunk of 17 MB with 3,588 inputs resulted in roughly 62 GB of string copies and around 150 seconds spent in `bundleOutputToEsbuildMetafile`, while the rolldown bundling itself took 3 seconds. Read the rendered length once per module before iterating its inputs. The generated metafile is unchanged. On the affected application the `OPTIMIZE_CHUNKS` phase drops from 179 seconds to 4 seconds and the total production build from 234 to 55 seconds. Fixes #34044 --- .../build/src/builders/application/chunk-optimizer.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/angular/build/src/builders/application/chunk-optimizer.ts b/packages/angular/build/src/builders/application/chunk-optimizer.ts index ea4c2f8076f9..3056ede376bf 100644 --- a/packages/angular/build/src/builders/application/chunk-optimizer.ts +++ b/packages/angular/build/src/builders/application/chunk-optimizer.ts @@ -113,11 +113,16 @@ function bundleOutputToEsbuildMetafile( continue; } + // Read the rendered length once per module. The value is a lazy getter on the bundler's + // rendered module object that transfers the entire module code from native memory on each + // access, which is prohibitively expensive when repeated for every input of a large chunk. + const { renderedLength } = renderedModule; + for (const [originalInputPath, originalInputInfo] of Object.entries( originalOutputEntry.inputs, )) { const proportion = originalInputInfo.bytesInOutput / totalOriginalBytesInModule; - const newBytesInOutput = Math.floor(renderedModule.renderedLength * proportion); + const newBytesInOutput = Math.floor(renderedLength * proportion); const existing = newOutputInputs[originalInputPath]; if (existing) { From 657a3238867dfdd55f52d2907bbfbd9c62f34783 Mon Sep 17 00:00:00 2001 From: Roman Garcia Date: Tue, 8 Sep 2026 16:15:49 +0200 Subject: [PATCH 2/3] Remove performance comments in chunk-optimizer.ts Removed comments explaining the performance impact of accessing the rendered length in the chunk optimizer. --- .../angular/build/src/builders/application/chunk-optimizer.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/angular/build/src/builders/application/chunk-optimizer.ts b/packages/angular/build/src/builders/application/chunk-optimizer.ts index 3056ede376bf..5c4d64c73a08 100644 --- a/packages/angular/build/src/builders/application/chunk-optimizer.ts +++ b/packages/angular/build/src/builders/application/chunk-optimizer.ts @@ -113,9 +113,6 @@ function bundleOutputToEsbuildMetafile( continue; } - // Read the rendered length once per module. The value is a lazy getter on the bundler's - // rendered module object that transfers the entire module code from native memory on each - // access, which is prohibitively expensive when repeated for every input of a large chunk. const { renderedLength } = renderedModule; for (const [originalInputPath, originalInputInfo] of Object.entries( From 308c23cc6a416e18aa5cc3bd90e4330a56f481e2 Mon Sep 17 00:00:00 2001 From: Roman Garcia Date: Tue, 8 Sep 2026 17:27:51 +0200 Subject: [PATCH 3/3] Update packages/angular/build/src/builders/application/chunk-optimizer.ts Co-authored-by: Charles <19598772+clydin@users.noreply.github.com> --- .../angular/build/src/builders/application/chunk-optimizer.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/angular/build/src/builders/application/chunk-optimizer.ts b/packages/angular/build/src/builders/application/chunk-optimizer.ts index 5c4d64c73a08..db3e1d2f180d 100644 --- a/packages/angular/build/src/builders/application/chunk-optimizer.ts +++ b/packages/angular/build/src/builders/application/chunk-optimizer.ts @@ -113,8 +113,10 @@ function bundleOutputToEsbuildMetafile( continue; } + // Read once per module: in Rolldown, `renderedLength` is an uncached getter that + // copies the entire module code across the NAPI bridge on each access. const { renderedLength } = renderedModule; - + for (const [originalInputPath, originalInputInfo] of Object.entries( originalOutputEntry.inputs, )) {