Skip to content

Conversation

@danielroe
Copy link
Member

🔗 Linked issue

📚 Description

this is an initial step to make vite plugins compatible with the environment api

@bolt-new-by-stackblitz
Copy link

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

@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 10, 2025

Open in StackBlitz

@nuxt/kit

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

nuxt

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

@nuxt/rspack-builder

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

@nuxt/schema

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

@nuxt/vite-builder

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

@nuxt/webpack-builder

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

commit: 2db2381

@coderabbitai
Copy link

coderabbitai bot commented Oct 10, 2025

Walkthrough

The PR reorganises Nuxt's Vite integration: it streamlines the client build config in packages/vite/src/client.ts by removing bespoke resolve.alias, HMR/server-CORS overrides, Rollup output customization and dynamic dev-server middleware. It adds new internal plugins (AnalyzePlugin, DevServerPlugin, EnvironmentsPlugin, LayerDepOptimizePlugin, ReplacePlugin, VitePluginCheckerPlugin), rewrites SSRStylesPlugin and adjusts StableEntryPlugin to be environment-scoped. Import paths for ViteNode-related modules were moved to the plugins directory and the server pipeline now includes the vite-plugin-checker integration while several legacy dev-only and optimizeDeps customisations were removed.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 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 and accurately summarises the primary change in this pull request, namely refactoring Vite plugins to support the environment API, and follows conventional commit style without extraneous detail.
Description Check ✅ Passed The description states that this pull request is an initial step to make Vite plugins compatible with the environment API, which directly aligns with the implemented changes and is therefore on-topic.
✨ 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/vite-plugins

📜 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 f19f9bf and 2db2381.

