Skip to content

vercel-functions: skip default-export rule for App Router pages#73

Open
mvanhorn wants to merge 1 commit intovercel:mainfrom
mvanhorn:fix/false-positive-default-export-app-router
Open

vercel-functions: skip default-export rule for App Router pages#73
mvanhorn wants to merge 1 commit intovercel:mainfrom
mvanhorn:fix/false-positive-default-export-app-router

Conversation

@mvanhorn
Copy link
Copy Markdown

Fixes the false-positive Use named exports (GET, POST, PUT, DELETE) instead of default export for route handlers ERROR that 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.

Refs anthropics/claude-code#54989 (the bug was reported in claude-code, but the validation rule lives here in skills/vercel-functions/SKILL.md lines 25-29).

Problem

The current rule:

validate:
  -
    pattern: export\s+default\s+function
    message: 'Use named exports (GET, POST, PUT, DELETE) instead of default export for route handlers'
    severity: error

matches any default-exported function. Next.js App Router requires default exports for page.tsx, layout.tsx, loading.tsx, error.tsx, not-found.tsx, sitemap.ts, and template.tsx, so the rule fires [ERROR] on every Write/Edit to any of those files. The reporter has a 44-page project where this fires constantly and cannot be suppressed without disabling the entire skill.

Fix

Add a skipIfFileContains regex (the same shape used in skills/routing-middleware/SKILL.md) that suppresses the rule when the file shows strong signals of being an App Router file rather than a route handler:

Signal Catches
'use client' directive client components
export const metadata|dynamic|revalidate|fetchCache|runtime App Router config exports
export default function …(Page|Layout|Loading|Error|NotFound|Sitemap|Template|Default) (also lower-case sitemap/robots/opengraph/manifest) App Router file conventions
<[A-Z]… (capitalised JSX tag) any JSX-returning page
{ children } destructure layouts and templates
MetadataRoute. sitemap/robots/manifest helpers
from 'next/(font|image|link|navigation|headers|cookies)' App Router imports

Each of these is overwhelmingly common in App Router pages and overwhelmingly absent from route handlers. A buggy export default function handler inside a route.ts still fires the rule because none of the patterns match.

Why skipIfFileContains and not a new field

The reporter suggested onlyIfFilename / skipIfFilename. Adding a new schema field requires the downstream consumer (claude-code) to honor it, otherwise the field is inert and the false positive remains. skipIfFileContains is already supported and already used by skills/routing-middleware/SKILL.md, so this PR fixes the bug today without coordinating new field support.

Verification

Tested the regex against representative content for each affected file plus the buggy route handler case (Python regex used for portability):

page.tsx (server)                          fires=True  skip=True  -> skipped (correct)
page.tsx (client - 'use client')           fires=True  skip=True  -> skipped (correct)
layout.tsx (RootLayout)                    fires=True  skip=True  -> skipped (correct)
layout.tsx (MarketingLayout)               fires=True  skip=True  -> skipped (correct)
sitemap.ts                                 fires=True  skip=True  -> skipped (correct)
loading.tsx                                fires=True  skip=True  -> skipped (correct)
not-found.tsx                              fires=True  skip=True  -> skipped (correct)
route.ts (BUG: export default fn handler)  fires=True  skip=False -> flagged (correct)
route.ts (BUG: export default with NextResponse) fires=True  skip=False -> flagged (correct)

Plugin-level checks still pass:

$ bun run validate
PASSED with 1 warning(s)

$ bun run build
build:skills — 0 updated, 10 unchanged, 0 errors
build:from-skills — 0 updated, 8 unchanged, 0 errors

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.
Copy link
Copy Markdown
Collaborator

@Melkeydev Melkeydev left a comment

Choose a reason for hiding this comment

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

approved but:

  • can you resolve the conflicts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants