Skip to content

refactor(@angular/build): budget and optimize JavaScript transformation concurrency - #34086

Open
clydin wants to merge 4 commits into
angular:mainfrom
clydin:js-transformer-concurrency
Open

refactor(@angular/build): budget and optimize JavaScript transformation concurrency#34086
clydin wants to merge 4 commits into
angular:mainfrom
clydin:js-transformer-concurrency

Conversation

@clydin

@clydin clydin commented Sep 11, 2026

Copy link
Copy Markdown
Member

Optimizes JavaScript transformation concurrency and aligns the JavaScriptTransformer configuration and throttling semantics with the rest of the build pipeline (specifically I18nInliner).

With the OXC-based linker, JavaScript transformation tasks are significantly faster (completing in milliseconds per file), whereas worker thread instantiation in Node.js incurs ~140ms overhead per thread. Concurrently, esbuild utilizes all available CPU cores for bundling. This change budgets transformation concurrency to balance parallel processing capacity against thread startup and scheduling overhead, and ensures transformation backpressure is applied consistently across all entry points.

…Transformer

Aligns the JavaScriptTransformer concurrency configuration and semantics with the I18nInliner API. An optional maxConcurrency property is added to JavaScriptTransformerOptions with validation to ensure it is an integer greater than or equal to 1. The required positional maxThreads parameter is removed from the constructor, allowing concurrency to default to the available worker pool threads when omitted.

The previous concurrency multiplier that allowed up to double the worker count in active transformation tasks has also been removed. With the significantly faster oxc-based transformation pipeline, individual file transformations complete in milliseconds, eliminating the need for deep I/O task pre-buffering. Bounding active tasks directly to maxConcurrency also prevents task bursts from prematurely forcing the worker pool to expand to its maximum thread count. The minThreads pinning in WorkerPool creation is removed so that Piscina defaults to a single initial thread instead of eagerly allocating all workers.
…hrottle

Ensures that direct calls to transformData are bounded by the concurrency throttle. Previously, transformData bypassed the semaphore and directly dispatched tasks to the worker pool. A private #transform method now contains the core transformation logic, allowing both transformFile and transformData to use the throttle without double-throttling or unbounded worker dispatch.
…currency during bundling

JavaScript transformation tasks with the OXC linker are very fast (roughly 10ms per file), whereas worker thread startup in Node.js costs around 140ms per thread. Concurrently, esbuild utilizes all available CPU cores for bundling.

Budgeting transformation concurrency to a quarter of available cores balances parallel processing capacity with thread startup costs and avoids starving esbuild. A minimum of 1 ensures transformation progress on small or constrained environments, while an upper bound of 6 accommodates large builds on many-core systems without inducing thread scheduling overhead or excessive memory footprint.
@clydin clydin added the target: minor This PR is targeted for the next minor release label Sep 11, 2026

@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 refactors the JavaScriptTransformer class to accept a maxConcurrency option within its configuration object, replacing the previous positional maxThreads argument. It also introduces a new maxTransformWorkers utility to calculate the default transformation concurrency based on available parallelism (capped at 6) to prevent CPU starvation during bundling. Unit tests have been updated and expanded to cover these changes. No review comments were provided, so there is no feedback to address.

…avaScriptTransformer

Worker thread startup in Node.js incurs a non-trivial initialization delay (roughly 100ms to 160ms) primarily driven by V8 module evaluation and loading transitive dependencies of the linker, such as @angular/compiler-cli, @angular/compiler, and TypeScript. While individual OXC file transformations take only around 10ms, on-demand thread creation during burst requests exposes this startup latency directly on the critical path.

Configuring minThreads to match maxConcurrency ensures that worker threads are pre-allocated upfront. During initial bundling, this allows workers to complete their initialization concurrently while TypeScript compilation executes, hiding module loading overhead and preventing transformation bottlenecks when esbuild emits files. If linker initialization costs are reduced in the future or a pre-warmed shared worker pool is introduced, this pre-allocation strategy can be revisited.
@clydin clydin added the action: review The PR is still awaiting reviews from at least one requested reviewer label Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action: review The PR is still awaiting reviews from at least one requested reviewer area: @angular/build target: minor This PR is targeted for the next minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant