Skip to content

Conversation

@danielroe
Copy link
Member

@danielroe danielroe commented Oct 12, 2025

📚 Description

in preparation for the move to nitro v3 (and also supporting nitro as a vite plugin), this extracts the nitro server implementation in to a separate and configurable @nuxt/nitro-server package.

the idea would be we can allow people to override this package to test nitro v3 early, and we can also disable it automatically (from the vite builder) when enabling nitro as a vite plugin. at that point we will also need to refactor this implementation so we can keep nitro configuration in sync between the nitro-server + vite-builder.

I'm still thinking about the right api for configuring this. server.builder with a bundle export might not be right, and I'd welcome thoughts from the rest of the team. 🙏

cc: @pi0

🚧 TODO

  • add server builder augments to nuxt types

@bolt-new-by-stackblitz
Copy link

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

} catch (error: any) {
await nuxt.callHook('build:error', error)

if (error.toString().includes('Cannot find module \'@nuxt/webpack-builder\'')) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

Comment on lines 4 to 11
server: {
builder: {
$resolve: (val) => {
if (typeof val === 'string') { return val }
return '@nuxt/nitro-server'
},
},
},
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this the right api?

@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 12, 2025

Open in StackBlitz

@nuxt/kit

npm i https://pkg.pr.new/@nuxt/kit@33462

nuxt

npm i https://pkg.pr.new/nuxt@33462

@nuxt/rspack-builder

npm i https://pkg.pr.new/@nuxt/rspack-builder@33462

@nuxt/schema

npm i https://pkg.pr.new/@nuxt/schema@33462

@nuxt/vite-builder

npm i https://pkg.pr.new/@nuxt/vite-builder@33462

@nuxt/webpack-builder

npm i https://pkg.pr.new/@nuxt/webpack-builder@33462

commit: 07ba85b

@codspeed-hq
Copy link

codspeed-hq bot commented Oct 12, 2025

CodSpeed Performance Report

Merging #33462 will not alter performance

Comparing refactor/nuxt-nitro (07ba85b) with main (3c38d1f)

Summary

✅ 10 untouched

@danielroe danielroe marked this pull request as ready for review October 13, 2025 19:58
@coderabbitai
Copy link

coderabbitai bot commented Oct 13, 2025

Walkthrough

Adds a standalone Nitro server package (packages/nitro-server) with build config, utilities, templates and TS type generation. Moves Nitro bootstrap entry from initNitro to bundle and wires a new Nuxt server orchestrator (bundleServer) that dynamically loads server builders. Shifts many Nuxt-internal type imports to nuxt/app and relocates/removes nitropack module augmentations from Nuxt to the nitro-server template. Adds schema support for server.builder with a resolver defaulting to '@nuxt/nitro-server'. Updates UI template paths and gitignore/templates for Nitro runtime.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly describes the primary change by naming the refactor of Nitro into a separate @nuxt/nitro-server package and follows conventional formatting. It is concise, specific, and clearly captures the main purpose of the pull request.
Description Check ✅ Passed The pull request description clearly explains the motivation, scope, and intended usage of extracting the Nitro server implementation into its own package, and it aligns directly with the summary of changes. It also outlines future considerations and includes a relevant TODO, making it both descriptive and pertinent to the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/nuxt-nitro

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/nitro-server/src/runtime/utils/renderer/islands.ts (1)

62-86: Escape dynamic values in RegExp to avoid incorrect matches.

uid, clientId, and slot are interpolated into regexes without escaping. If they contain regex meta, replacements may fail or misbehave.

Apply:

+import escapeRE from 'escape-string-regexp'
@@
-      html = html.replace(new RegExp(` data-island-uid="${uid}" data-island-component="${clientId}"[^>]*>`), (full) => {
+      const eUid = escapeRE(uid)
+      const eClientId = escapeRE(clientId)
+      html = html.replace(new RegExp(` data-island-uid="${eUid}" data-island-component="${eClientId}"[^>]*>`), (full) => {
         return full + teleports[key]
       })
@@
-      html = html.replace(new RegExp(` data-island-uid="${uid}" data-island-slot="${slot}"[^>]*>`), (full) => {
+      const eUid2 = escapeRE(uid)
+      const eSlot = escapeRE(slot)
+      html = html.replace(new RegExp(` data-island-uid="${eUid2}" data-island-slot="${eSlot}"[^>]*>`), (full) => {
         return full + teleports[key]
       })
♻️ Duplicate comments (1)
packages/nuxt/types.d.mts (1)

1-1: Mirror of DTS change; verify Nitro typings source.

Same note as in packages/nuxt/types.d.ts: ensure Nitro augmentations are generated from @nuxt/nitro-server.

🧹 Nitpick comments (9)
packages/nitro-server/src/runtime/utils/renderer/build-files.ts (2)

39-44: Avoid relying on hoisting for local renderToString

renderToString is referenced before its declaration. This works due to function hoisting, but moving the declaration above improves clarity and avoids edge cases in transformed output.

-  // Create renderer
-  const renderer = createRenderer(createSSRApp, {
-    precomputed,
-    manifest: import.meta.dev ? await getClientManifest() : undefined,
-    renderToString,
-    buildAssetsURL,
-  })
-
-  type RenderToStringParams = Parameters<typeof _renderToString>
-  async function renderToString (input: RenderToStringParams[0], context: RenderToStringParams[1]) {
+  type RenderToStringParams = Parameters<typeof _renderToString>
+  async function renderToString (input: RenderToStringParams[0], context: RenderToStringParams[1]) {
     const html = await _renderToString(input, context)
     // In development with vite-node, the manifest is on-demand and will be available after rendering
     if (import.meta.dev && process.env.NUXT_VITE_NODE_OPTIONS) {
       renderer.rendererContext.updateManifest(await getClientManifest())
     }
     return APP_ROOT_OPEN_TAG + html + APP_ROOT_CLOSE_TAG
   }
 
+  // Create renderer
+  const renderer = createRenderer(createSSRApp, {
+    precomputed,
+    manifest: import.meta.dev ? await getClientManifest() : undefined,
+    renderToString,
+    buildAssetsURL,
+  })

77-85: Dev parity: update manifest in SPA path with vite-node

SSR updates the manifest post-render in dev with vite-node; SPA path doesn’t. Mirroring the update improves consistency for tools relying on rendererContext.

   const renderer = createRenderer(() => () => {}, {
     precomputed,
     manifest: import.meta.dev ? await getClientManifest() : undefined,
     renderToString: () => spaTemplate,
     buildAssetsURL,
   })
   const result = await renderer.renderToString({})
+  if (import.meta.dev && process.env.NUXT_VITE_NODE_OPTIONS) {
+    renderer.rendererContext.updateManifest(await getClientManifest())
+  }
packages/schema/src/types/schema.ts (1)

1529-1535: Document default and object support for server.builder.

Types allow an object { bundle(nuxt) }, but runtime resolver currently ignores non-string values. Please:

  • Clarify in JSDoc that default is '@nuxt/nitro-server'.
  • Ensure the resolver preserves object builders (see comment in config/nitro.ts).
packages/nuxt/src/core/server.ts (1)

3-3: Tighten server builder typing and remove stray webpack error check

  • The server builder exposes bundle, which doesn't align with NuxtBuilder. Use a local ServerBuilder type instead.
  • The webpack-specific error message is unrelated here; it can confuse users. Let loadServerBuilder raise a contextual error.
  • Prefer unknown in catch.
-import type { Nuxt, NuxtBuilder } from 'nuxt/schema'
+import type { Nuxt } from 'nuxt/schema'
+
+type ServerBuilder = {
+  bundle: (nuxt: Nuxt) => Promise<void> | void
+}

 export async function bundleServer (nuxt: Nuxt) {
   try {
     const { bundle } = !nuxt.options.server.builder || typeof nuxt.options.server.builder === 'string'
       ? await loadServerBuilder(nuxt, nuxt.options.server.builder)
       : nuxt.options.server.builder

     await bundle(nuxt)
-  } catch (error: any) {
+  } catch (error: unknown) {
     await nuxt.callHook('build:error', error)
-
-    if (error.toString().includes('Cannot find module \'@nuxt/webpack-builder\'')) {
-      throw new Error('Could not load `@nuxt/webpack-builder`. You may need to add it to your project dependencies, following the steps in `https://github.com/nuxt/framework/pull/2812`.')
-    }
-
     throw error
   }
 }

-async function loadServerBuilder (nuxt: Nuxt, builder = '@nuxt/nitro-server'): Promise<NuxtBuilder> {
+async function loadServerBuilder (nuxt: Nuxt, builder = '@nuxt/nitro-server'): Promise<ServerBuilder> {
   try {
     return await importModule(builder, { url: [directoryToURL(nuxt.options.rootDir), new URL(import.meta.url)] })
   } catch (err) {
     // TODO: docs
     throw new Error(`Loading \`${builder}\` server builder failed.`, { cause: err })
   }
 }

Also applies to: 5-12, 15-17, 23-30

packages/nitro-server/src/index.ts (1)

128-130: Harden Nuxt version resolution

Wrap readPackageJSON('nuxt', …) to avoid aborting when the package cannot be resolved; you already have a fallback.

-const { version: nuxtVersion } = await readPackageJSON('nuxt', { from: import.meta.url })
+const { version: nuxtVersion } = await readPackageJSON('nuxt', { from: import.meta.url }).catch(() => ({} as any))
packages/nuxt/src/core/nuxt.ts (1)

236-241: Normalise server builder type reference to a relative path

Keep consistency with the Vite builder: if serverBuilderTypePath resolves to an absolute path, convert it to a path relative to buildDir before adding it to TS references.

-const serverBuilderTypePath = typeof nuxt.options.server.builder === 'string'
-  ? nuxt.options.server.builder === '@nuxt/nitro-server'
-    ? resolveModulePath(nuxt.options.server.builder, { from: import.meta.url })
-    : nuxt.options.server.builder
-  : undefined
+const _serverBuilderTypePath = typeof nuxt.options.server.builder === 'string'
+  ? nuxt.options.server.builder === '@nuxt/nitro-server'
+    ? resolveModulePath(nuxt.options.server.builder, { from: import.meta.url })
+    : nuxt.options.server.builder
+  : undefined
+const serverBuilderTypePath =
+  _serverBuilderTypePath && isAbsolute(_serverBuilderTypePath)
+    ? relative(nuxt.options.buildDir, _serverBuilderTypePath)
+    : _serverBuilderTypePath

@@
-  if (serverBuilderTypePath) {
-    opts.references.push({ types: serverBuilderTypePath })
-    opts.nodeReferences.push({ types: serverBuilderTypePath })
-  }
+  if (serverBuilderTypePath) {
+    opts.references.push({ types: serverBuilderTypePath })
+    opts.nodeReferences.push({ types: serverBuilderTypePath })
+  }
@@
-  if (serverBuilderTypePath) {
-    opts.references.push({ types: serverBuilderTypePath })
-  }
+  if (serverBuilderTypePath) {
+    opts.references.push({ types: serverBuilderTypePath })
+  }

Additional import required:

-import { join, normalize, relative, resolve } from 'pathe'
+import { join, normalize, relative, resolve, isAbsolute } from 'pathe'

Also applies to: 266-269, 295-297

packages/nitro-server/src/templates.ts (1)

13-20: Also normalise absolute types references

When types is an absolute path, convert it to a relative path like you do for path.

-  ...references.map((ref) => {
-    if ('path' in ref && isAbsolute(ref.path)) {
-      ref.path = relative(sourceDir, ref.path)
-    }
-    return `/// <reference ${renderAttrs(ref)} />`
-  }),
+  ...references.map((ref) => {
+    if ('path' in ref && isAbsolute(ref.path)) {
+      ref.path = relative(sourceDir, ref.path)
+    }
+    if ('types' in ref && typeof (ref as any).types === 'string' && isAbsolute((ref as any).types)) {
+      (ref as any).types = relative(sourceDir, (ref as any).types)
+    }
+    return `/// <reference ${renderAttrs(ref as any)} />`
+  }),
packages/nitro-server/src/augments.ts (2)

8-20: DRY the duplicated augmentation shapes to prevent drift.

Both 'nitropack' and 'nitropack/types' blocks duplicate identical shapes. Extract local shared types and have each interface extend them.

Apply these interface tweaks inside the listed ranges:

 declare module 'nitropack' {
-  interface NitroRuntimeConfigApp {
-    buildAssetsDir: string
-    cdnURL: string
-  }
-  interface NitroRouteRules {
-    ssr?: boolean
-    noScripts?: boolean
-    /** @deprecated Use `noScripts` instead */
-    experimentalNoScripts?: boolean
-    appMiddleware?: Record<string, boolean>
-  }
+  interface NitroRuntimeConfigApp extends _NitroRuntimeConfigAppFields {}
+  interface NitroRouteRules extends _NitroRouteRulesFields {}
 }
 
 declare module 'nitropack/types' {
-  interface NitroRuntimeConfigApp {
-    buildAssetsDir: string
-    cdnURL: string
-  }
-  interface NitroRouteRules {
-    ssr?: boolean
-    noScripts?: boolean
-    /** @deprecated Use `noScripts` instead */
-    experimentalNoScripts?: boolean
-    appMiddleware?: Record<string, boolean>
-  }
+  interface NitroRuntimeConfigApp extends _NitroRuntimeConfigAppFields {}
+  interface NitroRouteRules extends _NitroRouteRulesFields {}
 }
 
 // Note: Keep in sync with packages/nuxt/src/core/templates.ts
 declare module 'nitropack' {
   // eslint-disable-next-line @typescript-eslint/no-empty-object-type
   interface NitroRuntimeConfig extends RuntimeConfig {}
-  interface NitroRouteConfig {
-    ssr?: boolean
-    noScripts?: boolean
-    /** @deprecated Use `noScripts` instead */
-    experimentalNoScripts?: boolean
-  }
-  interface NitroRuntimeHooks {
-    'dev:ssr-logs': (ctx: { logs: LogObject[], path: string }) => void | Promise<void>
-    'render:html': (htmlContext: NuxtRenderHTMLContext, context: { event: H3Event }) => void | Promise<void>
-    'render:island': (islandResponse: NuxtIslandResponse, context: { event: H3Event, islandContext: NuxtIslandContext }) => void | Promise<void>
-  }
+  interface NitroRouteConfig extends _NitroRouteConfigFields {}
+  interface NitroRuntimeHooks extends _NitroRuntimeHooksShape {}
 }
 declare module 'nitropack/types' {
   // eslint-disable-next-line @typescript-eslint/no-empty-object-type
   interface NitroRuntimeConfig extends RuntimeConfig {}
-  interface NitroRouteConfig {
-    ssr?: boolean
-    noScripts?: boolean
-    /** @deprecated Use `noScripts` instead */
-    experimentalNoScripts?: boolean
-  }
-  interface NitroRuntimeHooks {
-    'dev:ssr-logs': (ctx: { logs: LogObject[], path: string }) => void | Promise<void>
-    'render:html': (htmlContext: NuxtRenderHTMLContext, context: { event: H3Event }) => void | Promise<void>
-    'render:island': (islandResponse: NuxtIslandResponse, context: { event: H3Event, islandContext: NuxtIslandContext }) => void | Promise<void>
-  }
+  interface NitroRouteConfig extends _NitroRouteConfigFields {}
+  interface NitroRuntimeHooks extends _NitroRuntimeHooksShape {}
 }

Add these shared shapes above the first declare module:

type _NitroRuntimeConfigAppFields = {
  buildAssetsDir: string
  cdnURL: string
}

type _NitroRouteRulesFields = {
  ssr?: boolean
  noScripts?: boolean
  /** @deprecated Use `noScripts` instead */
  experimentalNoScripts?: boolean
  appMiddleware?: Record<string, boolean>
}

type _NitroRouteConfigFields = {
  ssr?: boolean
  noScripts?: boolean
  /** @deprecated Use `noScripts` instead */
  experimentalNoScripts?: boolean
}

type _NitroRuntimeHooksShape = {
  'dev:ssr-logs': (ctx: { logs: LogObject[], path: string }) => void | Promise<void>
  'render:html': (htmlContext: NuxtRenderHTMLContext, context: { event: H3Event }) => void | Promise<void>
  'render:island': (islandResponse: NuxtIslandResponse, context: { event: H3Event, islandContext: NuxtIslandContext }) => void | Promise<void>
}
```<!-- review_comment_end -->



Also applies to: 22-34, 37-51, 52-66

---

`40-45`: **Confirm omission of `appMiddleware` from `NitroRouteConfig` is intentional.**

`NitroRouteRules` includes `appMiddleware`, but `NitroRouteConfig` does not. If that’s by design (rules vs per‑route config), all good; otherwise add it for parity.


<!-- review_comment_end -->
<!-- file_end -->


Also applies to: 55-60

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used**: CodeRabbit UI

**Review profile**: CHILL

**Plan**: Pro

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 3c38d1f8bdff7c6d86579a2722507590a17022c9 and 0295d5050d51093f68863b668526afa41673f114.

</details>

<details>
<summary>⛔ Files ignored due to path filters (4)</summary>

* `package.json` is excluded by `!package.json`, `!**/package.json`
* `packages/nitro-server/package.json` is excluded by `!**/package.json`
* `packages/nuxt/package.json` is excluded by `!**/package.json`
* `pnpm-lock.yaml` is excluded by `!**/pnpm-lock.yaml`, `!pnpm-lock.yaml`

</details>

<details>
<summary>📒 Files selected for processing (25)</summary>

* `packages/nitro-server/.attw.json` (1 hunks)
* `packages/nitro-server/.gitignore` (1 hunks)
* `packages/nitro-server/build.config.ts` (1 hunks)
* `packages/nitro-server/src/augments.ts` (1 hunks)
* `packages/nitro-server/src/index.ts` (13 hunks)
* `packages/nitro-server/src/runtime/handlers/error.ts` (1 hunks)
* `packages/nitro-server/src/runtime/handlers/island.ts` (1 hunks)
* `packages/nitro-server/src/runtime/handlers/renderer.ts` (1 hunks)
* `packages/nitro-server/src/runtime/utils/renderer/app.ts` (1 hunks)
* `packages/nitro-server/src/runtime/utils/renderer/build-files.ts` (1 hunks)
* `packages/nitro-server/src/runtime/utils/renderer/islands.ts` (1 hunks)
* `packages/nitro-server/src/templates.ts` (1 hunks)
* `packages/nitro-server/src/utils.ts` (1 hunks)
* `packages/nuxt/build.config.ts` (0 hunks)
* `packages/nuxt/src/app/types.ts` (1 hunks)
* `packages/nuxt/src/app/types/augments.ts` (0 hunks)
* `packages/nuxt/src/core/nuxt.ts` (6 hunks)
* `packages/nuxt/src/core/plugins/import-protection.ts` (1 hunks)
* `packages/nuxt/src/core/server.ts` (1 hunks)
* `packages/nuxt/src/core/templates.ts` (2 hunks)
* `packages/nuxt/types.d.mts` (1 hunks)
* `packages/nuxt/types.d.ts` (1 hunks)
* `packages/schema/src/config/nitro.ts` (1 hunks)
* `packages/schema/src/types/schema.ts` (1 hunks)
* `packages/ui-templates/lib/render.ts` (1 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (2)</summary>

* packages/nuxt/build.config.ts
* packages/nuxt/src/app/types/augments.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>📓 Path-based instructions (1)</summary>

<details>
<summary>**/*.{ts,tsx}</summary>


**📄 CodeRabbit inference engine (.github/copilot-instructions.md)**

> Follow standard TypeScript conventions and best practices

Files:
- `packages/schema/src/config/nitro.ts`
- `packages/nitro-server/src/runtime/utils/renderer/islands.ts`
- `packages/nitro-server/src/utils.ts`
- `packages/nitro-server/src/runtime/handlers/renderer.ts`
- `packages/ui-templates/lib/render.ts`
- `packages/nuxt/src/core/templates.ts`
- `packages/nitro-server/build.config.ts`
- `packages/nitro-server/src/runtime/handlers/error.ts`
- `packages/nitro-server/src/augments.ts`
- `packages/schema/src/types/schema.ts`
- `packages/nuxt/src/core/server.ts`
- `packages/nuxt/types.d.ts`
- `packages/nitro-server/src/runtime/utils/renderer/build-files.ts`
- `packages/nitro-server/src/runtime/utils/renderer/app.ts`
- `packages/nuxt/src/app/types.ts`
- `packages/nitro-server/src/index.ts`
- `packages/nuxt/src/core/plugins/import-protection.ts`
- `packages/nitro-server/src/runtime/handlers/island.ts`
- `packages/nuxt/src/core/nuxt.ts`
- `packages/nitro-server/src/templates.ts`

</details>

</details><details>
<summary>🧬 Code graph analysis (7)</summary>

<details>
<summary>packages/nitro-server/build.config.ts (2)</summary><blockquote>

<details>
<summary>packages/nuxt/build.config.ts (1)</summary>

* `ctx` (25-27)

</details>
<details>
<summary>debug/build-config.ts (1)</summary>

* `addRollupTimingsPlugin` (20-24)

</details>

</blockquote></details>
<details>
<summary>packages/nitro-server/src/augments.ts (1)</summary><blockquote>

<details>
<summary>packages/nuxt/src/app/types.ts (3)</summary>

* `NuxtRenderHTMLContext` (39-46)
* `NuxtIslandResponse` (30-37)
* `NuxtIslandContext` (21-28)

</details>

</blockquote></details>
<details>
<summary>packages/nuxt/src/core/server.ts (1)</summary><blockquote>

<details>
<summary>packages/nitro-server/src/index.ts (1)</summary>

* `bundle` (37-766)

</details>

</blockquote></details>
<details>
<summary>packages/nuxt/src/app/types.ts (1)</summary><blockquote>

<details>
<summary>packages/nuxt/src/app/index.ts (4)</summary>

* `NuxtAppLiterals` (14-14)
* `NuxtIslandContext` (14-14)
* `NuxtIslandResponse` (14-14)
* `NuxtRenderHTMLContext` (14-14)

</details>

</blockquote></details>
<details>
<summary>packages/nitro-server/src/index.ts (2)</summary><blockquote>

<details>
<summary>packages/nitro-server/src/templates.ts (1)</summary>

* `nitroSchemaTemplate` (4-82)

</details>
<details>
<summary>packages/nitro-server/src/utils.ts (1)</summary>

* `distDir` (11-11)

</details>

</blockquote></details>
<details>
<summary>packages/nuxt/src/core/plugins/import-protection.ts (1)</summary><blockquote>

<details>
<summary>packages/schema/src/types/config.ts (1)</summary>

* `NuxtOptions` (82-94)

</details>

</blockquote></details>
<details>
<summary>packages/nuxt/src/core/nuxt.ts (1)</summary><blockquote>

<details>
<summary>packages/nuxt/src/core/server.ts (1)</summary>

* `bundleServer` (5-21)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (14)</summary><blockquote>

<details>
<summary>packages/nuxt/src/core/plugins/import-protection.ts (1)</summary><blockquote>

`16-16`: **LGTM! Function declaration refactor is appropriate.**

The conversion from a const arrow function to a traditional function declaration is a harmless stylistic change. The function signature and body remain unchanged, and whilst this alters hoisting semantics, there are no references to the function within the module that would be affected.

</blockquote></details>
<details>
<summary>packages/nitro-server/src/runtime/utils/renderer/build-files.ts (1)</summary><blockquote>

`1-1`: **Correct import entry for vue-bundle-renderer**

Importing createRenderer from 'vue-bundle-renderer/runtime' is the right entry. LGTM.

Based on learnings

</blockquote></details>
<details>
<summary>packages/nitro-server/.gitignore (1)</summary><blockquote>

`1-2`: **LGTM!**

Appropriate .gitignore entries for generated error templates.

</blockquote></details>
<details>
<summary>packages/nitro-server/.attw.json (1)</summary><blockquote>

`1-3`: **LGTM!**

Appropriate configuration for handling CommonJS/ESM interoperability in the new package.

</blockquote></details>
<details>
<summary>packages/nitro-server/src/runtime/handlers/error.ts (1)</summary><blockquote>

`4-4`: **LGTM!**

Correctly updates type import to use the public `nuxt/app` API instead of internal aliases, aligning with the package extraction goals.

</blockquote></details>
<details>
<summary>packages/nitro-server/src/runtime/utils/renderer/app.ts (1)</summary><blockquote>

`4-4`: **LGTM!**

Type import correctly updated to use the public `nuxt/app` API.

</blockquote></details>
<details>
<summary>packages/nitro-server/src/utils.ts (2)</summary><blockquote>

`4-6`: **LGTM!**

Simple, type-safe utility for normalising values to arrays.

---

`8-11`: **LGTM!**

Correctly computes the distribution directory, accounting for bundler output structures such as `dist/chunks` or `dist/shared`.

</blockquote></details>
<details>
<summary>packages/ui-templates/lib/render.ts (1)</summary><blockquote>

`203-208`: **LGTM!**

Correctly redirects the error-500 template from Nuxt runtime to Nitro runtime templates, aligning with the package extraction strategy.

</blockquote></details>
<details>
<summary>packages/nitro-server/build.config.ts (1)</summary><blockquote>

`4-21`: **LGTM!**

Well-structured build configuration for the extracted Nitro server package. The declaration generation, runtime entry separation, and external dependencies are all appropriate.

</blockquote></details>
<details>
<summary>packages/nitro-server/src/runtime/handlers/island.ts (1)</summary><blockquote>

`10-10`: **LGTM!**

Correctly updates island types to use the public `nuxt/app` API, ensuring consistency across the refactored package.

</blockquote></details>
<details>
<summary>packages/nuxt/types.d.ts (1)</summary><blockquote>

`1-1`: **Verify Nitro typings are provided via `@nuxt/nitro-server` templates.**

Removing Nuxt-side nitropack augmentations shifts responsibility. Ensure the new package generates the necessary module augmentations (e.g. render:html hooks, route rules, runtime config) for consumers.

To confirm, check template generation in `packages/nitro-server/src/templates.ts` and the resulting `.nuxt/types` output includes nitro augmentations.

</blockquote></details>
<details>
<summary>packages/nitro-server/src/runtime/handlers/renderer.ts (1)</summary><blockquote>

`15-15`: **Type import alignment looks good.**

Switching `NuxtRenderHTMLContext` to `nuxt/app` matches the new typing surface. No runtime impact.

</blockquote></details>
<details>
<summary>packages/nuxt/src/core/templates.ts (1)</summary><blockquote>

`14-14`: **Approve removal of unused TSReference import** No TSReference usage remains in this file; the import update is correct.

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/nuxt/src/app/types.ts (1)

9-12: Missing html field (previously flagged).

This issue was already raised in a previous review: the NuxtIslandSlotResponse interface is missing the html field, which creates type inconsistency with how slots are used elsewhere. Please refer to the previous review comment for the suggested fix.

🧹 Nitpick comments (2)
packages/nitro-server/src/augments.ts (1)

36-66: Duplication and manual sync requirement increase maintenance burden.

Similar to the first augmentation block, these interfaces are duplicated between 'nitropack' and 'nitropack/types'. Additionally, the comment on line 36 introduces a manual synchronisation requirement with packages/nuxt/src/core/templates.ts, which creates risk of drift if changes are made in one location but not the other.

Consider:

  1. Applying the same DRY refactor suggested for lines 8-34 to extract shared definitions
  2. Investigating whether these augmentations could be generated from a single source of truth (e.g., via a build-time template) to eliminate the manual sync requirement

For the manual sync concern, you could add automated verification:

#!/bin/bash
# Check for consistency between augments.ts and core/templates.ts
echo "=== Checking for NitroRuntimeConfig in templates.ts ==="
rg -n "interface NitroRuntimeConfig" packages/nuxt/src/core/templates.ts -A 5 || echo "Not found in templates.ts"

echo -e "\n=== Comparing NitroRouteConfig definitions ==="
echo "In augments.ts:"
rg -n "interface NitroRouteConfig" packages/nitro-server/src/augments.ts -A 5

echo -e "\nIn templates.ts:"
rg -n "interface NitroRouteConfig" packages/nuxt/src/core/templates.ts -A 5 || echo "Not found in templates.ts"
packages/nuxt/src/app/types.ts (1)

14-19: Consider stricter typing for props.

The props: unknown type at line 16 is quite permissive. Consider using props?: Record<string, any> or a more specific type to improve type safety and developer experience whilst maintaining flexibility.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0295d50 and 07ba85b.

⛔ Files ignored due to path filters (1)
  • packages/nitro-server/package.json is excluded by !**/package.json
📒 Files selected for processing (5)
  • docs/3.api/6.nuxt-config.md (2 hunks)
  • packages/nitro-server/src/augments.ts (1 hunks)
  • packages/nuxt/src/app/types.ts (1 hunks)
  • packages/nuxt/src/core/server.ts (1 hunks)
  • packages/schema/src/config/nitro.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Follow standard TypeScript conventions and best practices

Files:

  • packages/schema/src/config/nitro.ts
  • packages/nuxt/src/core/server.ts
  • packages/nuxt/src/app/types.ts
  • packages/nitro-server/src/augments.ts
🧬 Code graph analysis (2)
packages/nuxt/src/core/server.ts (1)
packages/nitro-server/src/index.ts (1)
  • bundle (37-766)
packages/nitro-server/src/augments.ts (1)
packages/nuxt/src/app/types.ts (3)
  • NuxtRenderHTMLContext (39-46)
  • NuxtIslandResponse (30-37)
  • NuxtIslandContext (21-28)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: test-fixtures (windows-latest, built, vite, default, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, dev, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, async, manifest-on, js, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, webpack, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-on, js, lts/-1)
  • GitHub Check: release-pkg-pr-new
  • GitHub Check: typecheck (windows-latest, bundler)
  • GitHub Check: test-benchmark
  • GitHub Check: test-size
  • GitHub Check: typecheck (ubuntu-latest, bundler)
  • GitHub Check: code
🔇 Additional comments (6)
packages/nitro-server/src/augments.ts (2)

1-1: Past concern resolved: type-only import now used.

The previous review flagged the runtime side-effect import. The current type-only syntax (import type {} from 'nitropack/types') correctly ensures zero runtime impact whilst making the nitropack type augmentations available.


8-34: Verify necessity of duplicate augmentations in packages/nitro-server/src/augments.ts

The interfaces NitroRuntimeConfigApp and NitroRouteRules are declared identically for both 'nitropack' and 'nitropack/types'. Confirm whether 'nitropack/types' genuinely exports these types; if it re-exports from the main module, drop the redundant augmentation or extract shared definitions to avoid duplication.

packages/nuxt/src/app/types.ts (4)

1-1: LGTM!

The import of SerializableHead from @unhead/vue is correct and properly used in the NuxtIslandResponse interface.


21-28: Verify the Omit pattern for slots.

Line 26 omits only 'fallback' from NuxtIslandSlotResponse, leaving just the props field. Please confirm this is the intended design, especially given that NuxtIslandClientResponse components (line 27) omit 'html'. This asymmetry may be intentional, but worth verifying for consistency.


30-37: LGTM!

The interface correctly uses SerializableHead and has a well-structured response shape for island rendering.


39-46: LGTM!

The render context interface is well-structured with appropriate string array types for HTML rendering.

Comment on lines +6 to +13
$resolve: (val) => {
if (typeof val === 'string') {
return val
}
if (val && typeof val === 'object' && 'bundle' in val) {
return val
}
return '@nuxt/nitro-server'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate custom builder objects before accepting them.

The resolver now accepts any object that merely has a bundle key. If a user provides { bundle: 'foo' } (easy to do in JS config), schema will pass it through, but when bundleServer later executes await bundle(nuxt) it will explode with “bundle is not a function”. Please gate this branch on typeof val.bundle === 'function' (and otherwise fall back to the default or throw) so we fail fast and predictably.

🤖 Prompt for AI Agents
In packages/schema/src/config/nitro.ts around lines 6 to 13, the resolver
currently accepts any object that contains a bundle key which may be a
non-function and later causes runtime errors; update the branch so it only
accepts objects where typeof val.bundle === 'function' (otherwise return the
default '@nuxt/nitro-server' or throw), i.e. validate that val is an object with
a callable bundle before returning it to ensure fast, predictable failure.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/nuxt/src/app/types.ts (1)

9-12: Assess whether html field is required in NuxtIslandSlotResponse.

A previous review identified that html may be missing from NuxtIslandSlotResponse. Currently, only props and fallback are defined. Verify whether slots require an html field based on runtime usage in the Nitro server handlers that consume these types.

Run the following script to check how NuxtIslandSlotResponse is used in the codebase:

#!/bin/bash
# Description: Search for usage of NuxtIslandSlotResponse and check if html property is accessed

# Search for NuxtIslandSlotResponse usage
rg -nP --type=ts -C5 'NuxtIslandSlotResponse'

# Search for slot.html or slots.*?.html patterns
rg -nP --type=ts -C3 '\bslots?\[[^\]]+\]\.html\b|\bslots?\.[a-zA-Z_$][a-zA-Z0-9_$]*\.html\b'
🧹 Nitpick comments (3)
packages/schema/src/config/nitro.ts (1)

4-16: Consider adding runtime validation for the bundle property.

The resolver correctly preserves object builders with a bundle property, addressing the previous concern. However, it doesn't validate that bundle is actually a function, which could allow invalid objects like { bundle: 'not-a-function' } to pass through.

Whilst TypeScript types should prevent this at compile time, adding a runtime check would provide an extra safety layer and clearer error messages:

  server: {
    builder: {
      $resolve: (val) => {
        if (typeof val === 'string') {
          return val
        }
-       if (val && typeof val === 'object' && 'bundle' in val) {
+       if (val && typeof val === 'object' && 'bundle' in val && typeof (val as any).bundle === 'function') {
          return val
        }
        return '@nuxt/nitro-server'
      },
    },
  },

Alternatively, if you want to provide a clearer error for invalid configurations:

$resolve: (val) => {
  if (typeof val === 'string') {
    return val
  }
  if (val && typeof val === 'object' && 'bundle' in val) {
    if (typeof (val as any).bundle !== 'function') {
      throw new TypeError('server.builder.bundle must be a function')
    }
    return val
  }
  return '@nuxt/nitro-server'
}
packages/nuxt/src/app/types.ts (2)

24-24: Consider using a more specific type for props.

The props field uses Record<string, any>, which bypasses type safety. If the prop structure is known or can be constrained, consider using Record<string, unknown> or a more specific type to improve type safety.

Apply this diff if unknown is acceptable:

-  props?: Record<string, any>
+  props?: Record<string, unknown>

34-34: Consider using a more specific type for nested props.

The nested props field uses Record<string, Record<string, any>>, which weakens type safety. If the structure can be constrained, consider using Record<string, Record<string, unknown>> for better type safety.

Apply this diff if unknown is acceptable:

-  props?: Record<string, Record<string, any>>
+  props?: Record<string, Record<string, unknown>>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0295d50 and 07ba85b.

⛔ Files ignored due to path filters (1)
  • packages/nitro-server/package.json is excluded by !**/package.json
📒 Files selected for processing (5)
  • docs/3.api/6.nuxt-config.md (2 hunks)
  • packages/nitro-server/src/augments.ts (1 hunks)
  • packages/nuxt/src/app/types.ts (1 hunks)
  • packages/nuxt/src/core/server.ts (1 hunks)
  • packages/schema/src/config/nitro.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/nuxt/src/core/server.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Follow standard TypeScript conventions and best practices

Files:

  • packages/nitro-server/src/augments.ts
  • packages/nuxt/src/app/types.ts
  • packages/schema/src/config/nitro.ts
🧬 Code graph analysis (2)
packages/nitro-server/src/augments.ts (1)
packages/nuxt/src/app/types.ts (3)
  • NuxtRenderHTMLContext (39-46)
  • NuxtIslandResponse (30-37)
  • NuxtIslandContext (21-28)
packages/nuxt/src/app/types.ts (1)
packages/nuxt/src/app/index.ts (4)
  • NuxtAppLiterals (14-14)
  • NuxtIslandContext (14-14)
  • NuxtIslandResponse (14-14)
  • NuxtRenderHTMLContext (14-14)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
  • GitHub Check: test-fixtures (windows-latest, built, rspack, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, built, vite, default, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, dev, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, dev, vite, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, built, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, dev, vite, default, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, async, manifest-on, js, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, webpack, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-on, js, lts/-1)
  • GitHub Check: typecheck (windows-latest, bundler)
  • GitHub Check: test-benchmark
🔇 Additional comments (4)
docs/3.api/6.nuxt-config.md (2)

427-480: Excellent documentation with comprehensive examples.

The expanded builder documentation is clear and well-structured, providing:

  • Type information with all supported builder options
  • Examples for each built-in builder (vite, webpack, rspack)
  • Clear guidance on custom builder objects with the bundle function
  • Instructions for creating custom builder packages

The progression from simple to complex use cases makes this easy to follow.


1272-1287: Clear documentation with appropriate cautionary guidance.

The server.builder documentation is concise and includes:

  • Accurate type definition matching the implementation
  • Clear explanation of the default behaviour
  • Appropriate warning callout about the API being internal and not finalised

The warning callout (lines 1285-1287) is particularly valuable as it sets clear expectations for users considering this option.

packages/nuxt/src/app/types.ts (2)

39-46: LGTM!

The NuxtRenderHTMLContext interface is well-structured and clearly represents the different sections of HTML rendering context.


1-1: Dependency @unhead/vue verified: declared in packages/nuxt/package.json (version ^2.0.14).

@danielroe danielroe merged commit f3dc078 into main Oct 13, 2025
50 of 52 checks passed
@danielroe danielroe deleted the refactor/nuxt-nitro branch October 13, 2025 21:42
@github-actions github-actions bot mentioned this pull request Oct 13, 2025
@github-actions github-actions bot mentioned this pull request Oct 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants