mirror of
https://github.com/cloudflare/vinext.git
synced 2026-09-14 19:04:59 +08:00
ea08183af2
* fix: respect pageExtensions in prerender and exclude _ prefixed api files - cli.ts: hoist resolveNextConfig so pageExtensions is passed to printBuildReport - run-prerender.ts: pass config.pageExtensions to pagesRouter/apiRouter (previously defaulted to ["tsx","ts","jsx","js"] regardless of next.config.js) - pages-router.ts (scanApiRoutes): add _ prefix exclude, matching pages/ behaviour - report.ts: tighten printBuildReport signature (pageExtensions required, not optional) - tests: add coverage for _ prefix exclusion in pages/api and pageExtensions filtering * PR #591 reviewed: 1 bug found, rest LGTM Co-authored-by: james-elicx <james-elicx@users.noreply.github.com> * remove files * fix: pass pageExtensions to appRouter in prerender; harden afterEach cache cleanup - run-prerender.ts: appRouter(appDir) was missing config.pageExtensions, same class of bug as the pagesRouter/apiRouter fix — App Router prerender would scan with default extensions regardless of next.config.js - build-report.test.ts: afterEach now invalidates both app and pages route caches so a test failure can't leak cached routes into subsequent tests --------- Co-authored-by: ask-bonk[bot] <ask-bonk[bot]@users.noreply.github.com> Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>
121 lines
4.8 KiB
TypeScript
121 lines
4.8 KiB
TypeScript
import path from "node:path";
|
|
import os from "node:os";
|
|
import fs from "node:fs/promises";
|
|
import { describe, expect, it } from "vite-plus/test";
|
|
import { appRouter, invalidateAppRouteCache } from "../packages/vinext/src/routing/app-router.js";
|
|
import {
|
|
apiRouter,
|
|
invalidateRouteCache,
|
|
pagesRouter,
|
|
} from "../packages/vinext/src/routing/pages-router.js";
|
|
|
|
async function makeTempDir(prefix: string): Promise<string> {
|
|
return fs.mkdtemp(path.join(os.tmpdir(), prefix));
|
|
}
|
|
|
|
describe("pageExtensions route discovery", () => {
|
|
it("discovers app/page.mdx routes when pageExtensions includes mdx", async () => {
|
|
// Ported from Next.js MDX e2e setup:
|
|
// test/e2e/app-dir/mdx/next.config.ts
|
|
// https://github.com/vercel/next.js/blob/canary/test/e2e/app-dir/mdx/next.config.ts
|
|
const tmpRoot = await makeTempDir("vinext-app-ext-mdx-");
|
|
const appDir = path.join(tmpRoot, "app");
|
|
try {
|
|
await fs.mkdir(path.join(appDir, "about"), { recursive: true });
|
|
await fs.writeFile(
|
|
path.join(appDir, "layout.tsx"),
|
|
"export default function Layout({ children }: { children: React.ReactNode }) { return <html><body>{children}</body></html>; }",
|
|
);
|
|
await fs.writeFile(
|
|
path.join(appDir, "page.tsx"),
|
|
"export default function Page() { return <div>home</div>; }",
|
|
);
|
|
await fs.writeFile(path.join(appDir, "about", "page.mdx"), "# About");
|
|
|
|
invalidateAppRouteCache();
|
|
const routes = await appRouter(appDir, ["tsx", "ts", "jsx", "js", "mdx"]);
|
|
const patterns = routes.filter((r) => r.pagePath).map((r) => r.pattern);
|
|
expect(patterns).toContain("/about");
|
|
} finally {
|
|
await fs.rm(tmpRoot, { recursive: true, force: true });
|
|
invalidateAppRouteCache();
|
|
}
|
|
});
|
|
|
|
it("does not discover app/page.mdx routes when mdx is not configured", async () => {
|
|
const tmpRoot = await makeTempDir("vinext-app-ext-no-mdx-");
|
|
const appDir = path.join(tmpRoot, "app");
|
|
try {
|
|
await fs.mkdir(path.join(appDir, "about"), { recursive: true });
|
|
await fs.writeFile(
|
|
path.join(appDir, "layout.tsx"),
|
|
"export default function Layout({ children }: { children: React.ReactNode }) { return <html><body>{children}</body></html>; }",
|
|
);
|
|
await fs.writeFile(
|
|
path.join(appDir, "page.tsx"),
|
|
"export default function Page() { return <div>home</div>; }",
|
|
);
|
|
await fs.writeFile(path.join(appDir, "about", "page.mdx"), "# About");
|
|
|
|
invalidateAppRouteCache();
|
|
const routes = await appRouter(appDir, ["tsx", "ts", "jsx", "js"]);
|
|
const patterns = routes.filter((r) => r.pagePath).map((r) => r.pattern);
|
|
expect(patterns).not.toContain("/about");
|
|
} finally {
|
|
await fs.rm(tmpRoot, { recursive: true, force: true });
|
|
invalidateAppRouteCache();
|
|
}
|
|
});
|
|
|
|
it("excludes _ prefixed files from api routes", async () => {
|
|
// Next.js ignores _-prefixed files in pages/api/ the same way it does in pages/.
|
|
const tmpRoot = await makeTempDir("vinext-api-underscore-");
|
|
const pagesDir = path.join(tmpRoot, "pages");
|
|
try {
|
|
await fs.mkdir(path.join(pagesDir, "api"), { recursive: true });
|
|
await fs.writeFile(
|
|
path.join(pagesDir, "api", "hello.ts"),
|
|
"export async function GET() { return Response.json({}); }",
|
|
);
|
|
await fs.writeFile(path.join(pagesDir, "api", "_helpers.ts"), "// internal helper");
|
|
|
|
invalidateRouteCache(pagesDir);
|
|
const apiRoutes = await apiRouter(pagesDir);
|
|
const patterns = apiRoutes.map((r) => r.pattern);
|
|
|
|
expect(patterns).toContain("/api/hello");
|
|
expect(patterns).not.toContain("/api/_helpers");
|
|
} finally {
|
|
await fs.rm(tmpRoot, { recursive: true, force: true });
|
|
invalidateRouteCache(pagesDir);
|
|
}
|
|
});
|
|
|
|
it("discovers pages and api files using configured pageExtensions", async () => {
|
|
const tmpRoot = await makeTempDir("vinext-pages-ext-mdx-");
|
|
const pagesDir = path.join(tmpRoot, "pages");
|
|
try {
|
|
await fs.mkdir(path.join(pagesDir, "api"), { recursive: true });
|
|
await fs.writeFile(
|
|
path.join(pagesDir, "index.tsx"),
|
|
"export default function Page() { return <div>home</div>; }",
|
|
);
|
|
await fs.writeFile(path.join(pagesDir, "about.mdx"), "# About");
|
|
await fs.writeFile(
|
|
path.join(pagesDir, "api", "hello.mdx"),
|
|
"export default function handler() {}",
|
|
);
|
|
|
|
invalidateRouteCache(pagesDir);
|
|
const pageRoutes = await pagesRouter(pagesDir, ["tsx", "ts", "jsx", "js", "mdx"]);
|
|
const apiRoutes = await apiRouter(pagesDir, ["tsx", "ts", "jsx", "js", "mdx"]);
|
|
|
|
expect(pageRoutes.map((r) => r.pattern)).toContain("/about");
|
|
expect(apiRoutes.map((r) => r.pattern)).toContain("/api/hello");
|
|
} finally {
|
|
await fs.rm(tmpRoot, { recursive: true, force: true });
|
|
invalidateRouteCache(pagesDir);
|
|
}
|
|
});
|
|
});
|