Skip to content

Turbopack: preserve chunk load promise identity - #100421

Merged
lukesandberg merged 3 commits into
canaryfrom
fleet/turbopack-ensure-chunk-promise-identity
Oct 21, 2026
Merged

lukesandberg merged 3 commits into
canaryfrom
fleet/turbopack-ensure-chunk-promise-identity

Conversation

@lukesandberg

@lukesandberg lukesandberg commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

#98836 added an on-demand __turbopack_ensure_chunk__ hook to the Turbopack Node dev runtime by overriding __turbopack_context__.l. The override returned ensured.then(() => loadChunkAsync(...)), so every call that hit a not-yet-cached chunk produced a new promise, and the first caller's promise never matched the one later callers got from chunkCache. That broke referential identity for __next_chunk_load__ (which wraps .l), which React relies on. It also created extra promises for React's dev async tracking to process.

This change makes loadChunkAsync itself aware of __turbopack_ensure_chunk__:

  • The hook is called synchronously on a cache miss. If it returns undefined (nothing to compile), the chunk is required synchronously and the shared pre-resolved promise is cached, exactly as without the hook.
  • If it returns a promise (the chunk is being compiled on demand), a single ensure → require/install promise is cached in chunkCache immediately. Concurrent and later callers all get the same promise until clearChunkCache().
  • If ensuring the chunk fails (a synchronous throw or an async rejection), the failure is not cached, so the next load retries. require failures stay cached as ChunkLoadError, as before.
  • The separate .l override and chunksBeingEnsured map in dev-base.ts are removed. The Node runtime snapshots are regenerated.

On the Next.js side, the dev hook is now a plain function. It returns synchronously for chunks that aren't lazy-compilation chunks, or that have no matching entries, and returns a promise only when it actually activates a lazy chunk.

Verification

  • pnpm test-dev-turbo test/development/app-dir/lazy-dynamic-imports/lazy-dynamic-imports.test.ts (12/12 pass)

  • A scratch Node script against the generated dev and build runtimes, with a mocked ensure hook. It checks:

    • async ensure: same promise for concurrent and post-settle calls, ensure called once, modules installed only after ensure, and eviction plus retry after an ensure failure
    • sync ensure: modules installed synchronously with the shared resolved promise, and no caching after a synchronous throw
    • cached ChunkLoadError, non-JS chunks, and clearChunkCache reset

    The identity and sync-path checks fail on the previous runtime and pass with this change.

Co-authored-by: Luke Sandberg <210140+lukesandberg@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Tests Passed

Commit: f8e30eb

@github-actions github-actions Bot added created-by: Turbopack team PRs by the Turbopack team. Turbopack Related to Turbopack with Next.js. labels Oct 19, 2026
@lukesandberg
lukesandberg marked this pull request as ready for review October 19, 2026 21:56
vercel-fleet-prod Bot and others added 2 commits October 19, 2026 22:08
Co-authored-by: Luke Sandberg <210140+lukesandberg@users.noreply.github.com>
Co-authored-by: Luke Sandberg <210140+lukesandberg@users.noreply.github.com>
@lukesandberg lukesandberg changed the title Turbopack: preserve chunk load promise identity with on-demand ensure Turbopack: preserve chunk load promise identity Oct 20, 2026
@lukesandberg
lukesandberg enabled auto-merge (squash) October 20, 2026 15:55
@lukesandberg
lukesandberg merged commit 6204bf0 into canary Oct 21, 2026
220 of 223 checks passed
@lukesandberg
lukesandberg deleted the fleet/turbopack-ensure-chunk-promise-identity branch October 21, 2026 19:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

created-by: Turbopack team PRs by the Turbopack team. Turbopack Related to Turbopack with Next.js. type: next

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants