diff --git a/.changeset/slimy-houses-punch.md b/.changeset/slimy-houses-punch.md new file mode 100644 index 00000000..5033bf7d --- /dev/null +++ b/.changeset/slimy-houses-punch.md @@ -0,0 +1,7 @@ +--- +"@opennextjs/cloudflare": patch +--- + +fix: enable using the `direct` queue for isr + +The `direct` mode is not recommended for use in production as it does not de-dupe requests. diff --git a/examples/e2e/app-router/app/api/isr/route.ts b/examples/e2e/app-router/app/api/isr/route.ts index 1fc3e43d..03bf5003 100644 --- a/examples/e2e/app-router/app/api/isr/route.ts +++ b/examples/e2e/app-router/app/api/isr/route.ts @@ -1,5 +1,3 @@ -import fs from "node:fs/promises"; -import path from "node:path"; import type { NextRequest } from "next/server"; import { NextResponse } from "next/server"; @@ -7,12 +5,20 @@ export const dynamic = "force-dynamic"; // This endpoint simulates an on demand revalidation request export async function GET(request: NextRequest) { - const cwd = process.cwd(); - const prerenderManifest = await fs.readFile(path.join(cwd, ".next/prerender-manifest.json"), "utf-8"); - const manifest = JSON.parse(prerenderManifest); + let manifest: { preview: { previewModeId: string } }; + // this fails at build time when next.js tries to evaluate the route + try { + // @ts-expect-error + const prerenderManifest = await import(/* webpackIgnore: true */ "./.next/prerender-manifest.json"); + manifest = prerenderManifest.default; + } catch { + return new Response(null, { status: 500 }); + } + const previewId = manifest.preview.previewModeId; - const result = await fetch(`https://${request.headers.get("host")}/isr`, { + const host = request.headers.get("host"); + const result = await fetch(`http${host?.includes("localhost") ? "" : "s"}://${host}/isr`, { headers: { "x-prerender-revalidate": previewId }, method: "HEAD", }); diff --git a/examples/e2e/app-router/e2e/isr.revalidate.test.ts b/examples/e2e/app-router/e2e/isr.revalidate.test.ts index a8463c94..3df688e0 100644 --- a/examples/e2e/app-router/e2e/isr.revalidate.test.ts +++ b/examples/e2e/app-router/e2e/isr.revalidate.test.ts @@ -1,7 +1,6 @@ import { expect, test } from "@playwright/test"; -// Cache (and revalidation) is currently not supported: https://github.com/opennextjs/opennextjs-cloudflare/issues/105 -test.skip("Test revalidate", async ({ request }) => { +test("Test revalidate", async ({ request }) => { const result = await request.get("/api/isr"); expect(result.status()).toEqual(200); diff --git a/examples/e2e/app-router/e2e/isr.test.ts b/examples/e2e/app-router/e2e/isr.test.ts index 58f32ede..934925e9 100644 --- a/examples/e2e/app-router/e2e/isr.test.ts +++ b/examples/e2e/app-router/e2e/isr.test.ts @@ -1,7 +1,6 @@ import { expect, test } from "@playwright/test"; -// ISR is currently not supported: https://github.com/opennextjs/opennextjs-cloudflare/issues/105 -test.skip("Incremental Static Regeneration", async ({ page }) => { +test("Incremental Static Regeneration", async ({ page }) => { test.setTimeout(45000); await page.goto("/"); await page.locator("[href='/isr']").click(); @@ -41,8 +40,7 @@ test.skip("Incremental Static Regeneration", async ({ page }) => { expect(newTime).not.toEqual(finalTime); }); -// ISR is currently not supported: https://github.com/opennextjs/opennextjs-cloudflare/issues/105 -test.skip("headers", async ({ page }) => { +test("headers", async ({ page }) => { let responsePromise = page.waitForResponse((response) => { return response.status() === 200; }); diff --git a/examples/e2e/app-router/open-next.config.ts b/examples/e2e/app-router/open-next.config.ts index b5de97ab..f1f956ca 100644 --- a/examples/e2e/app-router/open-next.config.ts +++ b/examples/e2e/app-router/open-next.config.ts @@ -7,8 +7,9 @@ const config: OpenNextConfig = { wrapper: "cloudflare-node", converter: "edge", incrementalCache: async () => cache, + queue: "direct", + // Unused implementation tagCache: "dummy", - queue: "dummy", }, }, diff --git a/packages/cloudflare/src/cli/build/utils/ensure-cf-config.ts b/packages/cloudflare/src/cli/build/utils/ensure-cf-config.ts index 9a3138a3..84b7668e 100644 --- a/packages/cloudflare/src/cli/build/utils/ensure-cf-config.ts +++ b/packages/cloudflare/src/cli/build/utils/ensure-cf-config.ts @@ -1,3 +1,4 @@ +import logger from "@opennextjs/aws/logger.js"; import type { OpenNextConfig } from "@opennextjs/aws/types/open-next.js"; /** @@ -12,8 +13,9 @@ export function ensureCloudflareConfig(config: OpenNextConfig) { dftMaybeUseCache: config.default?.override?.incrementalCache === "dummy" || typeof config.default?.override?.incrementalCache === "function", - dftUseDummyTagCacheAndQueue: - config.default?.override?.tagCache === "dummy" && config.default?.override?.queue === "dummy", + dftUseDummyTagCache: config.default?.override?.tagCache === "dummy", + dftMaybeUseQueue: + config.default?.override?.queue === "dummy" || config.default?.override?.queue === "direct", disableCacheInterception: config.dangerous?.enableCacheInterception !== true, mwIsMiddlewareExternal: config.middleware?.external == true, mwUseCloudflareWrapper: config.middleware?.override?.wrapper === "cloudflare-edge", @@ -21,6 +23,10 @@ export function ensureCloudflareConfig(config: OpenNextConfig) { mwUseFetchProxy: config.middleware?.override?.proxyExternalRequest === "fetch", }; + if (config.default?.override?.queue === "direct") { + logger.warn("The direct mode queue is not recommended for use in production."); + } + if (Object.values(requirements).some((satisfied) => !satisfied)) { throw new Error( "The `open-next.config.ts` should have a default export like this:\n\n" + @@ -31,7 +37,7 @@ export function ensureCloudflareConfig(config: OpenNextConfig) { converter: "edge", incrementalCache: "dummy" | function, tagCache: "dummy", - queue: "dummy", + queue: "dummy" | "direct", }, },