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!"
}