fix: emit async wrapper for TLA modules under onDemandWrapping#10086
Conversation
How to use the Graphite Merge QueueAdd the label graphite: merge-when-ready to this PR to add it to the merge queue. You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
9897950 to
fdb678e
Compare
67054c1 to
c9f92db
Compare
c9f92db to
f084ccc
Compare
✅ Deploy Preview for rolldown-rs canceled.
|
f084ccc to
72350c6
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
Merge activity
|
### What this PR solves
Under `experimental.onDemandWrapping`, the concatenated module-group wrapper — the single `__esm` closure holding the bodies of every module in a merged group — was always emitted as a sync arrow. When the group's entry is TLA-tainted (has top-level `await`, or awaits a TLA importee's `init` call), those `await`s land inside that closure, producing a chunk with `await` in a non-async function: a SyntaxError at load.
```js
// before
var init_entry = __esm(() => {
...
await init_dep(); // SyntaxError: await outside async function
});
// after
var init_entry = __esm(async () => {
...
await init_dep();
});
```
### How
One render change in `render_chunk_content` (`crates/rolldown/src/ecmascript/format/esm.rs`): emit `async () => {` when `metas[group.entry].is_tla_or_contains_tla_dependency`. This mirrors the `is_async` flag already threaded into `make_esm_wrapper_stmt` for the non-concatenated (single-module) wrapper path — the concatenated group path just never received it.
### Tests
Added `{ "strictExecutionOrder": true, "onDemandWrapping": true }` config variants to the TLA fixtures so the emitted syntax is pinned by snapshots (and executed):
- `issues/9083`
- `topics/tla/on_demand_await_call`
- `topics/tla/transitive_dep`
- `function/experimental/on_demand_wrapping/top_level_await_syntax`
Each fails on main with the sync closure and passes with this change.
72350c6 to
bc6ce75
Compare

What this PR solves
Under
experimental.onDemandWrapping, the concatenated module-group wrapper — the single__esmclosure holding the bodies of every module in a merged group — was always emitted as a sync arrow. When the group's entry is TLA-tainted (has top-levelawait, or awaits a TLA importee'sinitcall), thoseawaits land inside that closure, producing a chunk withawaitin a non-async function: a SyntaxError at load.How
One render change in
render_chunk_content(crates/rolldown/src/ecmascript/format/esm.rs): emitasync () => {whenmetas[group.entry].is_tla_or_contains_tla_dependency. This mirrors theis_asyncflag already threaded intomake_esm_wrapper_stmtfor the non-concatenated (single-module) wrapper path — the concatenated group path just never received it.Tests
Added
{ "strictExecutionOrder": true, "onDemandWrapping": true }config variants to the TLA fixtures so the emitted syntax is pinned by snapshots (and executed):issues/9083topics/tla/on_demand_await_calltopics/tla/transitive_depfunction/experimental/on_demand_wrapping/top_level_await_syntaxEach fails on main with the sync closure and passes with this change.