📒 Files selected for processing (1)
  • packages/vite/src/server.ts (3 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/server.ts
🧬 Code graph analysis (1)
packages/vite/src/server.ts (1)
packages/vite/src/plugins/vite-plugin-checker.ts (1)
  • VitePluginCheckerPlugin (5-23)

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: 7

Caution

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

⚠️ Outside diff range comments (1)
packages/vite/src/runtime/vite-node-shared.mjs (1)

231-286: Request-level retries don’t run; promise is returned (not awaited)

sendRequest only retries connectSocket failures; timeouts/connection drops after connect reject the returned promise and bypass the retry loop. Await the request promise inside the loop so errors trigger retries.

Apply this diff:

-  for (let requestAttempt = 0; requestAttempt <= MAX_RETRY_ATTEMPTS; requestAttempt++) {
+  for (let requestAttempt = 0; requestAttempt <= MAX_RETRY_ATTEMPTS; requestAttempt++) {
     try {
-      const socket = await connectSocket()
-
-      return new Promise((resolve, reject) => {
+      await connectSocket()
+      const result = await new Promise((resolve, reject) => {
         const timeoutId = setTimeout(() => {
           pendingRequests.delete(requestId)
           reject(new Error(`Request timeout after ${REQUEST_TIMEOUT_MS}ms for type: ${type}`))
         }, REQUEST_TIMEOUT_MS)
@@
         try {
           socket.write(fullMessage)
         } catch (error) {
           clearTimeout(timeoutId)
           pendingRequests.delete(requestId)
           reject(error)
         }
-      })
+      })
+      return result
     } catch (error) {
       lastError = error
       if (requestAttempt < MAX_RETRY_ATTEMPTS) {
         const delay = calculateRetryDelay(requestAttempt)
         await new Promise(resolve => setTimeout(resolve, delay))
         // clear current connection state to force reconnection
         if (clientSocket) {
           clientSocket.destroy()
           clientSocket = undefined
         }
         currentConnectPromise = undefined
+        continue
       }
     }
   }
🧹 Nitpick comments (6)
packages/vite/src/plugins/analyze.ts (1)

25-50: Optional: reduce noise in size stats

Consider adding legalComments: 'none' to the esbuild transform to avoid emitted licence comments skewing minified size comparisons.

-                  transform(module.code || '', { minify: true })
+                  transform(module.code || '', { minify: true, legalComments: 'none' })
packages/vite/src/plugins/dev-server.ts (3)

91-101: Safer route matching for dev handlers

Dynamic regex from variable input can be fragile and expose ReDoS risks. Prefer compiling routes with a safe library (e.g. path-to-regexp) or, at minimum, pre-validate patterns and avoid .*.

Example:

// import { pathToRegexp } from 'path-to-regexp'
devHandlerRegexes.push(pathToRegexp(handler.route))

Note: You already escape meta characters and anchor the pattern, which helps; this is a robustness suggestion. Based on static analysis hints.


77-83: Middleware insertion relies on function name

Detecting viteTransformMiddleware by Function.name is brittle across versions/minification. Keep the current fallback (append), but consider a more robust heuristic (e.g. insert before first stack entry whose route is '' and handles transform, or expose a hook upstream).


104-112: Micro-optimisation: cache Vite routes

You rebuild viteRoutes on each request. Cache once after server start and invalidate only if the stack changes (rare).

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

45-46: Remove unused idRefMap

idRefMap is written but not read anywhere in this file. Drop it to reduce noise.

-  const idRefMap: Record<string, string> = {}
...
-            idRefMap[relativeToSrcDir(file)] = ref
...
-            idRefMap[relativeToSrcDir(resolved.id)] = ref

Also applies to: 263-265, 290-291


188-191: Clarify inBundle check

!!relativeToSrcDir(moduleId) is always truthy for valid paths, so inBundle becomes effectively isVue(moduleId) || isEntry. If that’s intentional, add a short comment; otherwise refine the condition.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 002c92c and 04b43f5.

📒 Files selected for processing (13)
  • packages/vite/src/client.ts (2 hunks)
  • packages/vite/src/plugins/analyze.ts (1 hunks)
  • packages/vite/src/plugins/dev-server.ts (1 hunks)
  • packages/vite/src/plugins/environments.ts (1 hunks)
  • packages/vite/src/plugins/layer-dep-optimize.ts (1 hunks)
  • packages/vite/src/plugins/replace.ts (1 hunks)
  • packages/vite/src/plugins/ssr-styles.ts (1 hunks)
  • packages/vite/src/plugins/stable-entry.ts (1 hunks)
  • packages/vite/src/plugins/vite-node.ts (1 hunks)
  • packages/vite/src/plugins/vite-plugin-checker.ts (1 hunks)
  • packages/vite/src/runtime/vite-node-shared.mjs (2 hunks)
  • packages/vite/src/server.ts (2 hunks)
  • packages/vite/src/vite.ts (3 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/vite-node.ts
  • packages/vite/src/server.ts
  • packages/vite/src/plugins/environments.ts
  • packages/vite/src/plugins/stable-entry.ts
  • packages/vite/src/plugins/vite-plugin-checker.ts
  • packages/vite/src/plugins/layer-dep-optimize.ts
  • packages/vite/src/plugins/analyze.ts
  • packages/vite/src/plugins/replace.ts
  • packages/vite/src/client.ts
  • packages/vite/src/plugins/ssr-styles.ts
  • packages/vite/src/plugins/dev-server.ts
  • packages/vite/src/vite.ts
🧠 Learnings (1)
📚 Learning: 2024-11-05T15:22:54.759Z
Learnt from: GalacticHypernova
PR: nuxt/nuxt#26468
File: packages/nuxt/src/components/plugins/loader.ts:24-24
Timestamp: 2024-11-05T15:22:54.759Z
Learning: In `packages/nuxt/src/components/plugins/loader.ts`, the references to `resolve` and `distDir` are legacy code from before Nuxt used the new unplugin VFS and will be removed.

Applied to files:

  • packages/vite/src/plugins/vite-node.ts
🧬 Code graph analysis (4)
packages/vite/src/server.ts (1)
packages/vite/src/plugins/vite-plugin-checker.ts (1)
  • VitePluginCheckerPlugin (5-23)
packages/vite/src/client.ts (3)
packages/vite/src/plugins/analyze.ts (1)
  • AnalyzePlugin (7-53)
packages/vite/src/plugins/dev-server.ts (1)
  • DevServerPlugin (10-140)
packages/vite/src/plugins/vite-plugin-checker.ts (1)
  • VitePluginCheckerPlugin (5-23)
packages/vite/src/plugins/ssr-styles.ts (2)
packages/schema/src/types/nuxt.ts (1)
  • Nuxt (89-116)
packages/vite/src/utils/config.ts (1)
  • resolveClientEntry (3-15)
packages/vite/src/vite.ts (3)
packages/vite/src/plugins/replace.ts (1)
  • ReplacePlugin (5-31)
packages/vite/src/plugins/layer-dep-optimize.ts (1)
  • LayerDepOptimizePlugin (6-40)
packages/vite/src/plugins/ssr-styles.ts (1)
  • SSRStylesPlugin (17-297)
🪛 ast-grep (0.39.6)
packages/vite/src/plugins/dev-server.ts

[warning] 93-99: 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(
^${handler.route .replace(/[.+?^${}()|[\]\\]/g, '\\$&') // escape regex syntax characters .replace(/:[^/]+/g, '[^/]+') // dynamic segments (:param) .replace(/\*\*/g, '.*') // double wildcard (**) to match any path .replace(/\*/g, '[^/]*')}$, // single wildcard (*) to match any segment
)
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 (6)
packages/vite/src/runtime/vite-node-shared.mjs (2)

7-10: Typedef path updates look correct

Pointing to ../plugins/vite-node aligns with the refactor.


221-225: JSDoc types aligned with plugins/vite-node

References updated consistently; no issues spotted.

packages/vite/src/server.ts (2)

12-12: Import path switch to plugins/vite-node

Matches the new structure; OK.


33-34: Async checker plugin in SSR pipeline

Using VitePluginCheckerPlugin(nuxt, 'ssr') directly in plugins is acceptable since Vite supports Promise and nested arrays. Manually verify your installed Vite version’s PluginOption type includes Promise support.

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

149-152: Plugin ordering looks good

PublicDirs → Replace → LayerDepOptimize → SSRStyles is sensible for resolves/replacements before style processing.

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

122-125: Async plugins in array are acceptable

Analyze/Checker return async plugin options; Vite handles Promise and nested arrays. Looks fine.

If any issue arises with plugin resolution order, explicitly await them:

-      AnalyzePlugin(nuxt),
-      DevServerPlugin(nuxt),
-      VitePluginCheckerPlugin(nuxt, 'client'),
+      await AnalyzePlugin(nuxt),
+      DevServerPlugin(nuxt),
+      await VitePluginCheckerPlugin(nuxt, 'client'),

@coderabbitai
Copy link

coderabbitai bot commented Oct 10, 2025

Walkthrough

The PR restructures Nuxt’s Vite integration to a plugin-based architecture. It introduces multiple plugins (DevServerPlugin, EnvironmentsPlugin, ReplacePlugin, LayerDepOptimizePlugin, SSRStylesPlugin, VitePluginCheckerPlugin) and updates AnalyzePlugin and StableEntryPlugin. Significant inlined config and server logic in client/server/vite orchestration is removed and delegated to these plugins. Dev server behaviour, environment-specific aliases/outputs, replace handling, layer dep optimisation, SSR CSS handling, and type-checker integration are moved into dedicated plugins. Vite Node imports and runtime typedefs are updated to the plugins path. Function signatures change for AnalyzePlugin and SSRStylesPlugin. Client and server build flows are adjusted to use the new plugins.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% 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 captures the core refactoring goal of the pull request by stating that Vite plugins are being made compatible with the environment API, which aligns directly with the extensive plugin updates in the changeset. It is concise and specific enough for a reviewer to understand the main change at a glance.
Description Check ✅ Passed The description states that this is an initial step to make Vite plugins compatible with the environment API, which correctly relates to the refactoring of multiple plugin files to adopt the environment‐aware approach. Although brief, it remains on-topic and reflects the pull request’s purpose.
✨ 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/vite-plugins

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/vite/src/client.ts (1)

117-119: Remove duplicate TypeCheckPlugin registration

TypeCheckPlugin only injects the vite-plugin-checker runtime entry, which VitePluginCheckerPlugin already handles (plus actual type-checking). Delete its import and invocation in client.ts to avoid duplicate overlays.

-import { TypeCheckPlugin } from './plugins/type-check'
...
-      // Type checking client panel
-      TypeCheckPlugin(nuxt),
🧹 Nitpick comments (12)
packages/vite/src/plugins/vite-node.ts (2)

221-232: Deduplicate socket cleanup logic in buildEnd

buildEnd repeats cleanupSocket. Call the helper to keep behaviour consistent.

-    async buildEnd () {
-      if (socketServer && socketServer.listening) {
-        await new Promise<void>(resolveClose => socketServer!.close(() => resolveClose()))
-      }
-      if (socketPath && !socketPath.startsWith('\\\\.\\pipe\\')) {
-        try {
-          await unlink(socketPath)
-        } catch {
-          // Error is ignored if the file doesn't exist or cannot be unlinked
-        }
-      }
-    },
+    async buildEnd () {
+      await cleanupSocket()
+    },

416-424: Skip unlink for Linux abstract sockets and avoid sync FS call (optional)

currentSocketPath may be an abstract socket ('\0…'), which isn’t a filesystem entry. Guard for that (and consider using async unlink for non-blocking IO).

-  // Clean up existing socket file (Unix only)
-  if (!currentSocketPath.startsWith('\\\\.\\pipe\\')) {
+  // Clean up existing socket file (Unix only; skip Windows pipes and Linux abstract sockets)
+  if (!currentSocketPath.startsWith('\\\\.\\pipe\\') && currentSocketPath.charCodeAt(0) !== 0) {
     try {
-      fs.unlinkSync(currentSocketPath)
+      fs.unlinkSync(currentSocketPath)
     } catch (unlinkError: any) {
       if (unlinkError.code !== 'ENOENT') {
         // Socket cleanup failed, but continue anyway
       }
     }
   }
packages/vite/src/plugins/replace.ts (2)

9-20: Micro-optimisation: return early if there’s nothing to replace

Avoid adding a no-op plugin when no import.meta.* defines exist.

       const replaceOptions: Record<string, string> = Object.create(null)
@@
-      for (const define of [config.define || {}, environment.config.define || {}]) {
+      for (const define of [config.define || {}, environment.config.define || {}]) {
         // ...
       }
+      if (Object.keys(replaceOptions).length === 0) {
+        return false
+      }

22-29: Avoid identifier shadowing between rollup and rolldown replace plugins

Shadowing replacePlugin can be confusing. Rename for clarity and ensure option shape matches rolldown’s expected API.

-import replacePlugin from '@rollup/plugin-replace'
+import rollupReplacePlugin from '@rollup/plugin-replace'
@@
-      if (vite.rolldownVersion) {
-        const { replacePlugin } = await import('rolldown/experimental')
-        return replacePlugin(replaceOptions)
+      if (vite.rolldownVersion) {
+        const { replacePlugin: rolldownReplacePlugin } = await import('rolldown/experimental')
+        return rolldownReplacePlugin(replaceOptions)
       } else {
-        return replacePlugin({ ...replaceOptions, preventAssignment: true })
+        return rollupReplacePlugin({ ...replaceOptions, preventAssignment: true })
       }
packages/vite/src/plugins/stable-entry.ts (1)

67-71: Stale TODO comment

You’ve adopted the environment API here already. Consider removing or updating the TODO to reflect remaining gaps (if any).

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

96-160: Avoid shadowing and clarify variable names in generateBundle (optional)

Inner const file shadows the outer loop variable file. It’s correct due to block scope, but renaming improves readability.

-            for (const css of files) {
-              const file = this.getFileName(css)
+            for (const css of files) {
+              const outFile = this.getFileName(css)
               if (cssImports.has(file)) {
                 continue
               }
-              cssImports.add(file)
+              cssImports.add(outFile)
               const name = `style_${i++}`
-              importStatements.add(genImport(`./${relative(baseDir, file)}`, name))
+              importStatements.add(genImport(`./${relative(baseDir, outFile)}`, name))
               exportNames.add(name)
             }

196-226: Global CSS handling: warn path is good; also import as side-effect when unresolved (optional)

When a global CSS entry can’t be resolved for inlining, you prepend an import — good fallback. Consider normalising nuxt.options.css to string[] earlier to handle objects like { src } consistently.


228-246: Early-return condition may skip static CSS import scanning for non-island modules

transform() returns early when !(id in clientCSSMap) and not an island, which skips the later static import scan. If that’s intentional (teleport only client-observed CSS), ignore. Otherwise, consider moving the static import scan before this guard.

packages/vite/src/plugins/layer-dep-optimize.ts (1)

15-19: Normalise both paths to avoid Windows mismatches

Normalise layer directories too (and rootDir) before startsWith checks; currently only the importer is normalised.

-  const delimitedRootDir = nuxt.options.rootDir + '/'
+  const root = normalize(nuxt.options.rootDir)
+  const delimitedRootDir = root.endsWith('/') ? root : root + '/'

-    if (dirs.app !== nuxt.options.srcDir && !dirs.app.startsWith(delimitedRootDir)) {
-      layerDirs.push(dirs.app)
+    if (dirs.app !== nuxt.options.srcDir) {
+      const appDir = normalize(dirs.app)
+      if (!appDir.startsWith(delimitedRootDir)) {
+        layerDirs.push(appDir)
+      }
     }

Also applies to: 29-36

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

19-51: Optionally gate analyse to build mode.

Visualizer and generateBundle are no-ops in dev but still add plugin overhead. Consider enabling only when !nuxt.options.dev.

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

23-31: Consider scoping base override to the client environment.

Setting base: './' globally may affect SSR tooling unintentionally. If only the client build needs a relative base, move this into configEnvironment('client').

packages/vite/src/plugins/dev-server.ts (1)

91-101: Dynamic regex from routes: safe but consider path-to-regexp for robustness.

You escape and normalise well; still, using a proven router pattern compiler (e.g. path-to-regexp) reduces future maintenance and ReDoS risks.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 002c92c and 8500a2e.

📒 Files selected for processing (13)
  • packages/vite/src/client.ts (2 hunks)
  • packages/vite/src/plugins/analyze.ts (1 hunks)
  • packages/vite/src/plugins/dev-server.ts (1 hunks)
  • packages/vite/src/plugins/environments.ts (1 hunks)
  • packages/vite/src/plugins/layer-dep-optimize.ts (1 hunks)
  • packages/vite/src/plugins/replace.ts (1 hunks)
  • packages/vite/src/plugins/ssr-styles.ts (1 hunks)
  • packages/vite/src/plugins/stable-entry.ts (1 hunks)
  • packages/vite/src/plugins/vite-node.ts (1 hunks)
  • packages/vite/src/plugins/vite-plugin-checker.ts (1 hunks)
  • packages/vite/src/runtime/vite-node-shared.mjs (2 hunks)
  • packages/vite/src/server.ts (2 hunks)
  • packages/vite/src/vite.ts (3 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/dev-server.ts
  • packages/vite/src/plugins/replace.ts
  • packages/vite/src/plugins/analyze.ts
  • packages/vite/src/plugins/stable-entry.ts
  • packages/vite/src/server.ts
  • packages/vite/src/plugins/vite-node.ts
  • packages/vite/src/plugins/vite-plugin-checker.ts
  • packages/vite/src/plugins/environments.ts
  • packages/vite/src/plugins/layer-dep-optimize.ts
  • packages/vite/src/client.ts
  • packages/vite/src/vite.ts
  • packages/vite/src/plugins/ssr-styles.ts
🧠 Learnings (1)
📚 Learning: 2024-11-05T15:22:54.759Z
Learnt from: GalacticHypernova
PR: nuxt/nuxt#26468
File: packages/nuxt/src/components/plugins/loader.ts:24-24
Timestamp: 2024-11-05T15:22:54.759Z
Learning: In `packages/nuxt/src/components/plugins/loader.ts`, the references to `resolve` and `distDir` are legacy code from before Nuxt used the new unplugin VFS and will be removed.

Applied to files:

  • packages/vite/src/plugins/vite-node.ts
🧬 Code graph analysis (4)
packages/vite/src/server.ts (1)
packages/vite/src/plugins/vite-plugin-checker.ts (1)
  • VitePluginCheckerPlugin (5-23)
packages/vite/src/client.ts (3)
packages/vite/src/plugins/analyze.ts (1)
  • AnalyzePlugin (7-53)
packages/vite/src/plugins/dev-server.ts (1)
  • DevServerPlugin (10-140)
packages/vite/src/plugins/vite-plugin-checker.ts (1)
  • VitePluginCheckerPlugin (5-23)
packages/vite/src/vite.ts (4)
packages/vite/src/plugins/replace.ts (1)
  • ReplacePlugin (5-31)
packages/vite/src/plugins/layer-dep-optimize.ts (1)
  • LayerDepOptimizePlugin (6-40)
packages/vite/src/plugins/ssr-styles.ts (1)
  • SSRStylesPlugin (17-297)
packages/vite/src/plugins/environments.ts (1)
  • EnvironmentsPlugin (10-84)
packages/vite/src/plugins/ssr-styles.ts (2)
packages/schema/src/types/nuxt.ts (1)
  • Nuxt (89-116)
packages/vite/src/utils/config.ts (1)
  • resolveClientEntry (3-15)
🪛 ast-grep (0.39.6)
packages/vite/src/plugins/dev-server.ts

[warning] 93-99: 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(
^${handler.route .replace(/[.+?^${}()|[\]\\]/g, '\\$&') // escape regex syntax characters .replace(/:[^/]+/g, '[^/]+') // dynamic segments (:param) .replace(/\*\*/g, '.*') // double wildcard (**) to match any path .replace(/\*/g, '[^/]*')}$, // single wildcard (*) to match any segment
)
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). (3)
  • GitHub Check: codeql (javascript-typescript)
  • GitHub Check: build
  • GitHub Check: code
🔇 Additional comments (10)
packages/vite/src/plugins/vite-node.ts (2)

19-21: Import path updates look fine; please confirm resolution across the refactor

Switching to parent-scoped utilities matches the new plugins layout. Just confirm ../dirs, ../utils, and ../utils/config are the intended canonical entry points to avoid duplicate bundles or circular refs.


182-205: Potential hook timing race: ensure the SSR server hook is registered before SSR server creation

configureServer runs for the client environment only, and registers the 'vite:serverCreated' hook. If the SSR Vite server can be created before this hook is registered, the socket server won’t be initialised. Please verify creation order or register this hook earlier (or handle the already-created case).

packages/vite/src/plugins/stable-entry.ts (1)

26-40: Environment gating logic looks good

Applies only in prod with entryImportMap, client env, supported targets, and hashed entry filenames. This aligns with import maps support constraints. LGTM.

Please confirm toArray returns [] for undefined output to avoid accidental truthiness on [undefined].

packages/vite/src/runtime/vite-node-shared.mjs (1)

7-10: Type path move to plugins/vite-node: looks correct; verify runtime packaging

Paths now reference ../plugins/vite-node. Ensure the runtime bundle includes these types/exports after the refactor so downstream JSDoc types resolve, and that the generated dist preserves the same relative structure.

Also applies to: 221-225

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

17-25: No-op in dev and Nitro manifest wiring: sensible

Early return in dev and build:manifest hook to strip CSS where inlined looks sound.

packages/vite/src/server.ts (2)

17-17: Checker integration for SSR looks good

Environment-scoped usage via applyToEnvironment aligns with Vite 6 Environment API. No issues spotted.

Also applies to: 33-34


12-12: No action needed – writeDevServer is correctly exported
Export found in packages/vite/src/plugins/vite-node.ts at line 502.

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

15-16: ViteNodePlugin import path is correct

The ViteNodePlugin function is exported from packages/vite/src/plugins/vite-node.ts, matching the import in client.ts.

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

5-22: LGTM: environment-scoped type checking vite-plugin-checker (^0.11.0) is declared in packages/vite/package.json.

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

3-3: Add missing static import for replacePlugin

The else branch in packages/vite/src/plugins/replace.ts calls replacePlugin(...) without importing it. Insert at the top:

+ import replacePlugin from '@rollup/plugin-replace'

Likely an incorrect or invalid review comment.

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 (3)
packages/vite/src/plugins/dev-server.ts (2)

21-23: Good fix: safe Set construction from possibly undefined exclude

Using item.exclude ?? [] avoids runtime errors. This resolves earlier feedback.


33-36: Good fix: guard config.server before writing cors

Initialising config.server prevents TypeError when setting cors.

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

12-15: Fix boolean build.analyse semantics: true should enable plugin

defu({}, true) → {} so .enabled is undefined and the plugin exits. Normalise boolean to enabled.

-  const analyzeOptions = defu({}, nuxt.options.build.analyze) as Exclude<NuxtOptions['build']['analyze'], boolean>
-  if (!analyzeOptions.enabled) {
-    return
-  }
+  const analyze = nuxt.options.build.analyze
+  if (!analyze) {
+    return
+  }
+  const analyzeOptions = typeof analyze === 'boolean'
+    ? { enabled: true }
+    : defu({ enabled: true }, analyze as Exclude<NuxtOptions['build']['analyze'], boolean>)
+  if (analyzeOptions.enabled === false) {
+    return
+  }
🧹 Nitpick comments (4)
packages/vite/src/plugins/dev-server.ts (3)

79-84: Insert skip-transform middleware before transform deterministically

If viteTransformMiddleware is not found, pushing to the end may place mw after transform. Unshift to guarantee it runs before transform.

-      if (transformHandler === -1) {
-        viteServer.middlewares.stack.push(mw)
-      } else {
+      if (transformHandler === -1) {
+        viteServer.middlewares.stack.unshift(mw)
+      } else {
         viteServer.middlewares.stack.splice(transformHandler, 0, mw)
       }

93-104: Route regex construction from variable input: consider safer, faster approach

Dynamic RegExp can still be error-prone and potentially expensive. Prefer a battle-tested router pattern utility (e.g. path-to-regexp) to compile handler.route safely with anchors and segment semantics, or at least cap greedy patterns.

Based on static analysis hints


114-118: Skip-transform condition likely never triggers when base is "/" (unnecessary base check)

With base "/" the first predicate is always false, so _skip_transform is never set; transform won’t be bypassed for non‑Vite routes. Rely solely on discovered viteRoutes.

-        if (!event.path.startsWith(viteServer.config.base!) && !viteRoutes.some(route => event.path.startsWith(route))) {
+        if (!viteRoutes.some(route => event.path.startsWith(route))) {
           // @ts-expect-error _skip_transform is a private property
           event.node.req._skip_transform = true
         } else if (!useViteCors) {
packages/vite/src/vite.ts (1)

150-154: Filter optional plugins to avoid undefined entries

LayerDepOptimizePlugin and SSRStylesPlugin may return undefined. Filter falsy to keep Vite’s plugin array clean.

-        plugins: [
+        plugins: ([
           // add resolver for files in public assets directories
           PublicDirsPlugin({
             dev: nuxt.options.dev,
             baseURL: nuxt.options.app.baseURL,
           }),
           ReplacePlugin(),
           LayerDepOptimizePlugin(nuxt),
           SSRStylesPlugin(nuxt),
           EnvironmentsPlugin(nuxt),
-        ],
+        ] as (vite.Plugin | undefined)[]).filter(Boolean) as vite.Plugin[],
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 04b43f5 and f19f9bf.

📒 Files selected for processing (3)
  • packages/vite/src/plugins/analyze.ts (1 hunks)
  • packages/vite/src/plugins/dev-server.ts (1 hunks)
  • packages/vite/src/vite.ts (3 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/vite.ts
  • packages/vite/src/plugins/dev-server.ts
  • packages/vite/src/plugins/analyze.ts
🧬 Code graph analysis (1)
packages/vite/src/vite.ts (4)
packages/vite/src/plugins/replace.ts (1)
  • ReplacePlugin (5-31)
packages/vite/src/plugins/layer-dep-optimize.ts (1)
  • LayerDepOptimizePlugin (6-40)
packages/vite/src/plugins/ssr-styles.ts (1)
  • SSRStylesPlugin (17-297)
packages/vite/src/plugins/environments.ts (1)
  • EnvironmentsPlugin (10-84)
🪛 ast-grep (0.39.6)
packages/vite/src/plugins/dev-server.ts

[warning] 95-101: 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(
^${handler.route .replace(/[.+?^${}()|[\]\\]/g, '\\$&') // escape regex syntax characters .replace(/:[^/]+/g, '[^/]+') // dynamic segments (:param) .replace(/\*\*/g, '.*') // double wildcard (**) to match any path .replace(/\*/g, '[^/]*')}$, // single wildcard (*) to match any segment
)
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: build
  • GitHub Check: code
🔇 Additional comments (1)
packages/vite/src/plugins/dev-server.ts (1)

134-138: Handled-state check is solid

Using res.writableEnded || event.handled avoids false 404s when upstream ended the response. LGTM.

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/vite/src/plugins/analyze.ts (1)

12-15: Preserve build.analyze boolean semantics (true should enable plugin)

defu({}, true) => {} so analyzeOptions.enabled is undefined and the plugin exits; build.analyze: true should enable defaults. This is a regression already noted earlier.

-  const analyzeOptions = defu({}, nuxt.options.build.analyze) as Exclude<NuxtOptions['build']['analyze'], boolean>
-  if (!analyzeOptions.enabled) {
-    return
-  }
+  const analyze = nuxt.options.build.analyze
+  if (!analyze) {
+    return
+  }
+  const analyzeOptions = typeof analyze === 'boolean'
+    ? { enabled: true }
+    : defu({ enabled: true }, analyze as Exclude<NuxtOptions['build']['analyze'], boolean>)
+  if (analyzeOptions.enabled === false) {
+    return
+  }
🧹 Nitpick comments (2)
packages/vite/src/vite.ts (1)

123-131: Avoid possible undefined access in assetFileNames

chunk.names[0]! can be undefined for some assets. Use a safe fallback (names[0], then name, then a default).

-              assetFileNames: nuxt.options.dev
-                ? undefined
-                : chunk => withoutLeadingSlash(join(nuxt.options.app.buildAssetsDir, `${sanitizeFilePath(filename(chunk.names[0]!))}.[hash].[ext]`)),
+              assetFileNames: nuxt.options.dev
+                ? undefined
+                : (chunk) => {
+                    const primaryName =
+                      (Array.isArray((chunk as any).names) && (chunk as any).names[0]) ||
+                      (chunk as any).name ||
+                      'asset'
+                    return withoutLeadingSlash(
+                      join(nuxt.options.app.buildAssetsDir, `${sanitizeFilePath(filename(primaryName))}.[hash].[ext]`),
+                    )
+                  },
packages/vite/src/plugins/dev-server.ts (1)

95-103: Harden dynamic route-to-RegExp conversion (ReDoS/perf risk)

Routes are user-configurable. Even with escaping/anchoring, constructing RegExp from variable input risks catastrophic backtracking.

  • Prefer using a proven router/compilator (e.g. path-to-regexp) to compile patterns safely.
  • If staying with strings:
    • Keep anchors (^ $) and escape as you do.
    • Replace patterns with atomic/possessive equivalents where supported, or simplify:
      • Use [^/]+ for :param
      • Use non-greedy segments for */** with explicit path boundaries
    • Consider bounding input length or pre-validating allowed tokens.

Example with path-to-regexp:

import { pathToRegexp } from 'path-to-regexp'
// ...
devHandlerRegexes.push(pathToRegexp(handler.route))

Based on static analysis hints.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 04b43f5 and f19f9bf.

📒 Files selected for processing (3)
  • packages/vite/src/plugins/analyze.ts (1 hunks)
  • packages/vite/src/plugins/dev-server.ts (1 hunks)
  • packages/vite/src/vite.ts (3 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/vite.ts
  • packages/vite/src/plugins/analyze.ts
  • packages/vite/src/plugins/dev-server.ts
🧬 Code graph analysis (2)
packages/vite/src/vite.ts (4)
packages/vite/src/plugins/replace.ts (1)
  • ReplacePlugin (5-31)
packages/vite/src/plugins/layer-dep-optimize.ts (1)
  • LayerDepOptimizePlugin (6-40)
packages/vite/src/plugins/ssr-styles.ts (1)
  • SSRStylesPlugin (17-297)
packages/vite/src/plugins/environments.ts (1)
  • EnvironmentsPlugin (10-84)
packages/vite/src/plugins/analyze.ts (1)
packages/vite/src/vite.ts (1)
  • bundle (31-189)
🪛 ast-grep (0.39.6)
packages/vite/src/plugins/dev-server.ts

[warning] 95-101: 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(
^${handler.route .replace(/[.+?^${}()|[\]\\]/g, '\\$&') // escape regex syntax characters .replace(/:[^/]+/g, '[^/]+') // dynamic segments (:param) .replace(/\*\*/g, '.*') // double wildcard (**) to match any path .replace(/\*/g, '[^/]*')}$, // single wildcard (*) to match any segment
)
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). (19)
  • GitHub Check: test-fixtures (ubuntu-latest, built, rspack, async, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, built, webpack, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, built, vite, default, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, webpack, async, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, built, rspack, async, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, built, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, built, webpack, async, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, built, vite, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, dev, 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 (windows-latest, dev, vite, async, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, dev, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, default, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, rspack, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-on, js, 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-benchmark
  • GitHub Check: typecheck (windows-latest, bundler)

@codspeed-hq
Copy link

codspeed-hq bot commented Oct 10, 2025

CodSpeed Performance Report

Merging #33445 will improve performances by 23.79%

Comparing refactor/vite-plugins (2db2381) with main (002c92c)

Summary

⚡ 1 improvement
✅ 9 untouched

Benchmarks breakdown

Benchmark BASE HEAD Change
initial production build in the minimal test fixture 5.8 s 4.7 s +23.79%

@danielroe danielroe merged commit d989fb8 into main Oct 10, 2025
83 of 84 checks passed
@danielroe danielroe deleted the refactor/vite-plugins branch October 10, 2025 15:44
@github-actions github-actions bot mentioned this pull request Oct 10, 2025
@github-actions github-actions bot mentioned this pull request Oct 23, 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants