diff --git a/packages/vinext/src/routing/pages-router.ts b/packages/vinext/src/routing/pages-router.ts index 2b0193a1..8ca88696 100644 --- a/packages/vinext/src/routing/pages-router.ts +++ b/packages/vinext/src/routing/pages-router.ts @@ -72,8 +72,13 @@ async function scanPageRoutes( "**/*", pagesDir, matcher.extensions, - (name: string) => name === "api" || name.startsWith("_"), + (name: string) => name.startsWith("_"), )) { + // Ignore top-level pages/api/* only (nested */api/* directories are valid page routes) + if (file === "api" || file.startsWith(`api${path.sep}`)) { + continue; + } + const route = fileToRoute(file, pagesDir, matcher); if (route) routes.push(route); } diff --git a/tests/fixtures/pages-basic/pages/blog/api/index.tsx b/tests/fixtures/pages-basic/pages/blog/api/index.tsx new file mode 100644 index 00000000..fdd38354 --- /dev/null +++ b/tests/fixtures/pages-basic/pages/blog/api/index.tsx @@ -0,0 +1,3 @@ +export default function BlogApiPage() { + return
Blog API page route
; +} diff --git a/tests/routing.test.ts b/tests/routing.test.ts index 71a9ffb2..9f00d8be 100644 --- a/tests/routing.test.ts +++ b/tests/routing.test.ts @@ -57,6 +57,15 @@ describe("pagesRouter - route discovery", () => { expect(patterns).not.toContain("/_document"); expect(patterns).not.toContain("/_error"); }); + + it("keeps nested api directories as page routes", async () => { + const routes = await pagesRouter(FIXTURE_DIR); + + const nestedApiRoute = routes.find((r) => r.pattern === "/blog/api"); + expect(nestedApiRoute).toBeDefined(); + expect(nestedApiRoute!.filePath).toContain(path.join("blog", "api", "index.tsx")); + }); + }); describe("matchRoute - URL matching", () => {