Skip to content

Conversation

@danielroe
Copy link
Member

🔗 Linked issue

#32342
closes #33262

📚 Description

This migrates us to using the Vite Environment API (on an opt-in basis) - building on the work in #33262.

Optimistically (!) ... I tested on https://github.com/nuxt/nuxt.com and with one small change (nuxt/ui#5008) everything worked fine in development.

🚧 TODO

  • support the Nuxt vitest runtime environment - this may need to happen in @nuxt/test-utils directly instead of here
  • document breaking changes and possibly allow opting in to this (or releasing a separate vite-builder)
  • add warnings when using deprecated hooks (and/or try to handle it by calling config() hooks of plugins injected in this way)
  • investigate increased bundle size (likely composable tree-shaking is not working as expected)
  • fix runtime compiler implementation
  • resolve deep imports plugin likely needs to be updated too

@bolt-new-by-stackblitz
Copy link

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

@github-actions github-actions bot added the 4.x label Oct 16, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 16, 2025

Walkthrough

This PR introduces an experimental Vite Environment API opt-in and enables it by default for future.compatibilityVersion ≥ 5. CI adds a vite-env-api builder and fixture exclusions. Core changes refactor Vite build wiring to support per-environment configs: new helpers clientEnvironment, ssrEnvironment and ssr; a ClientManifestPlugin; environment-aware orchestration in vite.ts with a viteEnvironmentApi path and a legacy serial fallback. API and plugin surfaces changed (addVitePlugin/extendViteConfig, ViteOptions, VitePluginCheckerPlugin). Multiple Vite plugins and vite-node runtime/server logic are adapted. Documentation and schema updates included.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Justification: Wide-ranging, heterogeneous changes touching build orchestration, new public helpers/APIs, runtime/server integration, plugin behaviours and CI/docs. High-density logic in multiple core files (vite.ts, vite-node, shared server/client, build.ts) requires thorough cross-file consistency and behavioural validation.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "feat(kit,vite): allow enabling vite environment api" uses conventional commit format and clearly summarises the primary objective of the changeset. The title directly aligns with the substantive changes across the PR, which implement opt-in support for the Vite Environment API throughout the kit and vite packages. The changes include modifications to build configuration, new environment-specific helpers, CI workflow updates, plugin rewrites for environment support, and comprehensive documentation updates—all of which centre on enabling and supporting the Vite Environment API. The title is concise, unambiguous, and accurately represents the main change from the developer's perspective.
Description Check ✅ Passed The PR description is clearly related to the changeset and provides meaningful context for the changes. It explains the purpose (migration to the Vite Environment API on an opt-in basis), references foundational prior work (PR 33262) and a linked issue, documents successful testing against an external project (nuxt.com), and lists completed TODOs that align with substantive changes in the PR such as supporting vitest runtime environments, documenting breaking changes, adding deprecation warnings, and addressing performance considerations. The description conveys sufficient information about the scope and intent without being overly verbose.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/compat-env-api

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 23887a4 and 19e9c7c.

📒 Files selected for processing (1)
  • docs/2.guide/3.going-further/1.features.md (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-11-11T12:34:22.648Z
Learnt from: Tofandel
PR: nuxt/nuxt#0
File: :0-0
Timestamp: 2024-11-11T12:34:22.648Z
Learning: Ensure that AI-generated summaries accurately reflect the key changes in the PR, focusing on notable changes such as the removal of unused imports and variables starting with underscores.

Applied to files:

  • docs/2.guide/3.going-further/1.features.md
🪛 LanguageTool
docs/2.guide/3.going-further/1.features.md

[uncategorized] ~77-~77: Loose punctuation mark.
Context: ...xt-5"} Learn more about testing Nuxt 5. :: ### multiApp This enables early acce...

(UNLIKELY_OPENING_PUNCTUATION)

⏰ 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). (1)
  • GitHub Check: code
🔇 Additional comments (2)
docs/2.guide/3.going-further/1.features.md (2)

