Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/evil-rabbits-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@opennextjs/cloudflare": patch
---

fix: Respect trailing slash config for \_next/image route in worker
2 changes: 1 addition & 1 deletion examples/playground15/app/api/signal/revalidate/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { revalidatePath } from "next/cache";
export const dynamic = "force-dynamic";

export async function GET() {
revalidatePath("/signal");
revalidatePath("/signal/");

return new Response("ok");
}
11 changes: 11 additions & 0 deletions examples/playground15/app/image/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Image from "next/image";

import tomineImg from "../../public/tomine.webp";

export default function Page() {
return (
<div>
<Image src={tomineImg} alt="Picture of Tomine" />
</div>
);
}
4 changes: 2 additions & 2 deletions examples/playground15/e2e/base.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ test.describe("playground/base", () => {
});

test("returns correct information about the request from a route handler", async ({ page, baseURL }) => {
const res = await page.request.get("/api/request");
const res = await page.request.get("/api/request/");
// Next.js can fall back to `localhost:3000` or `n` if it doesn't get the host - neither of these are expected.
const expectedURL = `${baseURL}/api/request`;
const expectedURL = `${baseURL}/api/request/`;
await expect(res.json()).resolves.toEqual({ nextUrl: expectedURL, url: expectedURL });
});

Expand Down
10 changes: 10 additions & 0 deletions examples/playground15/e2e/image.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { test, expect } from "@playwright/test";

test.describe("next/image with trailing slash", () => {
test("next/image with trailing slash", async ({ page }) => {
await page.goto("/image");
await expect(page.getByAltText("Picture of Tomine")).toBeVisible();
// The trailing slash should only be there if trailingSlash is enabled in next.config.ts
expect(await page.getAttribute("img", "src")).toMatch(/^\/_next\/image\//);
});
});
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { initOpenNextCloudflareForDev, getDeploymentId } from "@opennextjs/cloudflare";
import { NextConfig } from "next";

initOpenNextCloudflareForDev();

/** @type {import('next').NextConfig} */
const nextConfig = {
const nextConfig: NextConfig = {
typescript: { ignoreBuildErrors: true },
eslint: { ignoreDuringBuilds: true },
experimental: {
// Generate source map to validate the fix for opennextjs/opennextjs-cloudflare#341
serverSourceMaps: true,
},
deploymentId: getDeploymentId(),
trailingSlash: true,
};

export default nextConfig;
Binary file added examples/playground15/public/tomine.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions packages/cloudflare/src/cli/build/open-next/compile-init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export async function compileInit(options: BuildOptions, wranglerConfig: Unstabl
const nextConfig = loadConfig(path.join(options.appBuildOutputPath, ".next"));
const basePath = nextConfig.basePath ?? "";
const deploymentId = nextConfig.deploymentId ?? "";
const trailingSlash = nextConfig.trailingSlash ?? false;

await build({
entryPoints: [initPath],
Expand All @@ -31,6 +32,7 @@ export async function compileInit(options: BuildOptions, wranglerConfig: Unstabl
__NEXT_BASE_PATH__: JSON.stringify(basePath),
__ASSETS_RUN_WORKER_FIRST__: JSON.stringify(wranglerConfig.assets?.run_worker_first ?? false),
__DEPLOYMENT_ID__: JSON.stringify(deploymentId),
__TRAILING_SLASH__: JSON.stringify(trailingSlash),
},
});
}
3 changes: 3 additions & 0 deletions packages/cloudflare/src/cli/templates/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ function initRuntime() {
__BUILD_TIMESTAMP_MS__,
__NEXT_BASE_PATH__,
__ASSETS_RUN_WORKER_FIRST__,
__TRAILING_SLASH__,
// The external middleware will use the convertTo function of the `edge` converter
// by default it will try to fetch the request, but since we are running everything in the same worker
// we need to use the request as is.
Expand Down Expand Up @@ -155,4 +156,6 @@ declare global {
var __ASSETS_RUN_WORKER_FIRST__: boolean | string[] | undefined;
// Deployment ID
var __DEPLOYMENT_ID__: string;
// Next trailingSlash config
var __TRAILING_SLASH__: boolean;
}
5 changes: 4 additions & 1 deletion packages/cloudflare/src/cli/templates/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ export default {
}

// Fallback for the Next default image loader.
if (url.pathname === `${globalThis.__NEXT_BASE_PATH__}/_next/image`) {
if (
url.pathname ===
`${globalThis.__NEXT_BASE_PATH__}/_next/image${globalThis.__TRAILING_SLASH__ ? "/" : ""}`
) {
const imageUrl = url.searchParams.get("url") ?? "";
return await fetchImage(env.ASSETS, imageUrl, ctx);
}
Expand Down