diff --git a/examples/playground/app/api/env/route.ts b/examples/playground/app/api/env/route.ts index 24dfdc74..7a49c54d 100644 --- a/examples/playground/app/api/env/route.ts +++ b/examples/playground/app/api/env/route.ts @@ -1,3 +1,8 @@ +// This test relies on using `.dev.vars` to set the environment to `development` +// However `next build` is not passed an environment, so we do not want to cache +// the output. +export const dynamic = "force-dynamic"; + export async function GET() { return new Response(JSON.stringify(process.env)); } diff --git a/examples/playground/app/isr/[id]/dynamic/page.tsx b/examples/playground/app/isr/[id]/dynamic/page.tsx new file mode 100644 index 00000000..e7640c65 --- /dev/null +++ b/examples/playground/app/isr/[id]/dynamic/page.tsx @@ -0,0 +1,30 @@ +// Imported from https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration +interface Post { + id: string; + title: string; + content: string; +} + +// Next.js will invalidate the cache when a +// request comes in, at most once every 1 hour. +export const revalidate = 3600; + +// We'll prerender only the params from `generateStaticParams` at build time. +// If a request comes in for a path that hasn't been generated, +// Next.js will server-render the page on-demand. +export const dynamicParams = true; + +export async function generateStaticParams() { + return [{ id: "1" }, { id: "2" }, { id: "3" }]; +} + +export default async function Page({ params }: { params: Promise<{ id: string }> }) { + const id = (await params).id; + const post: Post = await fetch(`https://api.vercel.app/blog/${id}`).then((res) => res.json()); + return ( +
+

{post.title}

+

{post.content}

+
+ ); +} diff --git a/examples/playground/app/isr/[id]/no-dynamic/page.tsx b/examples/playground/app/isr/[id]/no-dynamic/page.tsx new file mode 100644 index 00000000..556fb617 --- /dev/null +++ b/examples/playground/app/isr/[id]/no-dynamic/page.tsx @@ -0,0 +1,29 @@ +// Imported from https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration +interface Post { + id: string; + title: string; + content: string; +} + +// Next.js will invalidate the cache when a +// request comes in, at most once every 1 hour. +export const revalidate = 3600; + +// We'll prerender only the params from `generateStaticParams` at build time. +// If a request comes in for a path that hasn't been generated, it will 404. +export const dynamicParams = false; + +export async function generateStaticParams() { + return [{ id: "1" }, { id: "2" }, { id: "3" }]; +} + +export default async function Page({ params }: { params: Promise<{ id: string }> }) { + const id = (await params).id; + const post: Post = await fetch(`https://api.vercel.app/blog/${id}`).then((res) => res.json()); + return ( +
+

{post.title}

+

{post.content}

+
+ ); +} diff --git a/examples/playground/e2e/isr.spec.ts b/examples/playground/e2e/isr.spec.ts new file mode 100644 index 00000000..4a922ace --- /dev/null +++ b/examples/playground/e2e/isr.spec.ts @@ -0,0 +1,30 @@ +import { test, expect, type APIResponse } from "@playwright/test"; +import type { BinaryLike } from "node:crypto"; +import { createHash } from "node:crypto"; + +test("Generated pages exist", async ({ page }) => { + const generatedIds = [1, 2, 3]; + let res: APIResponse; + for (const id of generatedIds) { + res = await page.request.get(`/isr/${id}/dynamic`); + expect(res.status()).toBe(200); + res = await page.request.get(`/isr/${id}/no-dynamic`); + expect(res.status()).toBe(200); + } +}); + +test("Non generated pages 404 when dynamic is false", async ({ page }) => { + const generatedIds = [4, 5, 6]; + for (const id of generatedIds) { + const res = await page.request.get(`/isr/${id}/no-dynamic`); + expect(res.status()).toBe(404); + } +}); + +test("Non generated pages are generated when dynamic is true", async ({ page }) => { + const generatedIds = [4, 5, 6]; + for (const id of generatedIds) { + const res = await page.request.get(`/isr/${id}/dynamic`); + expect(res.status()).toBe(200); + } +}); diff --git a/examples/playground/open-next.config.ts b/examples/playground/open-next.config.ts index d976688e..ef2e20a9 100644 --- a/examples/playground/open-next.config.ts +++ b/examples/playground/open-next.config.ts @@ -1,14 +1,15 @@ import type { OpenNextConfig } from "@opennextjs/aws/types/open-next.js"; +import cache from "@opennextjs/cloudflare/kv-cache"; const config: OpenNextConfig = { default: { override: { wrapper: "cloudflare-node", converter: "edge", + incrementalCache: async () => cache, + queue: "direct", // Unused implementation - incrementalCache: "dummy", tagCache: "dummy", - queue: "dummy", }, }, diff --git a/examples/playground/wrangler.json b/examples/playground/wrangler.json index 29a8ced6..53a0fbe6 100644 --- a/examples/playground/wrangler.json +++ b/examples/playground/wrangler.json @@ -8,6 +8,12 @@ "directory": ".open-next/assets", "binding": "ASSETS" }, + "kv_namespaces": [ + { + "binding": "NEXT_CACHE_WORKERS_KV", + "id": "" + } + ], "vars": { "hello": "Hello World from the cloudflare context!" }