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/calm-parents-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@opennextjs/cloudflare": patch
---

Support composable cache in Next 16
7 changes: 1 addition & 6 deletions examples/e2e/experimental/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,11 @@ const nextConfig: NextConfig = {
/* config options here */
cleanDistDir: true,
output: "standalone",
eslint: {
ignoreDuringBuilds: true,
},
cacheComponents: true,
typescript: {
// Ignore type errors during build for now, we'll need to figure this out later
ignoreBuildErrors: true,
},
experimental: {
cacheComponents: true,
},
};

export default nextConfig;
4 changes: 2 additions & 2 deletions examples/e2e/experimental/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"scripts": {
"dev": "next dev --turbopack --port 3004",
"build": "next build",
"build": "next build --webpack",
"start": "next start --port 3004",
"lint": "next lint",
"clean": "rm -rf .turbo node_modules .next .open-next",
Expand All @@ -15,7 +15,7 @@
},
"dependencies": {
"@opennextjs/cloudflare": "workspace:*",
"next": "15.4.2-canary.29",
"next": "catalog:e2e",
"react": "catalog:e2e",
"react-dom": "catalog:e2e"
},
Expand Down
2 changes: 1 addition & 1 deletion examples/e2e/experimental/src/app/api/revalidate/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { revalidateTag } from "next/cache";

export function GET() {
revalidateTag("fullyTagged");
revalidateTag("fullyTagged", "max");
return new Response("DONE");
}
2 changes: 0 additions & 2 deletions examples/e2e/experimental/src/app/ppr/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { DynamicComponent } from "@/components/dynamic";
import { StaticComponent } from "@/components/static";
import { Suspense } from "react";

export const experimental_ppr = true;

export default function PPRPage() {
return (
<div>
Expand Down
3 changes: 3 additions & 0 deletions examples/e2e/experimental/src/app/use-cache/ssr/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ export default async function Page() {
<div>
<h1>Cache</h1>
<p>{_headers.get("accept") ?? "No accept headers"}</p>
<h2>cached:</h2>
<Suspense fallback={<p>Loading...</p>}>
<FullyCachedComponent />
</Suspense>
<h2>cached (with tag):</h2>
<Suspense fallback={<p>Loading...</p>}>
<FullyCachedComponentWithTag />
</Suspense>
<h2>isr:</h2>
<Suspense fallback={<p>Loading...</p>}>
<ISRComponent />
</Suspense>
Expand Down
6 changes: 3 additions & 3 deletions examples/e2e/experimental/src/components/cached.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { unstable_cacheLife, unstable_cacheTag } from "next/cache";
import { cacheLife, cacheTag } from "next/cache";

export async function FullyCachedComponent() {
"use cache";
Expand All @@ -11,7 +11,7 @@ export async function FullyCachedComponent() {

export async function FullyCachedComponentWithTag() {
"use cache";
unstable_cacheTag("fullyTagged");
cacheTag("fullyTagged");
return (
<div>
<p data-testid="fully-cached-with-tag">{Date.now()}</p>
Expand All @@ -21,7 +21,7 @@ export async function FullyCachedComponentWithTag() {

export async function ISRComponent() {
"use cache";
unstable_cacheLife({
cacheLife({
stale: 1,
revalidate: 5,
});
Expand Down
4 changes: 2 additions & 2 deletions examples/e2e/experimental/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
Expand All @@ -22,6 +22,6 @@
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],
"exclude": ["node_modules"]
}
2 changes: 1 addition & 1 deletion packages/cloudflare/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"dependencies": {
"@ast-grep/napi": "0.40.0",
"@dotenvx/dotenvx": "catalog:",
"@opennextjs/aws": "3.9.6",
"@opennextjs/aws": "3.9.7",
"cloudflare": "^4.4.1",
"enquirer": "^2.4.1",
"glob": "catalog:",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from "./next-server.js";

describe("Next Server", () => {
const nextServerCode = `
const next15ServerCode = `
class NextNodeServer extends _baseserver.default {
constructor(options){
// Initialize super class
Expand Down Expand Up @@ -168,8 +168,27 @@ class NextNodeServer extends _baseserver.default {
// ...
}`;

const next16ServerCode = `
class NextNodeServer extends _baseserver.default {
// ...

async loadCustomCacheHandlers() {
const { cacheMaxMemorySize, cacheHandlers } = this.nextConfig;
if (!cacheHandlers) return;
// If we've already initialized the cache handlers interface, don't do it
// again.
if (!(0, _handlers.initializeCacheHandlers)(cacheMaxMemorySize)) return;
for (const [kind, handler] of Object.entries(cacheHandlers)){
if (!handler) continue;
(0, _handlers.setCacheHandler)(kind, (0, _interopdefault.interopDefault)(await dynamicImportEsmDefault((0, _formatdynamicimportpath.formatDynamicImportPath)(this.distDir, handler))));
}
}
// ...
}
`;

test("build ID", () => {
expect(computePatchDiff("next-server.js", nextServerCode, buildIdRule)).toMatchInlineSnapshot(`
expect(computePatchDiff("next-server.js", next15ServerCode, buildIdRule)).toMatchInlineSnapshot(`
"Index: next-server.js
===================================================================
--- next-server.js
Expand Down Expand Up @@ -206,7 +225,7 @@ class NextNodeServer extends _baseserver.default {
});

test("cache handler", () => {
expect(computePatchDiff("next-server.js", nextServerCode, createCacheHandlerRule("manifest")))
expect(computePatchDiff("next-server.js", next15ServerCode, createCacheHandlerRule("manifest")))
.toMatchInlineSnapshot(`
"Index: next-server.js
===================================================================
Expand Down Expand Up @@ -234,9 +253,10 @@ class NextNodeServer extends _baseserver.default {
`);
});

test("composable cache handler", () => {
expect(computePatchDiff("next-server.js", nextServerCode, createComposableCacheHandlersRule("manifest")))
.toMatchInlineSnapshot(`
test("composable cache handler (Next 15)", () => {
expect(
computePatchDiff("next-server.js", next15ServerCode, createComposableCacheHandlersRule("manifest"))
).toMatchInlineSnapshot(`
"Index: next-server.js
===================================================================
--- next-server.js
Expand Down Expand Up @@ -268,8 +288,38 @@ class NextNodeServer extends _baseserver.default {
`);
});

test("composable cache handler (Next 16)", () => {
expect(
computePatchDiff("next-server.js", next16ServerCode, createComposableCacheHandlersRule("manifest"))
).toMatchInlineSnapshot(`
"Index: next-server.js
===================================================================
--- next-server.js
+++ next-server.js
@@ -1,10 +1,15 @@
-
class NextNodeServer extends _baseserver.default {
// ...

async loadCustomCacheHandlers() {
- const { cacheMaxMemorySize, cacheHandlers } = this.nextConfig;
+ const cacheHandlers = null;
+const handlersSymbol = Symbol.for('@next/cache-handlers');
+const handlersMapSymbol = Symbol.for('@next/cache-handlers-map');
+const handlersSetSymbol = Symbol.for('@next/cache-handlers-set');
+globalThis[handlersMapSymbol] = new Map();
+globalThis[handlersMapSymbol].set("default", require('manifest').default);
+globalThis[handlersSetSymbol] = new Set(globalThis[handlersMapSymbol].values());
if (!cacheHandlers) return;
// If we've already initialized the cache handlers interface, don't do it
// again.
if (!(0, _handlers.initializeCacheHandlers)(cacheMaxMemorySize)) return;
"
`);
});

test("disable node middleware", () => {
expect(computePatchDiff("next-server.js", nextServerCode, disableNodeMiddlewareRule))
expect(computePatchDiff("next-server.js", next15ServerCode, disableNodeMiddlewareRule))
.toMatchInlineSnapshot(`
"Index: next-server.js
===================================================================
Expand Down Expand Up @@ -312,7 +362,8 @@ class NextNodeServer extends _baseserver.default {
});

test("attachRequestMeta", () => {
expect(computePatchDiff("next-server.js", nextServerCode, attachRequestMetaRule)).toMatchInlineSnapshot(`
expect(computePatchDiff("next-server.js", next15ServerCode, attachRequestMetaRule))
.toMatchInlineSnapshot(`
"Index: next-server.js
===================================================================
--- next-server.js
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,11 @@ fix: |-
export function createComposableCacheHandlersRule(handlerPath: string) {
return `
rule:
pattern: "const { cacheHandlers } = this.nextConfig.experimental;"
# matches
# - const { cacheHandlers } = this.nextConfig.experimental; pre Next 16
# - const { cacheMaxMemorySize, cacheHandlers } = this.nextConfig; from Next 16
kind: lexical_declaration
regex: cacheHandlers
inside:
kind: method_definition
has:
Expand Down
Loading
Loading