Skip to content

Commit 69807b1

Browse files
fix(cache): gate the middleware Cache Components patch on the app config
Cache interception alone made the generated middleware bundle's shape build-critical for apps that never render Cache Components routes.
1 parent 1aa2525 commit 69807b1

2 files changed

Lines changed: 30 additions & 6 deletions

File tree

packages/cloudflare/src/cli/build/patches/plugins/cache-components.spec.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -256,28 +256,44 @@ ${unrelatedIdleStartCheck}`;
256256
`);
257257
});
258258

259-
test("patches cache interception in the generated external middleware", () => {
260-
mockFs({
261-
"/output/middleware/handler.mjs": `export async function cacheInterceptor(event) {
259+
const middlewareBundle = `export async function cacheInterceptor(event) {
262260
let localizedPath = event.rawPath;
263261
const isISR = Object.keys(PrerenderManifest?.routes ?? {}).includes(localizedPath);
264262
if (isISR) {
265263
return generateResult(event);
266264
}
267265
return event;
268-
}`,
266+
}`;
267+
268+
function mockMiddlewareBuild(nextConfig: object, middleware = middlewareBundle) {
269+
mockFs({
270+
"/app/.next/required-server-files.json": JSON.stringify({ config: nextConfig }),
271+
"/output/middleware/handler.mjs": middleware,
269272
});
270273

271-
patchMiddlewareCacheComponents({
274+
return {
275+
appBuildOutputPath: "/app",
272276
outputDir: "/output",
273277
config: { dangerous: { enableCacheInterception: true } },
274-
} as BuildOptions);
278+
} as BuildOptions;
279+
}
280+
281+
test("patches cache interception in the generated external middleware", () => {
282+
patchMiddlewareCacheComponents(mockMiddlewareBuild({ cacheComponents: true }));
275283

276284
expect(readFileSync("/output/middleware/handler.mjs", "utf8")).toContain(
277285
'route.renderingMode === "PARTIALLY_STATIC"'
278286
);
279287
});
280288

289+
// Cache interception alone must not make the middleware bundle's shape build-critical.
290+
test("leaves the middleware alone when the app does not use Cache Components", () => {
291+
const buildOpts = mockMiddlewareBuild({}, "export function unrelated() {}");
292+
293+
expect(() => patchMiddlewareCacheComponents(buildOpts)).not.toThrow();
294+
expect(readFileSync("/output/middleware/handler.mjs", "utf8")).toBe("export function unrelated() {}");
295+
});
296+
281297
// The flag moved across Next canaries; missing a spelling would silently skip the patches.
282298
test.each([
283299
[{ cacheComponents: true }, true],

packages/cloudflare/src/cli/build/patches/plugins/cache-components.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { existsSync, readFileSync, writeFileSync } from "node:fs";
22
import path from "node:path";
33

4+
import { loadConfig } from "@opennextjs/aws/adapters/config/util.js";
45
import type { BuildOptions } from "@opennextjs/aws/build/helper.js";
56
import { patchCode } from "@opennextjs/aws/build/patch/astCodePatcher.js";
67
import type { ContentUpdater, Plugin } from "@opennextjs/aws/plugins/content-updater.js";
@@ -112,12 +113,19 @@ export function patchCacheComponentsScheduler(contents: string, runtimePath: str
112113
/**
113114
* Cache interception is compiled into the external middleware before the server bundle plugins run,
114115
* so patch its generated output at the boundary where Cloudflare takes ownership of the AWS build.
116+
*
117+
* Only apps combining Cache Components with cache interception hit the unresumable shell, so apps
118+
* without the flag must not depend on the shape of the generated middleware.
115119
*/
116120
export function patchMiddlewareCacheComponents(buildOpts: BuildOptions): void {
117121
if (buildOpts.config.dangerous?.enableCacheInterception !== true) {
118122
return;
119123
}
120124

125+
if (!usesCacheComponents(loadConfig(path.join(buildOpts.appBuildOutputPath, ".next")))) {
126+
return;
127+
}
128+
121129
const middlewarePath = path.join(buildOpts.outputDir, "middleware", "handler.mjs");
122130
if (!existsSync(middlewarePath)) {
123131
throw new Error("Cannot patch cache interception because the middleware bundle is missing");

0 commit comments

Comments
 (0)