Skip to content

fix(devtools): stop inlining every dependency into the Nitro v2 dev bundle - #1109

Merged
antfu merged 4 commits into
nuxt:mainfrom
antfubot:fix/nitro-v2-externals
Oct 6, 2026
Merged

antfu merged 4 commits into
nuxt:mainfrom
antfubot:fix/nitro-v2-externals

Conversation

@antfubot

@antfubot antfubot commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #1107.

Found while re-running the ecosystem playground on Nuxt 4.5 for the stable release. The nitro:config hook in module-main.ts sets noExternals = [<runtime/nitro>] whenever the key is absent. That is the Nitro v3 spelling; on Nitro v2 (nitropack, i.e. every Nuxt 4 app) noExternals is a boolean, so a non-empty array is truthy and Nitro bundles the entire dependency graph into the dev server (Cannot resolve … and externals are not allowed!).

Small apps only got slower, which is why the minimal playgrounds-ecosystem/nuxt4 app still passed. The combined ecosystem app failed outright: nuxt-og-image resolved playwright and Nitro died on electron/index.js, and even without that the inlined vite-node debug shim crashed the server with globalNamespaces.trim is not a function.

Nuxt 4 always provides externals.inline and never noExternals; Nuxt 5 does the reverse. The hook now branches on that shape instead of falling through to the v3 path. Covered by a unit test for both shapes (the fakeNuxt harness from devtools-origin.test.ts is shared for it), and verified by booting the nuxt4 and nuxt5 playgrounds plus the full ecosystem Playwright suite (follow-up PR).

Created with the help of an agent.

…rver boots

Since a1fcef8 the catalog resolves nitro 3.0.260903-beta while the pinned
Nuxt nightly still depended on 3.0.260610-beta. With two Nitro copies
installed, Nuxt's nitro:dev-service-proxy fails to load nitro/h3 from the
second one and every dev server in the repo 500s, which is why e2e has
hung and been cancelled on every run since.

Move to the current Nuxt nightly, which depends on nitro 260903 itself,
and drop the 260610 patch: 260903 already skips the nitro build for static
generates upstream.
Its nuxi prepare now declares every #build template as an ambient module
and resolves #imports for real, so the ts-expect-error on the settings
import becomes unused and the client plugin's inferred type cycles
through the composables it calls.
@socket-security

socket-security Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatednuxt-nightly@​5.0.0-29806258.d070492f ⏵ 5.0.0-2610052343-36eafab96 +2100100 +197100
Updated@​nuxt/​kit-nightly@​5.0.0-29806258.d070492f ⏵ 5.0.0-2610052343-36eafab97 +3100100 +197100
Updated@​nuxt/​schema-nightly@​5.0.0-29806258.d070492f ⏵ 5.0.0-2610052343-36eafab97 +4100100 +197100

View full report

@coderabbitai

coderabbitai Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 93ddd860-aeca-4b7b-801d-74cd6a0be5d1
📥 Commits

Reviewing files that changed from the base of the PR and between 3c38af2 and 2681ffc.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • packages/devtools/package.json
  • packages/devtools/src/runtime/settings.ts
  • turbo.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/devtools/src/runtime/settings.ts

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The Nitro v2 and v3 configuration branches now handle the inline runtime path separately, with tests covering both versions. The client plugin uses a Nuxt Plugin-typed constant, and the DevTools origin test uses a shared Nuxt fixture. Workspace overrides now target a different Nuxt nightly build, and the Nitro patch and its configuration have been removed.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 2681f

No material merge-blocking issue was established. The supported Nitro configuration and tracked client build path retain the required behavior.

Architecture Summary

Architecture risk: 🔵 Low · up to 2681f

The change affects 4 systems.

Changed systems: packages/devtools, patches, pnpm-workspace.yaml, turbo.json

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — packages/devtools (library) was modified; 7 changed files map to changed impact.
  • observed — patches (service) was modified; 1 changed file maps to changed impact.
  • observed — pnpm-workspace.yaml (service) was modified; 1 changed file maps to changed impact.
  • observed — turbo.json (service) was modified; 1 changed file maps to changed impact.

Before / after behavior

  • observed — Modified behavior in packages/devtools/src/module-main.ts: The Nitro v2 externals.inline handling is unchanged. For Nitro v3, the code now checks Array.isArray(config.noExternals) directly and initializes noExternals only when it is undefined. This replaces the previous property-presence check and separate if, so the noExternals handling is mutually exclusive with the externals branch; configurations with externals no longer also update noExternals.
  • observed — Modified behavior in packages/devtools/src/runtime/plugins/devtools.client.ts: Adds the Plugin type import from nuxt/app.
  • observed — Modified behavior in packages/devtools/src/runtime/plugins/devtools.client.ts: Adds a comment about Nuxt injection typing and assigns the defineNuxtPlugin result to a constant annotated as Plugin, replacing the inline default-exported plugin declaration.
  • observed — Modified behavior in packages/devtools/src/runtime/plugins/devtools.client.ts: Adds a default export of the typed plugin constant.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 6 files. (2 skipped: 2… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: preventing Nitro v2 from inlining every dependency into the dev bundle.
Description check ✅ Passed The description explains the Nitro v2 configuration issue, the fix, and the tests and validation reported for the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 6 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

build:client re-stubbed @nuxt/devtools through dev:prepare after turbo
had already built it, so a root pnpm build left a jiti stub in dist. The
published package was unaffected (prepack builds only the module), but
everything packing after a root build shipped the stub. The client only
needs the built module for types, which turbo already orders first.

Also use ts-ignore for the #build/devtools/settings import: whether nuxi
prepare declares it depends on the setup, so ts-expect-error fails in one
environment or the other.
…undle

The nitro:config hook set noExternals to a list whenever the key was
absent. That is the Nitro v3 spelling; on Nitro v2 (nitropack, every
Nuxt 4 app) noExternals is a boolean, so a non-empty array is truthy and
Nitro bundles the whole dependency graph into the dev server. Small apps
only got slower; the ecosystem playground failed outright (nuxt-og-image
dragging playwright in, vite-node's debug shim crashing on enable(true)).

Branch on the config shape instead: externals.inline when the config has
externals (v2), the noExternals list otherwise (v3).
@antfubot
antfubot force-pushed the fix/nitro-v2-externals branch from 3c38af2 to 2681ffc Compare October 6, 2026 04:04
@antfu
antfu merged commit 397f9b2 into nuxt:main Oct 6, 2026
8 checks passed
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.

2 participants