perf(turbopack): defer dynamic imports during lazy compilation - #181
Draft
fireairforce wants to merge 10 commits into
Draft
perf(turbopack): defer dynamic imports during lazy compilation#181fireairforce wants to merge 10 commits into
fireairforce wants to merge 10 commits into
Conversation
Squash the 16 utoo-specific commits into one integration commit while preserving the existing tree.
* fix(turbopack): preserve lazy asset graph state * fix(turbopack): narrow lazy asset state retention
Behind `experimental.turbopackLazyDynamicImports`, a dynamic import in the client graph is no longer compiled until the browser actually reaches it. `EsmAsyncAssetReference` wraps each resolved target in a `LazyCompilationProxyModule`. While the proxy is inactive it reports no references, so the target is never traversed and never compiled; the import resolves to a rejected promise that names the module, which is only reachable through a stale cache. Activation travels over the request the runtime already makes. Dev builds route async imports through a manifest chunk, and the proxy's manifest chunk carries the key that activates it in its file name, so the dev server can recover the key from the requested path alone: no index has to be maintained on the side, and the mapping survives a restart against a warm cache. The dev server intercepts the request, flips one activation bit, rebuilds the owning entrypoints, and only then serves the freshly written chunk. Because the manifest chunk's name does not depend on the activation bit, the URL the browser asked for is the file it receives.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What?
Add an opt-in, framework-agnostic lazy-compilation boundary for client dynamic imports:
This is adapted from vercel#97203, but intentionally excludes the Next.js configuration, server, NAPI, and framework-specific E2E integration. Utoo performs request activation through its own generic development asset server in utooland/utoo#3298.
Why?
Request-driven output serving alone avoids eagerly materializing every output asset, but Turbopack still discovers and analyzes dynamic-import targets while constructing the initial client graph. Large documentation applications such as Ant Design therefore continue to spend most of startup in module resolution, transforms, and analysis for routes that the browser has not opened.
With this change, those dynamic targets remain unresolved until their runtime manifest is requested.
Ant Design uncached local measurements on the same machine:
The first page intentionally pays for the dynamic modules it actually uses, but the full start-to-usable path remains substantially faster.
How?
LazyCompilationProxyModulestarts without a target reference. Requesting its manifest chunk recovers the activation key, flips the independently memoizedLazyCompilationState, and invalidates only that proxy. The activated proxy then resolves the original import and exposes the real target to chunking. Dynamic HMR chunk lists keep subsequent updates scoped to the loaded import.The outer proxy/module/chunk graph remains evictable. Only the tiny activation state uses
evict = "never", matching the lifecycle boundary used by the upstream proposal.Validation
cargo check -p pack-napiConsumer PR: utooland/utoo#3298
Upstream proposal: vercel#97203