refactor(nitro,rspack,vite,webpack): move cors handling into nitro builder#34048
refactor(nitro,rspack,vite,webpack): move cors handling into nitro builder#34048
Conversation
|
|
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
WalkthroughThis PR updates dev-server middleware across Nitro, Vite and Webpack. It changes the Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/webpack/src/webpack.ts (1)
138-173: Improve the error object at line 143.The thrown error object
{ status: 403 }is missing amessageproperty, which is inconsistent with the ErrorPartial pattern used elsewhere in this PR (see packages/vite/src/plugins/vite-node.ts lines 277, 288, 314, 321 where errors include both status and message).💬 Proposed fix to add message property
- throw { status: 403 } + throw { status: 403, message: 'Cross-site request blocked in no-cors mode' }packages/vite/src/plugins/dev-server.ts (1)
113-188:resolveHandler()isn’t caching (outerhandleris never assigned) + query strings can trigger false 404s.This currently rebuilds proxy patterns per request, and
$-anchoreddevHandlerRegexescan fail whenurlincludes?….Proposed fix
function resolveHandler () { if (handler) { return handler } // Pre-process proxy configuration once const proxyConfig = viteServer.config.server.proxy const proxyPatterns: Array<{ type: 'string' | 'regex', value: string | RegExp }> = [] if (proxyConfig) { for (const key in proxyConfig) { if (key.startsWith('^')) { try { proxyPatterns.push({ type: 'regex', value: new RegExp(key) }) } catch { // Invalid regex, skip this key } } else { proxyPatterns.push({ type: 'string', value: key }) } } } function isProxyPath (path: string) { for (const pattern of proxyPatterns) { if (pattern.type === 'regex' && (pattern.value as RegExp).test(path)) { return true } else if (pattern.type === 'string' && path.startsWith(pattern.value as string)) { return true } } return false } - return defineEventHandler(async (event: H3V1Event | H3V2Event) => { - const url = 'url' in event ? event.url.pathname + event.url.search + event.url.hash : event.path - const isBasePath = url.startsWith(viteServer.config.base!) + handler = defineEventHandler(async (event: H3V1Event | H3V2Event) => { + const fullUrl = 'url' in event ? (event.url.pathname + event.url.search + event.url.hash) : event.path + const pathname = fullUrl.split('?')[0]!.split('#')[0]! + const isBasePath = pathname.startsWith(viteServer.config.base!) // Check if this is a vite-handled route or proxy path let isViteRoute = isBasePath if (!isViteRoute) { // Check vite middleware routes (must be done per-request as middleware stack can change) for (const viteRoute of viteServer.middlewares.stack) { - if (viteRoute.route.length > 1 && url.startsWith(viteRoute.route)) { + if (viteRoute.route.length > 1 && pathname.startsWith(viteRoute.route)) { isViteRoute = true break } } // Check proxy paths - isViteRoute ||= isProxyPath(url) + isViteRoute ||= isProxyPath(pathname) } const { req, res } = 'runtime' in event ? event.runtime!.node! : event.node if (!isViteRoute) { // @ts-expect-error _skip_transform is a private property req._skip_transform = true } // Workaround: vite devmiddleware modifies req.url const _originalPath = req.url await new Promise((resolve, reject) => { viteServer.middlewares.handle(req as IncomingMessage, res as ServerResponse, (err: Error) => { req.url = _originalPath return err ? reject(err) : resolve(null) }) }) // if vite has not handled the request, we want to send a 404 for paths which are not in any static base or dev server handlers - if (url.startsWith(nuxt.options.app.buildAssetsDir) && !staticBases.some(baseURL => url.startsWith(baseURL)) && !devHandlerRegexes.some(regex => regex.test(url))) { + if (pathname.startsWith(nuxt.options.app.buildAssetsDir) && !staticBases.some(baseURL => pathname.startsWith(baseURL)) && !devHandlerRegexes.some(regex => regex.test(pathname))) { throw { status: 404 } satisfies ErrorPartial } }) + return handler }
🤖 Fix all issues with AI agents
In @packages/nitro-server/src/index.ts:
- Around line 864-875: Hoist the one-time check of options?.cors?.() out of the
per-request handler by evaluating it when registering the hook (store a boolean
like corsEnabled) so the defineEventHandler does not call options.cors() on
every request; inside the handler call handleCors(event,
nuxt.options.devServer.cors) only when corsEnabled is true. When setting the
Vary header (currently via setHeader(event, 'Vary', 'Origin')), preserve any
existing Vary value instead of overwriting: read the current header, append
"Origin" if not already present (comma-separated), and write the combined value
back via setHeader. Ensure you update the nuxt.hook('server:devHandler') block
and the devMiddlewareHandler.set(...) closure to use the hoisted corsEnabled and
the merged Vary header logic.
🧹 Nitpick comments (4)
packages/webpack/src/webpack.ts (1)
228-232: Consider the maintainability of the localdefineEventHandlerimplementation.This local implementation of
defineEventHandleravoids depending on a specific h3 version, but it duplicates framework internals by relying on the__is_handler__convention. If h3's internal marking mechanism changes, this code will silently fail to work correctly.Consider adding a comment documenting:
- Why this local implementation is necessary
- The expected lifecycle for removing it
- Any risks if h3's handler marking changes
Alternatively, explore whether this can be imported from a common location to reduce duplication.
packages/vite/src/plugins/vite-node.ts (1)
277-321: Verify error consistency across all throw sites.The error objects follow a mostly consistent pattern with
satisfies ErrorPartialannotations:
- Lines 277, 288, 321: Include
statusandmessage- Line 314: Includes
dataandmessagebut omitsstatusLine 314's module fetch error differs by including error data but no status code. Verify whether this is intentional or if it should include
status: 500to indicate a server error.Based on learnings, error handling patterns should be used consistently.
🔍 Suggested verification and optional fix
Consider whether line 314 should include a status code:
- throw { data: errorData, message: err.message || 'Error fetching module' } satisfies ErrorPartial + throw { status: 500, data: errorData, message: err.message || 'Error fetching module' } satisfies ErrorPartialThis would align all error objects to include a status code for consistent error handling downstream.
packages/vite/src/vite-node-entry.ts (1)
51-70: Type_errasErrorPartial(currently implicitlyany) and consider addingstatusCode/statusMessagefor compatibility.Right now
let _errdiscards the type-safety fromsatisfies ErrorPartial, and consumers commonly key offstatusCode/statusMessagerather thanstatusText.Proposed tweak
- let _err + let _err: ErrorPartial try { const { message, stack } = formatViteError(errorData, id) _err = { + statusCode: 500, + statusMessage: 'Vite Error', statusText: 'Vite Error', message, stack, } satisfies ErrorPartial } catch (formatError) { consola.warn('Internal nuxt error while formatting vite-node error. Please report this!', formatError) const message = `[vite-node] [TransformError] ${errorData?.message || '-'}` consola.error(message, errorData) throw { + statusCode: 500, + statusMessage: 'Vite Error', statusText: 'Vite Error', message, stack: `${message}\nat ${id}\n` + (errorData?.stack || ''), } satisfies ErrorPartial }packages/vite/src/plugins/dev-server.ts (1)
200-204: Avoid potential confusion with the localdefineEventHandlername (it’s not H3’s helper).Consider renaming to something like
markAsH3Handlerto make intent explicit.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
packages/rspack/package.jsonis excluded by!**/package.jsonpackages/vite/package.jsonis excluded by!**/package.jsonpackages/webpack/package.jsonis excluded by!**/package.jsonpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml,!pnpm-lock.yaml
📒 Files selected for processing (8)
packages/nitro-server/src/augments.tspackages/nitro-server/src/index.tspackages/vite/src/plugins/dev-server.tspackages/vite/src/plugins/vite-node.tspackages/vite/src/types.tspackages/vite/src/vite-node-entry.tspackages/vite/src/vite-node.tspackages/webpack/src/webpack.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Follow standard TypeScript conventions and best practices
Files:
packages/vite/src/types.tspackages/vite/src/plugins/vite-node.tspackages/vite/src/vite-node.tspackages/vite/src/plugins/dev-server.tspackages/nitro-server/src/augments.tspackages/nitro-server/src/index.tspackages/vite/src/vite-node-entry.tspackages/webpack/src/webpack.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx,js,jsx,vue}: Use clear, descriptive variable and function names
Add comments only to explain complex logic or non-obvious implementations
Keep functions focused and manageable (generally under 50 lines), and extract complex logic into separate domain-specific files
Remove code that is not used or needed
Use error handling patterns consistently
Files:
packages/vite/src/types.tspackages/vite/src/plugins/vite-node.tspackages/vite/src/vite-node.tspackages/vite/src/plugins/dev-server.tspackages/nitro-server/src/augments.tspackages/nitro-server/src/index.tspackages/vite/src/vite-node-entry.tspackages/webpack/src/webpack.ts
🧠 Learnings (2)
📚 Learning: 2025-11-25T11:42:16.132Z
Learnt from: CR
Repo: nuxt/nuxt PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-25T11:42:16.132Z
Learning: Applies to **/*.{ts,tsx,js,jsx,vue} : Use error handling patterns consistently
Applied to files:
packages/vite/src/plugins/vite-node.tspackages/vite/src/vite-node.tspackages/vite/src/vite-node-entry.ts
📚 Learning: 2024-11-05T15:22:54.759Z
Learnt from: GalacticHypernova
Repo: nuxt/nuxt PR: 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.tspackages/vite/src/plugins/dev-server.tspackages/nitro-server/src/index.ts
🧬 Code graph analysis (3)
packages/vite/src/plugins/vite-node.ts (2)
packages/vite/src/types.ts (1)
ErrorPartial(4-4)packages/nuxt/src/app/index.ts (1)
FetchResult(8-8)
packages/nitro-server/src/augments.ts (2)
packages/schema/src/index.ts (1)
HookResult(8-8)packages/schema/src/types/hooks.ts (1)
HookResult(16-16)
packages/vite/src/vite-node-entry.ts (1)
packages/vite/src/types.ts (1)
ErrorPartial(4-4)
⏰ 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: codeql (javascript-typescript)
🔇 Additional comments (7)
packages/vite/src/types.ts (1)
1-4: LGTM! Clean type definition for error compatibility.The
ErrorPartialtype provides a flexible union for handling errors across h3 v1 and v2, usingPartialto allow subset representations. This is used consistently throughout the Vite integration (packages/vite/src/plugins/vite-node.ts and packages/vite/src/vite-node-entry.ts).packages/vite/src/plugins/vite-node.ts (1)
23-23: LGTM! Proper import of ErrorPartial type.The import supports the transition from h3's
createErrorto plain error objects, aligning with the broader refactoring pattern.packages/vite/src/vite-node.ts (1)
147-151: LGTM! Improved type safety for error handling.The error construction now uses explicit typing
Error & { stack?: string, data?: unknown, status?: number, statusCode?: number }instead of relying on@ts-expect-errorcomments. This provides better type safety whilst maintaining compatibility with bothstatusandstatusCodeproperties.The approach correctly:
- Creates a proper Error instance with message
- Augments it with additional properties from the IPC response
- Supports both status and statusCode for compatibility
packages/nitro-server/src/augments.ts (1)
76-76: LGTM! Backwards-compatible hook signature update.The addition of the optional
optionsparameter with acorsfunction properly supports the CORS refactoring whilst maintaining backwards compatibility. The signature change aligns with the implementations in packages/webpack/src/webpack.ts (line 132) where{ cors: () => true }is passed.packages/webpack/src/webpack.ts (2)
124-132: The non-null assertion pattern and CORS configuration are established practices for 8000 H3 compatibility in dev middleware.This code implements a deliberate compatibility layer between H3 event objects and legacy webpack middleware. The pattern
'runtime' in event ? event.runtime!.node! : event.nodeis consistently used throughout the codebase (also at line 141 in the same file and in vite dev-server) to handle both H3 v1 and v2 event structures, as evidenced by the type definitionGenericHandler = (event: H3V1Event | H3V2Event).The CORS configuration
{ cors: () => true }is intentionally permissive for development purposes; this is a documented H3 pattern for local development servers where cross-origin requests should be allowed.The type casts (
as IncomingMessage,as ServerResponse) are necessary because webpack-dev-middleware and webpack-hot-middleware expect Node.js-style request and response objects, requiring TypeScript casts when providing H3 event properties. This is standard middleware integration practice.No changes needed — this is consistent with established patterns in the codebase.
2-3: Dual H3 version compatibility is intentionally implemented and properly handled.The imports of H3Event from both
h3-nextandh3enable the webpack builder to work with both versions. The code correctly uses structural feature detection ('runtime' in event) to handle the different H3Event structures across versions, making this pattern appropriate for the transition period. No consolidation needed at this time.packages/vite/src/plugins/dev-server.ts (1)
189-196: CORS hook wiring looks sensible; please sanity-check the H3 v1/v2 event-shape guards against the actualh3-next/h3versions in use.Specifically
'url' in eventand'runtime' in eventassumptions.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @packages/nitro-server/src/index.ts:
- Around line 864-875: The code uses event.path which breaks on H3 v2 where the
path is at event.url.pathname; update the dev middleware handler (inside
nuxt.hook and devMiddlewareHandler.set / defineEventHandler) to compute a
cross-version request path (e.g. const requestPath = event.path ??
event.url?.pathname) and use that requestPath when calling
options.cors(requestPath) and when determining CORS preflight via
handleCors(event, ...), leaving the rest of the handler (setHeader and return
h(event)) unchanged.
In @packages/vite/src/plugins/dev-server.ts:
- Around line 215-219: Remove the legacy sentinel assignment in
defineEventHandler: the function should simply return the handler unchanged
instead of using Object.assign to add a __is_handler__ property; update the
defineEventHandler implementation (and any local references) to return handler
directly and delete the unused "__is_handler__" marker so no internal sentinel
is written by defineEventHandler.
🧹 Nitpick comments (1)
packages/vite/src/plugins/dev-server.ts (1)
113-150: Consider renaming for clarity.The outer function
isProxyPathand the cached inner function_isProxyPathshare the same name (one with underscore), which may reduce readability. Consider a more descriptive name like_cachedMatcheror_proxyPathMatcher.♻️ Suggested refactor for clarity
- let _isProxyPath: ((url: string) => boolean) | undefined + let _proxyPathMatcher: ((url: string) => boolean) | undefined function isProxyPath (url: string) { - if (_isProxyPath) { - return _isProxyPath(url) + if (_proxyPathMatcher) { + return _proxyPathMatcher(url) } // Pre-process proxy configuration once const proxyConfig = viteServer.config.server.proxy const proxyPatterns: Array<{ type: 'string' | 'regex', value: string | RegExp }> = [] if (proxyConfig) { for (const key in proxyConfig) { if (key.startsWith('^')) { try { proxyPatterns.push({ type: 'regex', value: new RegExp(key) }) } catch { // Invalid regex, skip this key } } else { proxyPatterns.push({ type: 'string', value: key }) } } } - _isProxyPath = function isProxyPath (path: string) { + _proxyPathMatcher = function (path: string) { for (const pattern of proxyPatterns) { if (pattern.type === 'regex' && (pattern.value as RegExp).test(path)) { return true } else if (pattern.type === 'string' && path.startsWith(pattern.value as string)) { return true } } return false } - return _isProxyPath(url) + return _proxyPathMatcher(url) }
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
packages/rspack/package.jsonis excluded by!**/package.jsonpackages/vite/package.jsonis excluded by!**/package.jsonpackages/webpack/package.jsonis excluded by!**/package.jsonpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml,!pnpm-lock.yaml
📒 Files selected for processing (4)
packages/nitro-server/src/augments.tspackages/nitro-server/src/index.tspackages/vite/src/plugins/dev-server.tspackages/vite/src/vite-node-entry.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/nitro-server/src/augments.ts
- packages/vite/src/vite-node-entry.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Follow standard TypeScript conventions and best practices
Files:
packages/nitro-server/src/index.tspackages/vite/src/plugins/dev-server.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx,js,jsx,vue}: Use clear, descriptive variable and function names
Add comments only to explain complex logic or non-obvious implementations
Keep functions focused and manageable (generally under 50 lines), and extract complex logic into separate domain-specific files
Remove code that is not used or needed
Use error handling patterns consistently
Files:
packages/nitro-server/src/index.tspackages/vite/src/plugins/dev-server.ts
🧠 Learnings (1)
📚 Learning: 2024-11-05T15:22:54.759Z
Learnt from: GalacticHypernova
Repo: nuxt/nuxt PR: 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/nitro-server/src/index.tspackages/vite/src/plugins/dev-server.ts
🧬 Code graph analysis (1)
packages/vite/src/plugins/dev-server.ts (1)
packages/vite/src/types.ts (1)
ErrorPartial(4-4)
🔇 Additional comments (5)
packages/nitro-server/src/index.ts (1)
19-19: LGTM: H3 CORS utilities imported.The additional imports
handleCorsandsetHeaderare appropriate for implementing CORS handling within the Nitro builder.packages/vite/src/plugins/dev-server.ts (4)
5-6: LGTM: Cross-version H3 event type imports.The dual imports with aliasing enable compatibility with both H3 v1 and v2, aligning with the PR's goal of reducing version-specific dependencies.
11-11: LGTM: ErrorPartial type import.Type-only import for cross-version error handling.
190-210: LGTM: CORS decision logic integrated.The hook correctly delegates CORS handling decisions to the Nitro builder via the
corsoption, ensuring CORS is applied only when Vite isn't handling it. The logic appropriately covers Vite base paths, middleware routes, and proxy paths.
152-189: The URL reconstruction on line 153 is correct and safe. Theevent.urlobject in h3-next is a standard WHATWG URL API implementation wherepathname,search, andhashare always defined properties (defaulting to empty strings if absent). Concatenating these properties will not produce undefined values; the operation is valid regardless of whether the URL contains a query string or fragment.No action required.
| nuxt.hook('server:devHandler', (h, options) => { | ||
| devMiddlewareHandler.set(defineEventHandler((event) => { | ||
| if (options.cors(event.path)) { | ||
| const isPreflight = handleCors(event, nuxt.options.devServer.cors) | ||
| if (isPreflight) { | ||
| return null | ||
| } | ||
| setHeader(event, 'Vary', 'Origin') | ||
| } | ||
| return h(event) | ||
| })) | ||
| }) |
There was a problem hiding this comment.
Cross-version H3 event compatibility issue with event.path.
Line 866 accesses event.path, but H3 v2 events use event.url.pathname instead. This will break CORS handling when using H3 v2.
🔧 Proposed fix for cross-version compatibility
- nuxt.hook('server:devHandler', (h, options) => {
- devMiddlewareHandler.set(defineEventHandler((event) => {
- if (options.cors(event.path)) {
+ nuxt.hook('server:devHandler', (h, options) => {
+ devMiddlewareHandler.set(defineEventHandler((event) => {
+ const path = 'url' in event ? event.url.pathname : event.path
+ if (options.cors(path)) {
const isPreflight = handleCors(event, nuxt.options.devServer.cors)
if (isPreflight) {
return null
}
setHeader(event, 'Vary', 'Origin')
}
return h(event)
}))
})📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| nuxt.hook('server:devHandler', (h, options) => { | |
| devMiddlewareHandler.set(defineEventHandler((event) => { | |
| if (options.cors(event.path)) { | |
| const isPreflight = handleCors(event, nuxt.options.devServer.cors) | |
| if (isPreflight) { | |
| return null | |
| } | |
| setHeader(event, 'Vary', 'Origin') | |
| } | |
| return h(event) | |
| })) | |
| }) | |
| nuxt.hook('server:devHandler', (h, options) => { | |
| devMiddlewareHandler.set(defineEventHandler((event) => { | |
| const path = 'url' in event ? event.url.pathname : event.path | |
| if (options.cors(path)) { | |
| const isPreflight = handleCors(event, nuxt.options.devServer.cors) | |
| if (isPreflight) { | |
| return null | |
| } | |
| setHeader(event, 'Vary', 'Origin') | |
| } | |
| return h(event) | |
| })) | |
| }) |
🤖 Prompt for AI Agents
In @packages/nitro-server/src/index.ts around lines 864 - 875, The code uses
event.path which breaks on H3 v2 where the path is at event.url.pathname; update
the dev middleware handler (inside nuxt.hook and devMiddlewareHandler.set /
defineEventHandler) to compute a cross-version request path (e.g. const
requestPath = event.path ?? event.url?.pathname) and use that requestPath when
calling options.cors(requestPath) and when determining CORS preflight via
handleCors(event, ...), leaving the rest of the handler (setHeader and return
h(event)) unchanged.
| type GenericHandler = (event: H3V1Event | H3V2Event) => unknown | Promise<unknown> | ||
|
|
3E9C
||
| function defineEventHandler (handler: GenericHandler): GenericHandler { | ||
| return Object.assign(handler, { __is_handler__: true }) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, examine the dev-server.ts file to understand context
cat -n packages/vite/src/plugins/dev-server.ts | head -250 | tail -50Repository: nuxt/nuxt
Length of output: 2244
🏁 Script executed:
# Check package.json for h3 version specifications
cat package.json | grep -A 5 -B 5 "h3"Repository: nuxt/nuxt
Length of output: 97
🏁 Script executed:
# Search for __is_handler__ usage in the codebase
rg "__is_handler__" --type ts --type tsxRepository: nuxt/nuxt
Length of output: 80
🏁 Script executed:
# Check if there are any imports of defineEventHandler from h3
rg "defineEventHandler" --type ts --type tsx -A 3 -B 3Repository: nuxt/nuxt
Length of output: 80
🏁 Script executed:
# Find package.json locations
fd "package.json" | head -5Repository: nuxt/nuxt
Length of output: 35
🏁 Script executed:
# Search for __is_handler__ without type filter
rg "__is_handler__"Repository: nuxt/nuxt
Length of output: 240
🏁 Script executed:
# Search for H3V1Event and H3V2Event definitions
rg "H3V1Event|H3V2Event" -A 2 -B 2Repository: nuxt/nuxt
Length of output: 2123
🏁 Script executed:
# Check imports at the top of dev-server.ts
head -50 packages/vite/src/plugins/dev-server.tsRepository: nuxt/nuxt
Length of output: 2114
🏁 Script executed:
# Search for how defineEventHandler is used/called in the codebase
rg "defineEventHandler" -A 2 -B 2Repository: nuxt/nuxt
Length of output: 33734
🏁 Script executed:
# Search for how this handler is actually called/used
rg "viteMiddleware" packages/vite/src/plugins/dev-server.ts -B 5 -A 5Repository: nuxt/nuxt
Length of output: 1011
🏁 Script executed:
# Look at the callHook usage to see what h3 expects
rg "callHook.*devHandler" packages/vite/src/plugins/dev-server.ts -B 3 -A 10Repository: nuxt/nuxt
Length of output: 477
🏁 Script executed:
# Search for any comments or documentation about the handler flag
rg "__is_handler__" -B 5 -A 5Repository: nuxt/nuxt
Length of output: 997
🏁 Script executed:
# Check if there are any issues or discussions about h3 version compatibility
fd "README|CHANGELOG" packages/vite | xargs cat 2>/dev/null | head -100Repository: nuxt/nuxt
Length of output: 35
🏁 Script executed:
# Check Nitro integration to see how handlers are processed
rg "server:devHandler" --type ts -B 3 -A 8Repository: nuxt/nuxt
Length of output: 3615
🏁 Script executed:
# Look for h3 package details
fd "package.json" packages/ | xargs grep -l "h3" 2>/dev/null | head -3 | xargs catRepository: nuxt/nuxt
Length of output: 35
🏁 Script executed:
# Check how nitro processes these dev handlers
rg "devHandlers" packages/nitro-server -A 5Repository: nuxt/nuxt
Length of output: 1666
🌐 Web query:
h3 __is_handler__ flag h3-next compatibility
💡 Result:
Short answer: The "is_handler" marker is an internal TypeScript/JS sentinel used by the older h3 (v0.x / "h3" used by Nuxt/h3) typings to identify event/route handlers. h3 v2 / "h3-next" uses a different handler model and does not rely on that private flag — rely on the public APIs (defineHandler / defineEventHandler, isEventHandler, isEvent, or the H3 app/handler abstractions) for compatibility instead of checking is_handler directly.
References:
- h3 (v0.x) type definitions showing the "is_handler" sentinel. [1]
- h3 v2 / "h3-next" docs describing the new handler model (handlers as first-class/event handlers, defineHandler/defineEventHandler, etc.). [2][3]
🏁 Script executed:
# Search for any code that checks __is_handler__ flag
rg "__is_handler__" --type tsRepository: nuxt/nuxt
Length of output: 240
🏁 Script executed:
# Check if isEventHandler or other h3 APIs are used to identify handlers
rg "isEventHandler|isHandler" --type ts -B 2 -A 2Repository: nuxt/nuxt
Length of output: 35
🏁 Script executed:
# Look at the complete flow in nitro-server where the hook is processed
sed -n '80,120p' packages/nitro-server/src/index.tsRepository: nuxt/nuxt
Length of output: 2225
🏁 Script executed:
# Verify h3 imports used in nitro-server
grep -n "from 'h3'" packages/nitro-server/src/index.tsRepository: nuxt/nuxt
Length of output: 244
Remove the unused __is_handler__ flag; h3-next v2 does not recognise or use this internal sentinel.
The __is_handler__: true marker is an internal mechanism from h3 v0.x and is not part of h3-next v2's handler model. The flag is never checked anywhere in the codebase and provides no functional value. Handlers work correctly because they are properly wrapped by h3's defineEventHandler in the Nitro integration. Remove this dead code to maintain clarity and comply with the guideline of removing unnecessary code.
🤖 Prompt for AI Agents
In @packages/vite/src/plugins/dev-server.ts around lines 215 - 219, Remove the
legacy sentinel assignment in defineEventHandler: the function should simply
return the handler unchanged instead of using Object.assign to add a
__is_handler__ property; update the defineEventHandler implementation (and any
local references) to return handler directly and delete the unused
"__is_handler__" marker so no internal sentinel is written by
defineEventHandler.
CodSpeed Performance ReportMerging this PR will not alter performanceComparing Summary
Footnotes |
@nuxt/kit
@nuxt/nitro-server
nuxt
@nuxt/rspack-builder
@nuxt/schema
@nuxt/vite-builder
@nuxt/webpack-builder
commit: |
🔗 Linked issue
📚 Description
this aims to make the nuxt builders less dependent on the specific version of nitro/h3 and leaves that to the nitro builder integration.