@opennextjs/cloudflare 0.0.0-e62af72 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -8
- package/dist/api/get-cloudflare-context.d.mts +1 -1
- package/dist/cli/cache-handler/index.mjs +20 -0
- package/dist/cli/chunk-F7LECSR5.mjs +160 -0
- package/dist/cli/index.mjs +493 -332
- package/dist/cli/templates/shims/node-fs.ts +1 -1
- package/dist/cli/templates/worker.ts +28 -17
- package/package.json +13 -3
- package/dist/cli/cache-handler.mjs +0 -48
- package/dist/cli/chunk-UJCSKKID.mjs +0 -30
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Deploy Next.js apps to Cloudflare!
|
|
4
4
|
|
|
5
|
-
OpenNext for Cloudflare is Cloudflare specific adapter that enables deployment of Next.js applications to Cloudflare.
|
|
5
|
+
[OpenNext for Cloudflare](https://opennext.js.org/cloudflare) is Cloudflare specific adapter that enables deployment of Next.js applications to Cloudflare.
|
|
6
6
|
|
|
7
7
|
## Getting started
|
|
8
8
|
|
|
@@ -13,7 +13,13 @@ You can use [`create-next-app`](https://nextjs.org/docs/pages/api-reference/cli/
|
|
|
13
13
|
- add the following `devDependencies` to the `package.json`:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
+
npm add -D wrangler@latest @opennextjs/cloudflare
|
|
17
|
+
# or
|
|
16
18
|
pnpm add -D wrangler@latest @opennextjs/cloudflare
|
|
19
|
+
# or
|
|
20
|
+
yarn add -D wrangler@latest @opennextjs/cloudflare
|
|
21
|
+
# or
|
|
22
|
+
bun add -D wrangler@latest @opennextjs/cloudflare
|
|
17
23
|
```
|
|
18
24
|
|
|
19
25
|
- add a `wrangler.toml` at the root of your project
|
|
@@ -27,9 +33,34 @@ You can use [`create-next-app`](https://nextjs.org/docs/pages/api-reference/cli/
|
|
|
27
33
|
compatibility_flags = ["nodejs_compat"]
|
|
28
34
|
|
|
29
35
|
# Use the new Workers + Assets to host the static frontend files
|
|
30
|
-
|
|
36
|
+
assets = { directory = ".worker-next/assets", binding = "ASSETS" }
|
|
31
37
|
```
|
|
32
38
|
|
|
39
|
+
You can enable Incremental Static Regeneration ([ISR](https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration)) by adding a KV binding named `NEXT_CACHE_WORKERS_KV` to your `wrangler.toml`:
|
|
40
|
+
|
|
41
|
+
- Create the binding
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx wrangler kv namespace create NEXT_CACHE_WORKERS_KV
|
|
45
|
+
# or
|
|
46
|
+
pnpm wrangler kv namespace create NEXT_CACHE_WORKERS_KV
|
|
47
|
+
# or
|
|
48
|
+
yarn wrangler kv namespace create NEXT_CACHE_WORKERS_KV
|
|
49
|
+
# or
|
|
50
|
+
bun wrangler kv namespace create NEXT_CACHE_WORKERS_KV
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- Paste the snippet to your `wrangler.toml`:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
[[kv_namespaces]]
|
|
57
|
+
binding = "NEXT_CACHE_WORKERS_KV"
|
|
58
|
+
id = "..."
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
> [!WARNING]
|
|
62
|
+
> The current support for ISR is limited.
|
|
63
|
+
|
|
33
64
|
## Local development
|
|
34
65
|
|
|
35
66
|
- you can use the regular `next` CLI to start the Next.js dev server:
|
|
@@ -41,13 +72,25 @@ Run the following commands to preview the production build of your application l
|
|
|
41
72
|
- build the app and adapt it for Cloudflare
|
|
42
73
|
|
|
43
74
|
```bash
|
|
44
|
-
|
|
75
|
+
npx cloudflare
|
|
76
|
+
# or
|
|
77
|
+
pnpm cloudflare
|
|
78
|
+
# or
|
|
79
|
+
yarn cloudflare
|
|
80
|
+
# or
|
|
81
|
+
bun cloudflare
|
|
45
82
|
```
|
|
46
83
|
|
|
47
84
|
- Preview the app in Wrangler
|
|
48
85
|
|
|
49
86
|
```bash
|
|
87
|
+
npx wrangler dev
|
|
88
|
+
# or
|
|
50
89
|
pnpm wrangler dev
|
|
90
|
+
# or
|
|
91
|
+
yarn wrangler dev
|
|
92
|
+
# or
|
|
93
|
+
bun wrangler dev
|
|
51
94
|
```
|
|
52
95
|
|
|
53
96
|
## Deploy your app
|
|
@@ -57,9 +100,11 @@ Deploy your application to production with the following:
|
|
|
57
100
|
- build the app and adapt it for Cloudflare
|
|
58
101
|
|
|
59
102
|
```bash
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
103
|
+
npx cloudflare && npx wrangler deploy
|
|
104
|
+
# or
|
|
105
|
+
pnpm cloudflare && pnpm wrangler deploy
|
|
106
|
+
# or
|
|
107
|
+
yarn cloudflare && yarn wrangler deploy
|
|
108
|
+
# or
|
|
109
|
+
bun cloudflare && bun wrangler deploy
|
|
65
110
|
```
|
|
@@ -10,7 +10,7 @@ type CloudflareContext<CfProperties extends Record<string, unknown> = IncomingRe
|
|
|
10
10
|
/**
|
|
11
11
|
* the request's [cf properties](https://developers.cloudflare.com/workers/runtime-apis/request/#the-cf-property-requestinitcfproperties)
|
|
12
12
|
*/
|
|
13
|
-
cf: CfProperties;
|
|
13
|
+
cf: CfProperties | undefined;
|
|
14
14
|
/**
|
|
15
15
|
* the current [execution context](https://developers.cloudflare.com/workers/runtime-apis/context)
|
|
16
16
|
*/
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NEXT_BODY_SUFFIX,
|
|
3
|
+
NEXT_DATA_SUFFIX,
|
|
4
|
+
NEXT_HTML_SUFFIX,
|
|
5
|
+
NEXT_META_SUFFIX,
|
|
6
|
+
OpenNextCacheHandler,
|
|
7
|
+
RSC_PREFETCH_SUFFIX,
|
|
8
|
+
RSC_SUFFIX,
|
|
9
|
+
SEED_DATA_DIR
|
|
10
|
+
} from "../chunk-F7LECSR5.mjs";
|
|
11
|
+
export {
|
|
12
|
+
NEXT_BODY_SUFFIX,
|
|
13
|
+
NEXT_DATA_SUFFIX,
|
|
14
|
+
NEXT_HTML_SUFFIX,
|
|
15
|
+
NEXT_META_SUFFIX,
|
|
16
|
+
OpenNextCacheHandler,
|
|
17
|
+
RSC_PREFETCH_SUFFIX,
|
|
18
|
+
RSC_SUFFIX,
|
|
19
|
+
SEED_DATA_DIR
|
|
20
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// src/cli/cache-handler/constants.ts
|
|
28
|
+
var RSC_PREFETCH_SUFFIX = ".prefetch.rsc";
|
|
29
|
+
var RSC_SUFFIX = ".rsc";
|
|
30
|
+
var NEXT_DATA_SUFFIX = ".json";
|
|
31
|
+
var NEXT_META_SUFFIX = ".meta";
|
|
32
|
+
var NEXT_BODY_SUFFIX = ".body";
|
|
33
|
+
var NEXT_HTML_SUFFIX = ".html";
|
|
34
|
+
var SEED_DATA_DIR = "cdn-cgi/_cf_seed_data";
|
|
35
|
+
|
|
36
|
+
// src/cli/cache-handler/utils.ts
|
|
37
|
+
async function getAsset(key, cb) {
|
|
38
|
+
const resp = await process.env.ASSETS.fetch(key);
|
|
39
|
+
return resp.status === 200 ? await cb(resp) : void 0;
|
|
40
|
+
}
|
|
41
|
+
function getSeedBodyFile(key, suffix) {
|
|
42
|
+
return getAsset(key + suffix, (resp) => resp.arrayBuffer());
|
|
43
|
+
}
|
|
44
|
+
function getSeedTextFile(key, suffix) {
|
|
45
|
+
return getAsset(key + suffix, (resp) => resp.text());
|
|
46
|
+
}
|
|
47
|
+
function getSeedMetaFile(key) {
|
|
48
|
+
return getAsset(key + NEXT_META_SUFFIX, (resp) => resp.json());
|
|
49
|
+
}
|
|
50
|
+
function parseCtx(ctx = {}) {
|
|
51
|
+
return { ...ctx, kind: ctx?.kindHint?.toUpperCase() };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/cli/cache-handler/open-next-cache-handler.ts
|
|
55
|
+
var OpenNextCacheHandler = class _OpenNextCacheHandler {
|
|
56
|
+
constructor(ctx) {
|
|
57
|
+
this.ctx = ctx;
|
|
58
|
+
}
|
|
59
|
+
static maybeKVNamespace = void 0;
|
|
60
|
+
debug = !!process.env.NEXT_PRIVATE_DEBUG_CACHE;
|
|
61
|
+
async get(...args) {
|
|
62
|
+
const [key, _ctx] = args;
|
|
63
|
+
const ctx = parseCtx(_ctx);
|
|
64
|
+
if (this.debug) console.log(`cache - get: ${key}, ${ctx?.kind}`);
|
|
65
|
+
if (_OpenNextCacheHandler.maybeKVNamespace !== void 0) {
|
|
66
|
+
try {
|
|
67
|
+
const value = await _OpenNextCacheHandler.maybeKVNamespace.get(key, "json");
|
|
68
|
+
if (value) return value;
|
|
69
|
+
} catch (e) {
|
|
70
|
+
console.error(`Failed to get value for key = ${key}: ${e}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (ctx?.kind === "FETCH" || ctx?.kind === "IMAGE") return null;
|
|
74
|
+
const seedKey = `http://assets.local/${SEED_DATA_DIR}/${key}`.replace(/\/\//g, "/");
|
|
75
|
+
if (ctx?.kind === "APP" || ctx?.kind === "APP_ROUTE") {
|
|
76
|
+
const fallbackBody = await getSeedBodyFile(seedKey, NEXT_BODY_SUFFIX);
|
|
77
|
+
if (fallbackBody) {
|
|
78
|
+
const meta = await getSeedMetaFile(seedKey);
|
|
79
|
+
return {
|
|
80
|
+
lastModified: meta?.lastModified,
|
|
81
|
+
value: {
|
|
82
|
+
kind: ctx.kind === "APP_ROUTE" ? ctx.kind : "ROUTE",
|
|
83
|
+
body: fallbackBody,
|
|
84
|
+
status: meta?.status ?? 200,
|
|
85
|
+
headers: meta?.headers ?? {}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (ctx.kind === "APP_ROUTE") {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const seedHtml = await getSeedTextFile(seedKey, NEXT_HTML_SUFFIX);
|
|
94
|
+
if (!seedHtml) return null;
|
|
95
|
+
if (ctx?.kind === "PAGES" || ctx?.kind === "APP" || ctx?.kind === "APP_PAGE") {
|
|
96
|
+
const metaPromise = getSeedMetaFile(seedKey);
|
|
97
|
+
let pageDataPromise = Promise.resolve(void 0);
|
|
98
|
+
if (!ctx.isFallback) {
|
|
99
|
+
const rscSuffix = ctx.isRoutePPREnabled ? RSC_PREFETCH_SUFFIX : RSC_SUFFIX;
|
|
100
|
+
if (ctx.kind === "APP_PAGE") {
|
|
101
|
+
pageDataPromise = getSeedBodyFile(seedKey, rscSuffix);
|
|
102
|
+
} else {
|
|
103
|
+
pageDataPromise = getSeedTextFile(seedKey, ctx.kind === "APP" ? rscSuffix : NEXT_DATA_SUFFIX);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const [meta, pageData] = await Promise.all([metaPromise, pageDataPromise]);
|
|
107
|
+
return {
|
|
108
|
+
lastModified: meta?.lastModified,
|
|
109
|
+
value: {
|
|
110
|
+
kind: ctx.kind === "APP_PAGE" ? "APP_PAGE" : "PAGE",
|
|
111
|
+
html: seedHtml,
|
|
112
|
+
pageData: pageData ?? "",
|
|
113
|
+
...ctx.kind === "APP_PAGE" && { rscData: pageData },
|
|
114
|
+
postponed: meta?.postponed,
|
|
115
|
+
status: meta?.status,
|
|
116
|
+
headers: meta?.headers
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
async set(...args) {
|
|
123
|
+
const [key, entry, _ctx] = args;
|
|
124
|
+
if (_OpenNextCacheHandler.maybeKVNamespace === void 0) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (this.debug) console.log(`cache - set: ${key}`);
|
|
128
|
+
const data = {
|
|
129
|
+
lastModified: Date.now(),
|
|
130
|
+
value: entry
|
|
131
|
+
};
|
|
132
|
+
try {
|
|
133
|
+
await _OpenNextCacheHandler.maybeKVNamespace.put(key, JSON.stringify(data));
|
|
134
|
+
} catch (e) {
|
|
135
|
+
console.error(`Failed to set value for key = ${key}: ${e}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async revalidateTag(...args) {
|
|
139
|
+
const [tags] = args;
|
|
140
|
+
if (_OpenNextCacheHandler.maybeKVNamespace === void 0) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (this.debug) console.log(`cache - revalidateTag: ${JSON.stringify([tags].flat())}`);
|
|
144
|
+
}
|
|
145
|
+
resetRequestCache() {
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export {
|
|
150
|
+
__commonJS,
|
|
151
|
+
__toESM,
|
|
152
|
+
RSC_PREFETCH_SUFFIX,
|
|
153
|
+
RSC_SUFFIX,
|
|
154
|
+
NEXT_DATA_SUFFIX,
|
|
155
|
+
NEXT_META_SUFFIX,
|
|
156
|
+
NEXT_BODY_SUFFIX,
|
|
157
|
+
NEXT_HTML_SUFFIX,
|
|
158
|
+
SEED_DATA_DIR,
|
|
159
|
+
OpenNextCacheHandler
|
|
160
|
+
};
|