fix(dev): keep lazy handlers code-split so import-time errors surface correctly (v2) - #4458
fix(dev): keep lazy handlers code-split so import-time errors surface correctly (v2)#4458hiranuma wants to merge 1 commit into
Conversation
…rrectly In dev, the nitro-dev preset set Rollup's `inlineDynamicImports: true`, inlining every lazy server handler into a single `index.mjs` and evaluating each module eagerly at that bundle's top level. When one server module throws at import time, the whole bundle's evaluation aborts after the HTTP server has already started listening, leaving unrelated `const`s (e.g. `renderer`) in the temporal dead zone. Every request then fails with a misleading `Cannot access '<x>' before initialization` while the real error is only logged once as an uncaughtException. Keeping lazy handlers as real, code-split dynamic imports isolates an import-time failure to its own route and reports the real error. Refs: nitrojs#1670, nuxt/nuxt#20576, sidebase/nuxt-auth#271
|
Someone is attempting to deploy a commit to the Nitro Team on Vercel. A member of the Team first needs to authorize it. |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🔗 Linked issue
Fixes #4435 (for v2).
📚 Description
In dev, the
nitro-devpreset sets RollupinlineDynamicImports: true, which inlines everylazy server handler into the single
.nitro/dev/index.mjsand evaluates each handler moduleeagerly at that bundle's top level. When one server module throws at import
(evaluation) time, evaluation aborts after
server.listen()has already run, leavingunrelated later
consts (e.g.renderer) permanently in the temporal dead zone. Everyrequest then fails with a misleading
Cannot access '<x>' before initialization, while thereal error is only logged once at startup as an
uncaughtException.This has caused a long tail of reports that were closed as "circular dependency in user
code": #1670, nuxt/nuxt#20576, sidebase/nuxt-auth#271.
Fix: set
inlineDynamicImports: falsefor thenitro-devpreset so lazy handlers staygenuinely code-split in dev. An import-time failure is then isolated to its own route and
surfaces the real error instead of poisoning unrelated ones.
Behaviour, before → after (minimal repro: a healthy
/okroute + a/boomroute that throwsat import time):
GET /ok(unrelated)500 Cannot access 'ok_get$1' before initialization200 {"ok":true}GET /boom500 Cannot access 'ok_get$1' before initialization500with the real error atroutes/boom.get.ts🧪 Verification / scope note
test/unit/dev-import-error.test.ts+ fixture) that fails before /passes after this change.
baseline — zero regressions); with the added test the branch runs 643 / 0.
// externals plugin limitationconcern doesn't reproduce in the currentsuite with code-splitting on, but I'd welcome a maintainer's read on whether there are
externals scenarios the fixture doesn't cover.
Why this targets
v2and notmain: the misleading-TDZ behaviour is v2-specific. Iverified on
main(v3) that the bug does not reproduce — with the default rolldown devbuilder an import-time throw is already isolated (
/ok→ 200) and reports the real error, andwith the rollup builder the dev worker fails fast with the real error (503), never the TDZ. On
v3 this same
inlineDynamicImports: falsechange is a no-op for rolldown and actually breaksthe rollup build (
Cannot read properties of null (reading 'getVariableForExportName')). Sothe fix belongs on v2, where users on current Nuxt (
@nuxt/nitro-server→nitropack@^2)actually hit it. (Context on the parallel v3 PR: #4436.)