Skip to content

feat(@angular/build): migrate Angular Linker to oxc-parser and magic-string - #33625

Open
clydin wants to merge 1 commit into
angular:mainfrom
clydin:feat/linker-oxc-migration
Open

feat(@angular/build): migrate Angular Linker to oxc-parser and magic-string#33625
clydin wants to merge 1 commit into
angular:mainfrom
clydin:feat/linker-oxc-migration

Conversation

@clydin

@clydin clydin commented Jul 22, 2026

Copy link
Copy Markdown
Member

This refactors the Angular linker processing in the ESBuild pipeline to use oxc-parser and magic-string instead of @babel/core.

By using the lightweight AST and precise token spans provided by OXC, the linker is able to process partial declarations via targeted magic-string overwrites in-place. This removes the dependency on @babel/core and the linker Babel plugin, yielding faster build startup times and improved compilation performance.

@angular-robot angular-robot Bot added detected: feature PR contains a feature commit area: @angular/build labels Jul 22, 2026
@clydin
clydin force-pushed the feat/linker-oxc-migration branch from 89f575b to a1a721b Compare July 22, 2026 16:40
@clydin
clydin marked this pull request as ready for review July 23, 2026 19:03

@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 introduces a high-performance Angular partial declaration linker using oxc-parser and magic-string to replace the Babel-based linker. The review feedback highlights critical compatibility issues with the OXC AST structure. Specifically, oxc-parser does not export a Visitor class, requiring a custom recursive AST walker instead. Additionally, OXC AST node types differ from standard ESTree nodes: generic Literal nodes are represented as specific StringLiteral, NumericLiteral, BooleanLiteral, and NullLiteral nodes; identifiers are split into IdentifierReference and IdentifierName; and object properties are represented as ObjectProperty instead of Property.

Comment thread packages/angular/build/src/tools/angular/linker/oxc-linker.ts
Comment thread packages/angular/build/src/tools/angular/linker/oxc-linker.ts
Comment thread packages/angular/build/src/tools/angular/linker/oxc-ast-host.ts
Comment thread packages/angular/build/src/tools/angular/linker/oxc-ast-host.ts
Comment thread packages/angular/build/src/tools/angular/linker/oxc-ast-host.ts
Comment thread packages/angular/build/src/tools/angular/linker/oxc-ast-host.ts
Comment thread packages/angular/build/src/tools/angular/linker/oxc-ast-host.ts
Comment thread packages/angular/build/src/tools/angular/linker/oxc-ast-host.ts
Comment thread packages/angular/build/src/tools/angular/linker/oxc-ast-host.ts
Comment thread packages/angular/build/src/tools/angular/linker/oxc-ast-host.ts Outdated
@clydin clydin added the target: minor This PR is targeted for the next minor release label Jul 23, 2026
@clydin
clydin requested a review from alan-agius4 August 1, 2026 17:27
@clydin clydin added the action: review The PR is still awaiting reviews from at least one requested reviewer label Aug 1, 2026

@JoostK JoostK left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I've been wanting to experiment with this, so I'm excited to see this 🥳

Comment thread packages/angular/build/src/tools/angular/linker/oxc-linker.ts Outdated

class InlineDeclarationScope implements DeclarationScope<unknown, unknown> {
getConstantScopeRef(): null {
return null;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This works, but has the downside of pushing the constant pool in a local IIFE for each declaration, instead of sharing a single pool per module. Especially for library FESMs I'd expect this to introduce a bit of code-size overhead (due to inability to share constants across declarations).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

There is the potential for the raw output sizes to be slightly larger. However, the over-the-wire (compressed) sizes should be nearly identical. The local IIFE also has DCE advantages since a single pass will remove the unused constants. Shared constants of a significant size are typically going to be rare as well.

Comment thread packages/angular/build/src/tools/angular/linker/string-ast-factory.ts Outdated
Comment thread packages/angular/build/src/tools/angular/linker/string-ast-factory.ts Outdated
Comment thread packages/angular/build/src/tools/angular/linker/string-ast-factory.ts Outdated
node: T,
_sourceMapRange: SourceMapRange | null,
): T {
return node;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This probably means that compiled template code won't be mapped into its original external file mappings.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes. However, vendor source maps are typically not enabled so there would be no effective loss for the common case. In a followup, we can add a segment-based string factory that could be enabled for vendor source map cases though.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah, this is fine as follow-up 👍

@clydin
clydin force-pushed the feat/linker-oxc-migration branch 2 times, most recently from 9118d3c to b7fb852 Compare August 3, 2026 15:30
Comment thread packages/angular/build/src/tools/angular/linker/string-ast-factory.ts Outdated
…string

This refactors the Angular linker processing in the ESBuild pipeline to use `oxc-parser` and `magic-string` instead of `@babel/core`.

By using the lightweight AST and precise token spans provided by OXC, the linker is able to process partial declarations via targeted `magic-string` overwrites in-place. This removes the dependency on `@babel/core` and the linker Babel plugin, yielding faster build startup times and improved compilation performance.
@clydin
clydin force-pushed the feat/linker-oxc-migration branch from b7fb852 to 7517eb6 Compare August 3, 2026 16:23
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 detected: feature PR contains a feature commit target: minor This PR is targeted for the next minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants