mirror of
https://github.com/vercel/vercel-plugin.git
synced 2026-09-14 15:39:47 +08:00
vercel-functions: skip default-export rule for App Router pages (#73)
The rule
pattern: export\s+default\s+function
message: 'Use named exports (GET, POST, ...) instead of default
export for route handlers'
fires on every page.tsx, layout.tsx, loading.tsx, error.tsx, not-found.tsx,
sitemap.ts, and template.tsx in a Next.js App Router project, where a default
export is *required*. Reported in anthropics/claude-code#54989 with concrete
reproduction (a 44-page App Router project firing the error on every page
write/edit).
Add a skipIfFileContains regex that matches the strongest signals of an
App Router file (and not a route handler):
- 'use client' directive
- App Router config exports (metadata / dynamic / revalidate / fetchCache /
runtime)
- export default function whose name ends in Page / Layout / Loading /
Error / NotFound / Sitemap / Template / Default (also lowercase
sitemap / robots / opengraph / manifest for the convention files)
- JSX with a capitalised component tag
- a destructured `{ children }` parameter (layouts / templates)
- a `MetadataRoute` reference (sitemap, robots, manifest helpers)
- imports from next/font, next/image, next/link, next/navigation,
next/headers, next/cookies
Each of these is overwhelmingly common in App Router pages and overwhelmingly
absent from route.ts handlers. A bug `export default function handler` in
a route.ts still fires the rule because none of the patterns match.
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
This commit is contained in:
@@ -4660,7 +4660,8 @@
|
||||
{
|
||||
"pattern": "export\\s+default\\s+function",
|
||||
"message": "Use named exports (GET, POST, PUT, DELETE) instead of default export for route handlers",
|
||||
"severity": "error"
|
||||
"severity": "error",
|
||||
"skipIfFileContains": "(?:^|\\\\n)\\\\s*['\\\"]use\\\\s+client['\\\"]|export\\\\s+const\\\\s+(?:metadata|dynamic|revalidate|fetchCache|runtime)\\\\b|export\\\\s+default\\\\s+(?:async\\\\s+)?function\\\\s+\\\\w*(?:Page|Layout|Loading|Error|NotFound|Sitemap|Template|Default|sitemap|robots|opengraph|manifest)\\\\b|<[A-Z][A-Za-z0-9]*|\\\\{\\\\s*children\\\\s*[,}:]|MetadataRoute\\\\.|from\\\\s+['\\\"]next/(?:font|image|link|navigation|headers|cookies)['\\\"]"
|
||||
},
|
||||
{
|
||||
"pattern": "NextApiRequest|NextApiResponse",
|
||||
|
||||
@@ -27,6 +27,13 @@ validate:
|
||||
pattern: export\s+default\s+function
|
||||
message: 'Use named exports (GET, POST, PUT, DELETE) instead of default export for route handlers'
|
||||
severity: error
|
||||
# Skip on App Router page / layout / loading / error / not-found / sitemap / template / default files,
|
||||
# which require a default export by Next.js convention. Detected via the 'use client' directive,
|
||||
# an App Router config export (metadata, dynamic, revalidate, fetchCache, runtime), an `export default
|
||||
# function` whose name matches an App Router file (Page / Layout / Loading / etc.), or any JSX
|
||||
# element with a capitalised component tag — all signals that the file is a page-style file rather
|
||||
# than a route handler. See anthropics/claude-code#54989.
|
||||
skipIfFileContains: "(?:^|\\n)\\s*['\"]use\\s+client['\"]|export\\s+const\\s+(?:metadata|dynamic|revalidate|fetchCache|runtime)\\b|export\\s+default\\s+(?:async\\s+)?function\\s+\\w*(?:Page|Layout|Loading|Error|NotFound|Sitemap|Template|Default|sitemap|robots|opengraph|manifest)\\b|<[A-Z][A-Za-z0-9]*|\\{\\s*children\\s*[,}:]|MetadataRoute\\.|from\\s+['\"]next/(?:font|image|link|navigation|headers|cookies)['\"]"
|
||||
-
|
||||
pattern: NextApiRequest|NextApiResponse
|
||||
message: 'NextApiRequest/NextApiResponse are Pages Router types — use Web API Request/Response'
|
||||
|
||||
Reference in New Issue
Block a user