66-66: Grammar fix applied correctly.

The phrasing now correctly uses "opt in" (two words) as the verb form, addressing the previous grammar concern. Well done.


76-78: Well-placed documentation link.

The new read-more block appropriately directs users to the upgrade guide for testing Nuxt 5, providing helpful context for those exploring the Vite Environment API via compatibilityVersion.


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.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 16, 2025

Open in StackBlitz

@nuxt/kit

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

nuxt

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

@nuxt/rspack-builder

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

@nuxt/schema

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

@nuxt/vite-builder

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

@nuxt/webpack-builder

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

commit: 19e9c7c

@danielroe danielroe changed the title feat(kit,vite): allow enabling environment api feat(kit,vite): allow enabling environment api Oct 16, 2025
@danielroe danielroe changed the title feat(kit,vite): allow enabling environment api feat(kit,vite): allow enabling vite environment api Oct 16, 2025
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

🧹 Nitpick comments (3)
packages/vite/src/shared/server.ts (1)

64-68: Consider standard condition ordering.

The condition 'UNUSED_EXTERNAL_IMPORT' === warning.code uses Yoda-style comparison, which is uncommon in modern JavaScript. While not incorrect, the standard ordering warning.code === 'UNUSED_EXTERNAL_IMPORT' improves readability.

Apply this diff to use standard condition ordering:

