Skip to content

chore(deps): upgrade oxc to 0.138.0 and migrate to per-type AST construction#10018

Merged
shulaoda merged 1 commit into
mainfrom
upgrade-oxc-0.138
Jun 30, 2026
Merged

chore(deps): upgrade oxc to 0.138.0 and migrate to per-type AST construction#10018
shulaoda merged 1 commit into
mainfrom
upgrade-oxc-0.138

Conversation

@shulaoda

Copy link
Copy Markdown
Member

What this PR does

Upgrades oxc 0.137.00.138.0 and migrates all AST construction to oxc's new per-type constructor API.

oxc 0.138 (oxc#23043) replaced the AstBuilder construction methods (builder.alloc_foo(..), builder.expression_call(..), builder.vec(), ...) with per-type constructors that take the builder/allocator as the last argument. This PR bumps oxc and moves rolldown off the deprecated API so it no longer emits deprecation warnings.

Changes

  • Deps: oxc crates 0.137.00.138.0 (cargo + npm catalog); phf 0.130.14 with the macros feature (the previous build only got phf_map! via feature unification through oxc's own phf 0.13, which is gone).
  • 0.138 breaking-change fixes:
    • Arena methods (take_in, take_in_box, ArenaVec::new_in, ArenaBox::new_in) now take &impl GetAllocator — call sites pass &handle.
    • ConstantEvaluationCtx dropped its ast() method in favor of GetAstBuilder + GetAllocator supertraits (ast_scanner/const_eval.rs).
  • AST construction migration (~613 call sites across 20 files):
    • Generic nodes now use per-type constructors: Foo::new(.., &ast_factory) / Foo::boxed(..), oxc::allocator::Vec::*_in, Str::from_str_in.
    • AstFactory now implements GetAstBuilder + GetAllocator and drops its Deref to AstBuilder; make_* method bodies pass self. This keeps construction funnelled through the single AstFactory chokepoint, as described in internal-docs/ast-construction.
  • Regenerated embedded @oxc-project/runtime helpers (version string only).
  • Updated internal-docs/ast-construction/implementation.md to describe the new per-type API and the dropped Deref.

For reviewers

  • The bulk of the diff is the mechanical builder.method(..)Type::new_*(.., &handle) rewrite. The interesting part is crates/rolldown_ecmascript_utils/src/ast_factory.rs (trait impls, Deref removal, make_* bodies).
  • Snapshots are unchanged — the new constructors produce identical AST, so this is behavior-preserving.

Testing

  • just roll was green (clippy --deny warnings + full Rust/Node test suites, snapshots unchanged) before rebasing onto latest main.
  • After rebasing onto latest main, cargo check --workspace is clean (0 errors, 0 deprecation warnings).

…ruction

oxc 0.138 (oxc#23043) replaced the AstBuilder construction methods with
per-type constructors. This bumps oxc and migrates all AST construction to the
new API so the deprecated builder methods are no longer used.

- Bump oxc crates 0.137.0 -> 0.138.0 (cargo + npm); phf 0.13 -> 0.14 (macros feature)
- Fix 0.138 breaking changes: arena methods (take_in/new_in/...) now take
  `&impl GetAllocator`; `ConstantEvaluationCtx` gains `GetAstBuilder` +
  `GetAllocator` supertraits in place of its `ast()` method
- Migrate ~613 construction sites to per-type constructors
  (`Foo::new`/`Foo::boxed`, `oxc::allocator::Vec::*_in`, `Str::from_str_in`)
- `AstFactory` now implements `GetAstBuilder` + `GetAllocator` and drops its
  `Deref` to `AstBuilder`; `make_*` method bodies pass `self`
- Regenerate embedded runtime helpers; update internal-docs/ast-construction
@netlify

netlify Bot commented Jun 30, 2026

Copy link
Copy Markdown

Deploy Preview for rolldown-rs canceled.

Name Link
🔨 Latest commit b1e4850
🔍 Latest deploy log https://app.netlify.com/projects/rolldown-rs/deploys/6a433667de27420008f51871

@codspeed-hq

codspeed-hq Bot commented Jun 30, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 7 untouched benchmarks
⏩ 10 skipped benchmarks1


Comparing upgrade-oxc-0.138 (b1e4850) with main (35ac2e0)

Open in CodSpeed

Footnotes

  1. 10 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@sapphi-red sapphi-red 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 only checked the files that is marked as the code owner)

@shulaoda shulaoda self-assigned this Jun 30, 2026
@shulaoda
shulaoda merged commit aa32751 into main Jun 30, 2026
35 checks passed
@shulaoda
shulaoda deleted the upgrade-oxc-0.138 branch June 30, 2026 06:00
@overlookmotel

Copy link
Copy Markdown
Collaborator

Out of interest, did you use the codemod? Or by hand (or LLM's hand)?

@shulaoda

Copy link
Copy Markdown
Member Author

Out of interest, did you use the codemod? Or by hand (or LLM's hand)?

I used claude code. Using the skill upgrade-oxc first and then I told cc to migrate the new AST construction.

@rolldown-guard rolldown-guard Bot mentioned this pull request Jul 1, 2026
shulaoda added a commit that referenced this pull request Jul 1, 2026
## [1.1.4] - 2026-07-01

### 🚀 Features

- disable `experimental.lazyBarrel` by default (#10071) by @shulaoda

### 🐛 Bug Fixes

- dev: disable lazy barrel in dev mode (#10060) by @shulaoda
- generate: keep full JSON interface under preserveModules namespa… (#10056) by @IWANABETHATGUY
- check finalize_other_specifiers in its own Debug attribute (#10032) by @shulaoda
- serialize the KeepAssign unused minify option as "keep_assign" (#10031) by @shulaoda
- keep fragments after the newline fragment in MagicString::last_line (#10023) by @shulaoda
- generate: undeclared JSON named exports under preserveModules (#10020) (#10027) by @IWANABETHATGUY
- deconflict: rename CJS-wrapped locals that shadow chunk-root bindings (#9921) by @IWANABETHATGUY
- rolldown: keep entry facade when a shared chunk holds another entry's module (#9997) by @hyf0
- treeshake: also bail JSON default split when the object escapes (#9996) by @IWANABETHATGUY
- don't classify await in a strict-mode function as top-level await (#9987) by @shulaoda
- avoid spurious leading newline in addon hooks (banner/footer/intro/outro) (#9989) by @shulaoda
- handle JSON default mutation bailouts (#9972) by @TheAlexLichter
- plugin: make lazy hook metadata enumerable (#9991) by @TheAlexLichter
- dev: make init errors in lazy-compiled modules catchable (#9981) by @h-a-n-a
- treeshake: keep computed-key side effects on namespace member access (#9986) by @shulaoda
- binding: validate replace plugin delimiters length instead of panicking (#9984) by @shulaoda
- reconstruct nested rest patterns in into_expression (#9980) by @IWANABETHATGUY
- reconstruct rest patterns as spread in into_expression (#9976) by @shulaoda
- preserve export keyword on multi-declarator exports under keepNames (#9974) by @shulaoda
- deterministically keep the shortest name for deduplicated assets (#9948) by @x1024
- treeshake: apply @__NO_SIDE_EFFECTS__ to cross-chunk namespace calls (#9960) by @IWANABETHATGUY

### 🚜 Refactor

- drop redundant program scope enter/leave in finalizer (#10049) by @shulaoda
- deconflict: extract collect_chunk_scope_captured_names (#10006) by @IWANABETHATGUY
- unify pre-scan multi-declarator split into one decision site (#9982) by @IWANABETHATGUY
- common: return bool from SymbolRef::is_not_reassigned (#9962) by @IWANABETHATGUY

### 📚 Documentation

- rolldown: remove outdated comment for removing parenthesized expression (#10062) by @Dunqing
- use GitHub-flavored alert for Etiquette note in contribution guide (#10012) by @IWANABETHATGUY
- replace: explain the delimiters left and right boundaries (#9985) by @shulaoda
- ast-mutation: remove stale Address Use section after pre-scan refactor (#9983) by @IWANABETHATGUY
- remove fathom (#9968) by @mdong1909
- contribution-guide: code-format main branch references (#9966) by @IWANABETHATGUY
- contribution-guide: fix stale REPL note and tidy wording (#9957) by @hyf0
- contribution-guide: clarify when to discuss before opening a PR (#9955) by @hyf0

### ⚡ Performance

- disable preserve_parens across all parse paths (#10057) by @Dunqing
- common: inline declared_symbols with SmallVec (#9920) by @IWANABETHATGUY
- common: pack TaggedSymbolRef into 8 bytes (#9919) by @IWANABETHATGUY
- sourcemap: skip newline scan on the no-sourcemap join fast path (#9936) by @Boshen

### 🧪 Testing

- dev: error in lazy module should be catchable (#9975) by @sapphi-red
- dev: reject unknown lazy compile modules (#9969) by @sapphi-red

### ⚙️ Miscellaneous Tasks

- deps: update actions/cache action to v6 (#10001) by @renovate[bot]
- trigger vite ecosystem-ci from PR comments (#10058) by @shulaoda
- deps: update napi to v3.10.0 (#10063) by @renovate[bot]
- remove unused From impl for RolldownLabelSpan (#10055) by @shulaoda
- remove dead Diagnostic::with_kind method (#10054) by @shulaoda
- remove unused StatementExt methods (#10053) by @shulaoda
- remove unused ExpressionExt methods (#10052) by @shulaoda
- remove commented-out re_export_all_names field (#10051) by @shulaoda
- deps: update pnpm to v11.9.0 (#10047) by @renovate[bot]
- remove the unused BindingGenerateHmrPatchReturn napi type (#10034) by @shulaoda
- remove the dead inline_entry_chunk_wrapping scaffolding (#10037) by @shulaoda
- deps: bump oxc_resolver to 11.22.0 (#10045) by @Boshen
- remove never-constructed MatchImportKind::_Ignore variant (#10041) by @shulaoda
- remove the unused ScheduledBuild napi struct (#10033) by @shulaoda
- remove dead compute_hmr_update_single method (#10040) by @shulaoda
- drop the redundant visited.insert in manual code splitting (#10038) by @shulaoda
- remove the dead output_assets vector in render_chunk_to_assets (#10036) by @shulaoda
- remove the unused From<String>/Display impls for BindingLogLevel (#10035) by @shulaoda
- deps: upgrade oxc to 0.138.0 and migrate to per-type AST construction (#10018) by @shulaoda
- deps: update rust crates (#9911) by @renovate[bot]
- deps: update test262 submodule for tests (#10016) by @rolldown-guard[bot]
- deps: update github actions (#9999) by @renovate[bot]
- deps: update npm packages (#10000) by @renovate[bot]

### ◀️ Revert

- "fix(plugin): make lazy hook metadata enumerable (#9991)" (#10005) by @shulaoda

### ❤️ New Contributors

* @x1024 made their first contribution in [#9948](#9948)

Co-authored-by: shulaoda <[email protected]>
graphite-app Bot pushed a commit that referenced this pull request Jul 24, 2026
Follow-on after #10018.

First of a series of PRs all grouped around 2 themes:

1. Shorten code using AST builder methods.
2. Reduce string allocations.

The new AST builder methods allow shortened syntax. Utilize the shorter methods wherever possible.

Before:

```rust
ast::Statement::ExpressionStatement(ast::ExpressionStatement::boxed(span, call_expr, &self.ast_builder))
```

After:

```rust
ast::Statement::new_expression_statement(span, call_expr, &self.ast_builder)
```

Note: Diff is quite large, but these changes were almost entirely produced using the same [deterministic codemod](https://github.com/oxc-project/oxc/tree/overlookmotel/ast-builder-codemod) we used to migrate Oxc repo to new AST builder, with only some final tweaks by an LLM. I've reviewed it all and, even though I'm unfamiliar with Rolldown's codebase, I'm pretty confident it looks correct.
graphite-app Bot pushed a commit that referenced this pull request Jul 24, 2026
Follow-on after #10018.

The new AST builder methods allow passing arrays where a `Vec` is required. Use this facility to remove a lot of repetitious boilerplate.

Before:

```rust
FunctionBody::new(
  SPAN,
  oxc::allocator::Vec::new_in(&self.ast_builder),
  oxc::allocator::Vec::from_value_in(try_stmt, &self.ast_builder),
  &self.ast_builder,
)
```

After:

```rust
FunctionBody::new(SPAN, [], [try_stmt], &self.ast_builder)
```

Note: Like #10418, diff is quite large, but these changes were almost entirely produced using the same [deterministic codemod](https://github.com/oxc-project/oxc/tree/overlookmotel/ast-builder-codemod) we used to migrate Oxc repo to new AST builder, with only some final tweaks by an LLM. I've reviewed it all and, even though I'm unfamiliar with Rolldown's codebase, I'm pretty confident it looks correct.
graphite-app Bot pushed a commit that referenced this pull request Jul 24, 2026
Follow-on after #10018.

AST builder methods accept any type which is `Into<Str<'ast>>` for `Str` fields. This includes `&'static str`s. Where we have a `&'static str`, pass it directly to the builder method, rather than via `Str::from_str_in`.

This avoids unnecessarily allocating the string into the arena. As a side effect, it also makes the code shorter and more readable.

Before:

```rust
ast::BindingPattern::new_binding_identifier(
  SPAN,
  ast::Str::from_str_in("m", &self.ast_builder),
  &self.ast_builder,
)
```

After:

```rust
ast::BindingPattern::new_binding_identifier(SPAN, "m", &self.ast_builder)
```
graphite-app Bot pushed a commit that referenced this pull request Jul 24, 2026
)

Follow-on after #10018, continuation of #10420.

Custom AST builder methods (previously methods of `AstFactory`) take `&str`s. They allocate the string into arena, to obtain a `&'ast str` (allocator lifetime). Where the string is a `&'static str`, it's unnecessary to allocate into arena to extend the lifetime.

In these cases, use standard AST builder methods provided by Oxc, and skip the allocation.

Before:

```rust
BindingIdentifier::new_id(SPAN, "__rolldown_default__", &self.ast_builder)
```

After:

```rust
BindingIdentifier::new(SPAN, "__rolldown_default__", &self.ast_builder)
```
graphite-app Bot pushed a commit that referenced this pull request Jul 24, 2026
Follow-on after #10018, continuation of #10420 and #10421.

When converting `&'static str`s to `Str`s, use `Str::from` instead of `Str::from_str_in`. The difference is that `from_str_in` performs an allocation (in arena), whereas `from` is a zero-cost no-op conversion at runtime. When the `&str` already has a `'static` lifetime, it's unnecessary to extend it by allocating it into arena.

Before:

```rs
TemplateElementValue {
  raw: Str::from_str_in("/@vite/lazy?id=", &self.ast_builder),
  cooked: None,
}
```

After:

```rs
TemplateElementValue { raw: Str::from("/@vite/lazy?id="), cooked: None }
```
graphite-app Bot pushed a commit that referenced this pull request Jul 24, 2026
Follow-on after #10018, continuation of #10420 and #10421.

Where we already have a `Str<'ast>` or `Ident<'ast>`, avoid converting it into a `&str` and then allocating it back into arena again to convert back to `Str` or `Ident`. Just re-use the existing `Str` / `Ident`. This avoids unnecessary arena allocations, and in the case of `Ident`, it avoids re-hashing the string too.
graphite-app Bot pushed a commit that referenced this pull request Jul 24, 2026
Follow-on after #10018 and #10353. Pure refactor.

Implement `GetAstBuilder` and `GetAllocator` on visitor/pass/context types which hold an `AstBuilder`.

AST builder methods take any `&B where B: GetAstBuilder`, so this allows removing a lot of repetitious boilerplate code at call sites.

Before:

```rust
Expression::new_string_literal(
  SPAN,
  Str::from_str_in(id, &self.ast_builder),
  None,
  &self.ast_builder,
)
```

After:

```rust
Expression::new_string_literal(SPAN, Str::from_str_in(id, self), None, self)
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants