Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 7 additions & 0 deletions .changeset/slow-dolphins-sparkle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@opennextjs/cloudflare": patch
---

refactor: retrieve cache handler kv instance inside constructor

The cache handler was retrieving it's KV instance as a static property on the class that was defined at some point during the execution of the Next.js server. This moves the retrieval of the KV instance to happen inside the constructor for the class, so that it is retrieved during instantiation instead.
1 change: 1 addition & 0 deletions packages/cloudflare/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ declare global {
__NEXT_PRIVATE_STANDALONE_CONFIG?: string;
SKIP_NEXT_APP_BUILD?: string;
NEXT_PRIVATE_DEBUG_CACHE?: string;
__OPENNEXT_KV_BINDING_NAME: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@james-elicx Is this documented already?
If not, would you mind sending a PR?
Also maybe add a default value.
Thanks!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention was for this to just be used internally to inline a value into the cache handler, but yeah, it would make sense to let users use it as well

[key: string]: string | Fetcher;
}
}
Expand Down
19 changes: 17 additions & 2 deletions packages/cloudflare/src/cli/build/build-worker.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Plugin, build } from "esbuild";
import { cacheHandlerFileName, patchCache } from "./patches/investigated/patch-cache";
import { cp, readFile, writeFile } from "node:fs/promises";
import { existsSync, readFileSync } from "node:fs";
import { Config } from "../config";
Expand All @@ -8,7 +9,6 @@ import { fileURLToPath } from "node:url";
import { inlineEvalManifest } from "./patches/to-investigate/inline-eval-manifest";
import { inlineMiddlewareManifestRequire } from "./patches/to-investigate/inline-middleware-manifest-require";
import { inlineNextRequire } from "./patches/to-investigate/inline-next-require";
import { patchCache } from "./patches/investigated/patch-cache";
import { patchExceptionBubbling } from "./patches/to-investigate/patch-exception-bubbling";
import { patchFindDir } from "./patches/to-investigate/patch-find-dir";
import { patchReadFile } from "./patches/to-investigate/patch-read-file";
Expand Down Expand Up @@ -53,6 +53,9 @@ export async function buildWorker(config: Config): Promise<void> {

const templateDir = path.join(config.paths.internalPackage, "cli", "templates");

const cacheHandlerEntrypoint = path.join(templateDir, "cache-handler", "index.ts");
const cacheHandlerOutputFile = path.join(config.paths.builderOutput, cacheHandlerFileName);

const workerEntrypoint = path.join(templateDir, "worker.ts");
const workerOutputFile = path.join(config.paths.builderOutput, "index.mjs");

Expand All @@ -66,6 +69,18 @@ export async function buildWorker(config: Config): Promise<void> {
patchWranglerDeps(config);
updateWebpackChunksFile(config);

await build({
entryPoints: [cacheHandlerEntrypoint],
bundle: true,
outfile: cacheHandlerOutputFile,
format: "esm",
target: "esnext",
minify: true,
define: {
"process.env.__OPENNEXT_KV_BINDING_NAME": `"${config.cache.kvBindingName}"`,
},
});

await build({
entryPoints: [workerEntrypoint],
bundle: true,
Expand Down Expand Up @@ -167,7 +182,7 @@ async function updateWorkerBundledCode(workerOutputFile: string, config: Config)
patchedCode = inlineNextRequire(patchedCode, config);
patchedCode = patchFindDir(patchedCode, config);
patchedCode = inlineEvalManifest(patchedCode, config);
patchedCode = patchCache(patchedCode, config);
patchedCode = patchCache(patchedCode);
patchedCode = inlineMiddlewareManifestRequire(patchedCode, config);
patchedCode = patchExceptionBubbling(patchedCode);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
import { Config } from "../../../config";
import path from "node:path";
export const cacheHandlerFileName = "cache-handler.mjs";

/**
* Install the cloudflare KV cache handler
*/
export function patchCache(code: string, config: Config): string {
export function patchCache(code: string): string {
console.log("# patchCache");

const cacheHandler = path.join(config.paths.internalPackage, "cli", "cache-handler", "index.mjs");

const patchedCode = code.replace(
"const { cacheHandler } = this.nextConfig;",
`const cacheHandler = null;
CacheHandler = (await import('${cacheHandler}')).OpenNextCacheHandler;
CacheHandler.maybeKVNamespace = process.env["${config.cache.kvBindingName}"];
CacheHandler = (await import('./${cacheHandlerFileName}')).OpenNextCacheHandler;
`
);

if (patchedCode === code) {
throw new Error("Cache patch not applied");
throw new Error("Patch `patchCache` not applied");
}

return patchedCode;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NEXT_META_SUFFIX, SEED_DATA_DIR } from "../../cache-handler";
import { NEXT_META_SUFFIX, SEED_DATA_DIR } from "../../templates/cache-handler";
import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { Config } from "../../config";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,31 @@ import {
} from "./constants";
import { getSeedBodyFile, getSeedMetaFile, getSeedTextFile, parseCtx } from "./utils";
import type { IncrementalCacheValue } from "next/dist/server/response-cache";
import { KVNamespace } from "@cloudflare/workers-types";
import type { KVNamespace } from "@cloudflare/workers-types";

type CacheEntry = {
lastModified: number;
value: IncrementalCacheValue | null;
};

export class OpenNextCacheHandler implements CacheHandler {
static maybeKVNamespace: KVNamespace | undefined = undefined;
protected kv: KVNamespace | undefined;

protected debug: boolean = !!process.env.NEXT_PRIVATE_DEBUG_CACHE;

constructor(protected ctx: CacheHandlerContext) {}
constructor(protected ctx: CacheHandlerContext) {
this.kv = process.env[process.env.__OPENNEXT_KV_BINDING_NAME] as KVNamespace | undefined;
}

async get(...args: Parameters<CacheHandler["get"]>): Promise<CacheHandlerValue | null> {
const [key, _ctx] = args;
const ctx = parseCtx(_ctx);

if (this.debug) console.log(`cache - get: ${key}, ${ctx?.kind}`);

if (OpenNextCacheHandler.maybeKVNamespace !== undefined) {
if (this.kv !== undefined) {
try {
const value = await OpenNextCacheHandler.maybeKVNamespace.get<CacheEntry>(key, "json");
const value = await this.kv.get<CacheEntry>(key, "json");
if (value) return value;
} catch (e) {
console.error(`Failed to get value for key = ${key}: ${e}`);
Expand Down Expand Up @@ -115,7 +117,7 @@ export class OpenNextCacheHandler implements CacheHandler {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [key, entry, _ctx] = args;

if (OpenNextCacheHandler.maybeKVNamespace === undefined) {
if (this.kv === undefined) {
return;
}

Expand All @@ -127,15 +129,15 @@ export class OpenNextCacheHandler implements CacheHandler {
};

try {
await OpenNextCacheHandler.maybeKVNamespace.put(key, JSON.stringify(data));
await this.kv.put(key, JSON.stringify(data));
} catch (e) {
console.error(`Failed to set value for key = ${key}: ${e}`);
}
}

async revalidateTag(...args: Parameters<CacheHandler["revalidateTag"]>) {
const [tags] = args;
if (OpenNextCacheHandler.maybeKVNamespace === undefined) {
if (this.kv === undefined) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IncrementalCache } from "next/dist/server/lib/incremental-cache";
import type { IncrementalCache } from "next/dist/server/lib/incremental-cache";
import { NEXT_META_SUFFIX } from "./constants";

type PrerenderedRouteMeta = {
Expand Down
2 changes: 1 addition & 1 deletion packages/cloudflare/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { cp } from "node:fs/promises";
import { defineConfig } from "tsup";

const cliConfig = defineConfig({
entry: ["src/cli/index.ts", "src/cli/cache-handler/index.ts"],
entry: ["src/cli/index.ts"],
outDir: "dist/cli",
dts: false,
format: ["esm"],
Expand Down