-        if (warning.code && 'UNUSED_EXTERNAL_IMPORT' === warning.code) {
+        if (warning.code === 'UNUSED_EXTERNAL_IMPORT') {
           return
         }
packages/vite/src/plugins/client-manifest.ts (1)

68-88: Consider adding error handling for file operations.

The file operations (mkdir, writeFile, rm) are currently unguarded. Whilst this may be acceptable in a build context where failures would propagate naturally, adding explicit error handling could improve debuggability and provide clearer error messages for file system issues.

Consider wrapping the file operations in a try-catch block:

+    try {
       await mkdir(serverDist, { recursive: true })

       if (disableCssCodeSplit) {
         for (const entry of manifestEntries) {
           if (entry.file?.endsWith('.css')) {
             clientManifest[key]!.css ||= []
             ;(clientManifest[key]!.css as string[]).push(entry.file)
             break
           }
         }
       }

       const manifest = normalizeViteManifest(clientManifest)
       await nuxt.callHook('build:manifest', manifest)
       const precomputed = precomputeDependencies(manifest)
       await writeFile(resolve(serverDist, 'client.manifest.mjs'), 'export default ' + serialize(manifest), 'utf8')
       await writeFile(resolve(serverDist, 'client.precomputed.mjs'), 'export default ' + serialize(precomputed), 'utf8')

       if (!nuxt.options.dev) {
         await rm(manifestFile, { force: true })
       }
+    } catch (err) {
+      throw new Error(`Failed to write client manifest: ${err}`)
+    }
packages/vite/src/vite.ts (1)

270-294: Consider adding error handling for dev server creation.

The handleEnvironments function lacks explicit error handling for the createServer and buildApp calls. If these operations fail, the error will propagate but without context about which environment failed.

Add try-catch blocks with contextual error messages:

 async function handleEnvironments (nuxt: Nuxt, config: vite.InlineConfig) {
   config.customLogger = createViteLogger(config)
   config.configFile = false

   for (const environment of ['client', 'ssr']) {
     const environments = { [environment]: config.environments![environment]! }
     const strippedConfig = { ...config, environments } as ViteConfig
     const ctx = { isServer: environment === 'ssr', isClient: environment === 'client' }
     await nuxt.hooks.callHook('vite:extendConfig', strippedConfig, ctx)
     await nuxt.hooks.callHook('vite:configResolved', strippedConfig, ctx)
   }

   if (!nuxt.options.dev) {
+    try {
       const builder = await createBuilder(config)
       await builder.buildApp()
+    } catch (err) {
+      throw new Error(`Failed to build Vite app: ${err}`)
+    }
     return
   }

+  try {
     await withLogs(async () => {
       const server = await createServer(config)
       await server.environments.ssr.pluginContainer.buildStart({})
     }, 'Vite dev server built')

     await writeDevServer(nuxt)
+  } catch (err) {
+    throw new Error(`Failed to create Vite dev server: ${err}`)
+  }
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7bcc4ca and 7f148d4.

📒 Files selected for processing (16)
  • .github/workflows/ci.yml (2 hunks)
  • packages/kit/src/build.ts (4 hunks)
  • packages/schema/src/config/experimental.ts (1 hunks)
  • packages/vite/src/client.ts (2 hunks)
  • packages/vite/src/index.ts (1 hunks)
  • packages/vite/src/plugins/client-manifest.ts (1 hunks)
  • packages/vite/src/plugins/dev-server.ts (1 hunks)
  • packages/vite/src/plugins/environments.ts (1 hunks)
  • packages/vite/src/plugins/replace.ts (1 hunks)
  • packages/vite/src/plugins/ssr-styles.ts (1 hunks)
  • packages/vite/src/plugins/vite-node.ts (8 hunks)
  • packages/vite/src/plugins/vite-plugin-checker.ts (1 hunks)
  • packages/vite/src/server.ts (3 hunks)
  • packages/vite/src/shared/client.ts (1 hunks)
  • packages/vite/src/shared/server.ts (1 hunks)
  • packages/vite/src/vite.ts (4 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/vite/src/plugins/ssr-styles.ts
  • packages/vite/src/plugins/dev-server.ts
  • packages/vite/src/plugins/environments.ts
  • packages/schema/src/config/experimental.ts
  • packages/vite/src/plugins/replace.ts
  • packages/vite/src/plugins/client-manifest.ts
  • packages/kit/src/build.ts
  • packages/vite/src/plugins/vite-plugin-checker.ts
  • packages/vite/src/index.ts
  • packages/vite/src/shared/server.ts
  • packages/vite/src/server.ts
  • packages/vite/src/shared/client.ts
  • packages/vite/src/plugins/vite-node.ts
  • packages/vite/src/client.ts
  • packages/vite/src/vite.ts
🧠 Learnings (1)
📚 Learning: 2025-04-18T18:33:41.753Z
Learnt from: TheAlexLichter
PR: nuxt/nuxt#31812
File: packages/nuxt/src/components/plugins/islands-transform.ts:202-202
Timestamp: 2025-04-18T18:33:41.753Z
Learning: In Nuxt, using `rolldownVersion` (not `rollupVersion`) is intentional when detecting if rolldown-vite is being used, even though TypeScript may show an error because the property isn't in standard type definitions yet.

Applied to files:

  • packages/vite/src/plugins/environments.ts
  • packages/vite/src/plugins/replace.ts
  • packages/vite/src/vite.ts
🧬 Code graph analysis (8)
packages/vite/src/plugins/client-manifest.ts (1)
packages/vite/src/utils/config.ts (1)
  • resolveClientEntry (3-15)
packages/kit/src/build.ts (1)
packages/kit/src/utils.ts (1)
  • toArray (2-4)
packages/vite/src/index.ts (1)
packages/schema/src/types/config.ts (2)
  • ViteOptions (130-130)
  • ViteConfig (96-127)
packages/vite/src/shared/server.ts (1)
packages/vite/src/utils/transpile.ts (1)
  • transpile (11-28)
packages/vite/src/server.ts (1)
packages/vite/src/shared/server.ts (2)
  • ssr (10-26)
  • ssrEnvironment (28-89)
packages/vite/src/plugins/vite-node.ts (2)
packages/vite/src/runtime/vite-node.mjs (2)
  • invalidates (23-23)
  • errorData (48-48)
packages/vite/src/runtime/vite-node-shared.mjs (3)
  • socket (55-55)
  • socket (233-233)
  • response (141-141)
packages/vite/src/client.ts (1)
packages/vite/src/shared/client.ts (1)
  • clientEnvironment (4-78)
packages/vite/src/vite.ts (7)
packages/vite/src/plugins/dev-server.ts (2)
  • config (15-57)
  • DevServerPlugin (10-147)
packages/vite/src/utils/logger.ts (2)
  • logLevelMap (14-18)
  • createViteLogger (28-110)
packages/vite/src/shared/server.ts (2)
  • ssr (10-26)
  • ssrEnvironment (28-89)
packages/vite/src/shared/client.ts (1)
  • clientEnvironment (4-78)
packages/vite/src/plugins/vite-node.ts (2)
  • ViteNodePlugin (160-233)
  • writeDevServer (509-522)
packages/vite/src/plugins/client-manifest.ts (1)
  • ClientManifestPlugin (14-91)
packages/vite/src/plugins/dev-style-ssr.ts (1)
  • DevStyleSSRPlugin (10-31)
🪛 ast-grep (0.39.6)
packages/vite/src/plugins/client-manifest.ts

[warning] 58-58: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^${escapeRE(buildAssetsDir)})
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

⏰ 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). (2)
  • GitHub Check: code
  • GitHub Check: build
🔇 Additional comments (19)
packages/vite/src/plugins/dev-server.ts (1)

69-72: LGTM! Proper feature flagging for Environment API.

The conditional hook invocation is correctly gated behind the experimental flag. The hook parameters { isClient: true, isServer: true } reflect that a single Vite server now manages both client and server environments when the Environment API is enabled.

packages/schema/src/config/experimental.ts (1)

225-229: LGTM! Appropriate resolver logic for experimental feature.

The resolver correctly defaults to enabling the Vite Environment API for compatibility version 5 and above, whilst allowing explicit boolean overrides. This aligns with the pattern of experimental features becoming default in future major versions.

packages/vite/src/plugins/replace.ts (1)

22-22: LGTM! Improved type safety.

Replacing the @ts-expect-error comment with a type cast is a cleaner approach to accessing the non-public rolldownVersion property. Based on learnings, this property access is intentional for detecting rolldown-vite.

packages/vite/src/plugins/ssr-styles.ts (1)

68-68: LGTM! Correct condition for Environment API support.

The extended condition appropriately handles the case where the Vite Environment API is enabled, allowing the client entry to be resolved even when config.build.ssr is truthy. This reflects the architectural change where both client and server environments are managed simultaneously.

packages/vite/src/index.ts (1)

8-9: LGTM! Type refinement for Environment API.

The change from ViteConfig to EnvironmentOptions provides more specific typing for per-environment configuration, which aligns with the Vite Environment API. Note that this is a breaking change for consumers directly accessing these properties, but the PR objectives indicate that breaking changes are being documented.

packages/vite/src/plugins/vite-plugin-checker.ts (2)

5-5: LGTM! Appropriate signature change for flexible environment handling.

Making the environment parameter optional allows the plugin to operate in both environment-specific and all-environment modes, which is necessary for supporting the new Environment API architecture.


12-12: LGTM! Correct filtering logic for optional environment parameter.

The filter logic correctly handles both cases:

  • When environment is provided: only include that specific environment
  • When environment is undefined: include all defined environments (client and ssr if enabled)
packages/vite/src/plugins/environments.ts (1)

59-60: LGTM! Consistent type safety improvements.

The type casts provide a cleaner alternative to @ts-expect-error comments for accessing non-public Vite properties. Based on learnings, the rolldownVersion check is intentional for detecting rolldown-vite, and the advancedChunks assignment is a necessary configuration adjustment.

packages/vite/src/shared/client.ts (1)

1-78: LGTM! Well-structured environment configuration helper.

The clientEnvironment helper provides a clean abstraction for client-specific Vite configuration. Key strengths:

  • Comprehensive dependency exclusions prevent optimisation conflicts
  • Appropriate environment flag definitions for client-side builds
  • Correct build output configuration with proper path resolution
  • Conditional node compatibility based on experimental flag
packages/vite/src/shared/server.ts (1)

10-26: LGTM!

The SSR optimization configuration is well-structured, correctly delegating to the transpile helper for server-side transpilation and including appropriate Nuxt-specific patterns.

packages/vite/src/plugins/client-manifest.ts (2)

19-27: LGTM!

The plugin correctly targets the SSR environment as it needs to run after the server build (or client build if no server build) to generate the client manifest. The applyToEnvironment filter ensures the closeBundle hook executes in the proper build context.


58-59: Regular expression is safe from ReDoS.

The static analysis warning about potential ReDoS is a false positive. The escapeRE function (imported as escapeStringRegexp) properly escapes all regex special characters, making the constructed pattern safe.

packages/vite/src/vite.ts (7)

68-76: LGTM!

The rolldownVersion check correctly removes esbuild-specific configuration when using rolldown-vite. This usage is intentional and expected.

Based on learnings


111-144: LGTM!

The environment API configuration properly sets up per-environment builds with correct consumer types, warmup entries, and delegates to the new helper functions (clientEnvironment, ssrEnvironment, ssr) for environment-specific options.


179-187: Non-public property access is acceptable here.

The @ts-expect-error annotation correctly acknowledges the non-public watch property access. The conditional logic properly handles differences between rolldown and standard Vite, including the TODO reference for the rolldown GitHub issue.


189-232: Plugin array construction is well-gated.

The plugin array correctly conditionally includes plugins based on the viteEnvironmentApi flag. The separation between always-included plugins (PublicDirsPlugin, ReplacePlugin, etc.) and environment-API-specific plugins (VuePlugin, ViteNodePlugin, etc.) is clear.


296-302: LGTM!

The ViteBuildContext interface properly exposes the build context for external use, including optional server properties for the new environment API flow.


84-251: Environment configuration merging order is correct. mergeConfig applies user-supplied $client and $server overrides as intended.


263-268: Both code paths properly invoke the required hooks with appropriate context—backward compatibility is preserved.

Verification confirms that:

  • handleEnvironments and handleSerialBuilds both invoke vite:extendConfig and vite:configResolved hooks with correct isClient/isServer context parameters
  • The serial builds path (legacy) calls buildClient and buildServer sequentially, which internally trigger the same hooks
  • No hardcoded build order assumptions exist; the sequential invocation is consistent
  • All existing vite: hooks (vite:compiled, vite:serverCreated) are called in both paths with proper environment context

The two paths differ in architectural approach (Vite's environment API vs separate builds), but the hook contract and output equivalence are maintained. The serial builds path remains a reliable fallback for users with the flag disabled.

@codspeed-hq
Copy link

codspeed-hq bot commented Oct 16, 2025

CodSpeed Performance Report

Merging #33492 will not alter performance

Comparing feat/compat-env-api (19e9c7c) with main (5c0bb92)

Summary

✅ 10 untouched

@danielroe
Copy link
Member Author

@copilot would you add documentation in the migration guide about how to test this in preparation for nuxt 5?

including enabling compatibilityVersion

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

🧹 Nitpick comments (8)
docs/2.guide/4.recipes/2.vite-plugin.md (1)

82-98: Documentation addition is clear; verify plugin example is sufficiently complete.

The new section appropriately distinguishes Nuxt 5+ environment-specific usage. However, the placeholder comment on line 94 ("// Plugin configuration") leaves the example incomplete—readers may be uncertain what a full plugin implementation should contain. Consider either providing a minimal working example (e.g., a resolveId hook) or explicitly stating that developers should add their plugin logic here.

Consider expanding the example with minimal plugin implementation:

addVitePlugin(() => ({
  name: 'my-client-plugin',
  applyToEnvironment (environment) {
    return environment.name === 'client'
  },
  resolveId (id) {
    if (id === 'virtual-client-module') {
      return id
    }
  },
  load (id) {
    if (id === 'virtual-client-module') {
      return `export default { message: 'client-only' }`
    }
  },
}))

Alternatively, if the intent is to show only the structure, consider making it clear with a comment: "// Add your plugin hooks here".

docs/3.api/5.kit/14.builder.md (3)

17-19: Deprecation warning is appropriate.

The warning correctly indicates the hook is deprecated and recommends the newer approach. However, it could be more specific about when this applies: "Deprecated in Nuxt 5+" would be clearer than just stating it "is now deprecated".

Update the warning text for greater clarity:

- This hook is now deprecated, and we recommend using a Vite plugin instead with a `config` hook, or — for environment-specific configuration — the `applyToEnvironment` hook.
+ This hook is **deprecated in Nuxt 5+** and we recommend using a Vite plugin instead with a `config` hook, or — for environment-specific configuration — the `applyToEnvironment` hook.

37-74: Migration examples are comprehensive and well-structured.

The before/after pattern is excellent for migration guidance. The distinction between config (global), configEnvironment (per-environment), and applyToEnvironment (filtering) is clear. The warning at lines 72-74 appropriately flags the ordering caveat.

One minor improvement: the example at line 68 references a non-existent environment.name property without first establishing what properties environment objects have. While readers can infer it from context, adding a brief inline comment would help.

Consider adding context about the environment object:

    // For environment-specific configuration
    addVitePlugin(() => ({
      name: 'my-client-plugin',
      applyToEnvironment (environment) {
+       // `environment.name` is 'client' or 'ssr' (or custom names)
        return environment.name === 'client'
      },

157-159: Deprecation warning for addVitePlugin is helpful.

The warning correctly explains the behaviour change in Nuxt 5+: plugins with server: false or client: false will no longer have their config or configResolved hooks called. This is important for users to understand the migration.

However, the warning could be even clearer about the reason: these hooks operate on shared configuration in Nuxt 5+, so per-environment filtering changes how they behave. Consider linking to the applyToEnvironment() hook documentation.

Enhance the warning with a link to environment-specific plugin documentation:

- In Nuxt 5+, plugins registered with `server: false` or `client: false` options will not have their `config` or `configResolved` hooks called. Instead, use the `applyToEnvironment()` method instead for environment-specific plugins.
+ In Nuxt 5+, plugins registered with `server: false` or `client: false` options will not have their `config` or `configResolved` hooks called (as Vite uses a shared configuration). Instead, use the `applyToEnvironment()` method for environment-specific plugins. See [migration guide](#migration-to-vite-environment-api) for details.
docs/1.getting-started/18.upgrade.md (2)

66-95: "Migration to Vite Environment API" section is comprehensive and well-structured.

The introduction clearly explains what changed and why. The key changes are accurate and important. The tip at lines 76-78 provides helpful guidance on testing early.

However, the phrasing "Previously, Nuxt used separate client and server Vite configurations" could be slightly clearer: "Previously, Nuxt maintained separate Vite configurations for client and server bundles" would be more precise.

One potential issue: Line 84 states "will not have their config or configResolved hooks called" but this might be confusing to readers unfamiliar with Vite plugin architecture. Consider adding a clarifying note about why this happens (shared configuration model in Vite 6).

Add clarification about the hook behaviour change:

2. **Changed plugin registration**: Vite plugins registered with `addVitePlugin()` and only targeting one environment (by passing `server: false` or `client: false`) will not have their `config` or `configResolved` hooks called.
+ 
+   This is because Nuxt 5+ uses a shared Vite configuration model, and per-environment plugin filtering happens at registration time rather than during hook execution.

96-135: Migration steps provide excellent before/after examples.

The "Migrate to use Vite plugins" step (lines 98-135) is particularly helpful. It shows three common patterns:

  1. Using extendViteConfig with server: false
  2. Using Nuxt hooks like vite:extendConfig
  3. The recommended approach using addVitePlugin with environment-specific hooks

The examples are clear and runnable. The "Migrate Vite plugins to use environments" section (lines 137-171) demonstrates the applyToEnvironment pattern effectively.

One suggestion: The examples at lines 102-112 and 141-149 are somewhat duplicative (both show before patterns). Consider consolidating or cross-referencing.

docs/3.api/6.advanced/1.hooks.md (1)

78-79: Deprecation notes appropriately flag the behaviour change.

The table entries clearly indicate these hooks are deprecated in Nuxt 5+ and explain the key difference: operating on shared configuration rather than separate configs. This is consistent with messaging in other files.

However, the table format limits detail. Consider whether users should be directed to the migration guide. Since this is an API reference, the current brief approach is appropriate, but adding a note like "(see migration guide)" could improve discoverability.

Add migration guide reference for discoverability:

- `vite:extendConfig`      | `viteInlineConfig, env`    | Allows extending Vite default config. **Deprecated in Nuxt 5+.** In Nuxt 5, this operates on a shared configuration rather than separate client/server configs.
- `vite:configResolved`    | `viteInlineConfig, env`    | Allows reading the resolved Vite config. **Deprecated in Nuxt 5+.** In Nuxt 5, this operates on a shared configuration rather than separate client/server configs.
+ `vite:extendConfig`      | `viteInlineConfig, env`    | Allows extending Vite default config. **Deprecated in Nuxt 5+** (see [migration guide](/docs/4.x/getting-started/upgrade#migration-to-vite-environment-api)). In Nuxt 5, this operates on a shared configuration rather than separate client/server configs.
+ `vite:configResolved`    | `viteInlineConfig, env`    | Allows reading the resolved Vite config. **Deprecated in Nuxt 5+** (see [migration guide](/docs/4.x/getting-started/upgrade#migration-to-vite-environment-api)). In Nuxt 5, this operates on a shared configuration rather than separate client/server configs.
docs/2.guide/3.going-further/1.experimental-features.md (1)

899-921: New viteEnvironmentApi experimental feature section is well-integrated.

The section appropriately documents the experimental feature, explains the default behaviour with future.compatibilityVersion: 5, and provides clear enabling instructions. The warning at lines 915-917 helpfully directs users to the migration guide.

The description at line 913 could be slightly more concrete. Saying "better consistency between development and production builds" and "more granular control" is good, but readers might benefit from a brief example or more specific benefit.

Enhance the benefits description with more specificity:

- The Vite Environment API provides better consistency between development and production builds, more granular control over environment-specific configuration, and improved performance.
+ The Vite Environment API provides:
+ - Better consistency between development and production builds through unified configuration
+ - More granular control over environment-specific configuration via `applyToEnvironment()`
+ - Improved performance and plugin architecture alignment with Vite 6
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f148d4 and 23887a4.

📒 Files selected for processing (6)
  • docs/1.getting-started/18.upgrade.md (10 hunks)
  • docs/2.guide/3.going-further/1.experimental-features.md (1 hunks)
  • docs/2.guide/3.going-further/1.features.md (2 hunks)
  • docs/2.guide/4.recipes/2.vite-plugin.md (1 hunks)
  • docs/3.api/5.kit/14.builder.md (6 hunks)
  • docs/3.api/6.advanced/1.hooks.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
docs/3.api/5.kit/14.builder.md

[uncategorized] ~18-~18: Loose punctuation mark.
Context: ... — the applyToEnvironment hook. :: ### Usage ```ts twoslash import { de...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~71-~71: Loose punctuation mark.
Context: ...package') }, })) }, }) ``` ::warning Important: The config hoo...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~73-~73: Loose punctuation mark.
Context: ...ronment-specific configuration changes. :: ### Type ```ts twoslash // @errors: ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~158-~158: Loose punctuation mark.
Context: ...stead for environment-specific plugins. :: ### Usage ```ts twoslash // @errors:...

(UNLIKELY_OPENING_PUNCTUATION)

docs/1.getting-started/18.upgrade.md

[uncategorized] ~59-~59: Loose punctuation mark.
Context: ...s and changes as they become available ::note This section is subject to change ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~61-~61: Loose punctuation mark.
Context: ...using future.compatibilityVersion: 5. :: Breaking or significant changes will ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~64-~64: Possible missing comma found.
Context: ...ng or significant changes will be noted below along with migration steps for backward...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~75-~75: Loose punctuation mark.
Context: ...ethod to target specific environments. ::tip You can test this feature early by ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~77-~77: Loose punctuation mark.
Context: ...experimental.viteEnvironmentApi: true`. :: Key changes: 1. **Deprecated env...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~172-~172: Loose punctuation mark.
Context: ...ronment.name === 'client' }, })) ``` ::read-more{to="https://vite.dev/guide/ap...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~545-~545: Possible missing comma found.
Context: ...inimal impact on your app. If you have issues you should verify: - You're not using ...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~1248-~1248: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...et to their current values for some time and we do not have a reason to believe that...

(COMMA_COMPOUND_SENTENCE)

docs/2.guide/3.going-further/1.experimental-features.md

[uncategorized] ~914-~914: Loose punctuation mark.
Context: ...nfiguration, and improved performance. ::important Enabling this feature changes...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~916-~916: Loose punctuation mark.
Context: ...) for details on updating your plugins. :: ::read-more{to="https://vite.dev/guid...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~918-~918: Loose punctuation mark.
Context: ...r details on updating your plugins. :: ::read-more{to="https://vite.dev/guide/ap...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~920-~920: Loose punctuation mark.
Context: ...earn more about Vite's Environment API. ::

(UNLIKELY_OPENING_PUNCTUATION)

docs/2.guide/3.going-further/1.features.md

[grammar] ~66-~66: The word “opt-in” is a noun. The verb is spelled with a white space.
Context: ...s throughout your Nuxt configuration to opt-in to Nuxt v5 behaviour, including enablin...

(NOUN_VERB_CONFUSION)


[uncategorized] ~77-~77: Loose punctuation mark.
Context: ...xt-5"} Learn more about testing Nuxt 5. :: ### multiApp This enables early acce...

(UNLIKELY_OPENING_PUNCTUATION)

docs/2.guide/4.recipes/2.vite-plugin.md

[uncategorized] ~99-~99: Loose punctuation mark.
Context: ...ugin configuration })) }, }) ``` ::important If you're writing code that n...

(UNLIKELY_OPENING_PUNCTUATION)

⏰ 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). (3)
  • GitHub Check: codeql (javascript-typescript)
  • GitHub Check: build
  • GitHub Check: code
🔇 Additional comments (5)
docs/2.guide/3.going-further/1.features.md (1)

76-78: Verify punctuation in markdown component.

The closing period before :: on line 77 may be unnecessary within the markdown component context. Consider whether the sentence should end with a period.

docs/3.api/5.kit/14.builder.md (3)

100-101: Deprecation notes are clear and provide migration path.

The table entries correctly indicate these options are deprecated in Nuxt 5+ and direct users to addVitePlugin() with applyToEnvironment(). Consistent with the earlier deprecation warnings.


182-189: Updated example demonstrates the new pattern well.

The addition showing applyToEnvironment() usage is helpful and demonstrates the recommended approach. It sits naturally alongside the simpler example above it.


218-219: Deprecation notes are consistent with extendViteConfig.

The table entries align with the earlier messaging and provide consistent migration guidance.

docs/1.getting-started/18.upgrade.md (1)

37-62: New "Testing Nuxt 5" section is well-introduced.

The section clearly explains the opt-in mechanism and the expected defaults change. The positioning before the detailed Nuxt 4 migration section is logical.

The note at lines 60-62 appropriately flags that this section is subject to change, which is important for an experimental feature.

danielroe and others added 2 commits October 16, 2025 22:14
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@danielroe danielroe merged commit 0b65203 into main Oct 17, 2025
56 of 59 checks passed
@danielroe danielroe deleted the feat/compat-env-api branch October 17, 2025 05:38
This was referenced Oct 17, 2025
@github-actions github-actions bot mentioned this pull request Oct 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants