Skip to content

Commit d1237fe

Browse files
create an open-next.config.ts file for the user in case one is not already present (#193)
* create an open-next.config.ts file for the user in case one is not already present * update cloudflare open-next config validation error message
1 parent efae3ab commit d1237fe

File tree

6 files changed

+862
-771
lines changed

6 files changed

+862
-771
lines changed

packages/cloudflare/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
},
3333
"files": [
3434
"README.md",
35-
"dist"
35+
"dist",
36+
"templates"
3637
],
3738
"repository": {
3839
"type": "git",
@@ -73,7 +74,8 @@
7374
"@opennextjs/aws": "https://pkg.pr.new/@opennextjs/aws@684",
7475
"glob": "catalog:",
7576
"rimraf": "catalog:",
76-
"ts-morph": "catalog:"
77+
"ts-morph": "catalog:",
78+
"enquirer": "^2.4.1"
7779
},
7880
"peerDependencies": {
7981
"wrangler": "catalog:"

packages/cloudflare/src/cli/build/index.ts

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { cpSync } from "node:fs";
1+
import { cpSync, existsSync } from "node:fs";
22
import { createRequire } from "node:module";
33
import { dirname, join } from "node:path";
44

@@ -12,8 +12,10 @@ import { printHeader, showWarningOnWindows } from "@opennextjs/aws/build/utils.j
1212
import logger from "@opennextjs/aws/logger.js";
1313
import type { OpenNextConfig } from "@opennextjs/aws/types/open-next.js";
1414

15+
import { getPackageTemplatesDirPath } from "../../utils/get-package-templates-dir-path.js";
1516
import type { ProjectOptions } from "../config.js";
1617
import { containsDotNextDir, getConfig } from "../config.js";
18+
import { askConfirmation } from "../utils/ask-confirmation.js";
1719
import { bundleServer } from "./bundle-server.js";
1820
import { compileEnvFiles } from "./open-next/compile-env-files.js";
1921
import { copyCacheAssets } from "./open-next/copyCacheAssets.js";
@@ -35,6 +37,8 @@ export async function build(projectOpts: ProjectOptions): Promise<void> {
3537
const require = createRequire(import.meta.url);
3638
const openNextDistDir = dirname(require.resolve("@opennextjs/aws/index.js"));
3739

40+
await createOpenNextConfigIfNotExistent(projectOpts);
41+
3842
const { config, buildDir } = await compileOpenNextConfig(baseDir);
3943

4044
ensureCloudflareConfig(config);
@@ -100,6 +104,29 @@ export async function build(projectOpts: ProjectOptions): Promise<void> {
100104
logger.info("OpenNext build complete.");
101105
}
102106

107+
/**
108+
* Creates a `open-next.config.ts` file for the user if it doesn't exist, but only after asking for the user's confirmation.
109+
*
110+
* If the user refuses an error is thrown (since the file is mandatory).
111+
*
112+
* @param projectOpts The options for the project
113+
*/
114+
async function createOpenNextConfigIfNotExistent(projectOpts: ProjectOptions): Promise<void> {
115+
const openNextConfigPath = join(projectOpts.sourceDir, "open-next.config.ts");
116+
117+
if (!existsSync(openNextConfigPath)) {
118+
const answer = await askConfirmation(
119+
"Missing required `open-next.config.ts` file, do you want to create one?"
120+
);
121+
122+
if (!answer) {
123+
throw new Error("The `open-next.config.ts` file is required, aborting!");
124+
}
125+
126+
cpSync(join(getPackageTemplatesDirPath(), "defaults", "open-next.config.ts"), openNextConfigPath);
127+
}
128+
}
129+
103130
/**
104131
* Ensures open next is configured for cloudflare.
105132
*
@@ -122,30 +149,32 @@ function ensureCloudflareConfig(config: OpenNextConfig) {
122149
};
123150

124151
if (Object.values(requirements).some((satisfied) => !satisfied)) {
125-
throw new Error(`open-next.config.ts should contain:
126-
{
127-
default: {
128-
override: {
129-
wrapper: "cloudflare-node",
130-
converter: "edge",
131-
incrementalCache: "dummy" | function,
132-
tagCache: "dummy",
133-
queue: "dummy",
134-
},
135-
},
136-
137-
middleware: {
138-
external: true,
139-
override: {
140-
wrapper: "cloudflare-edge",
141-
converter: "edge",
142-
proxyExternalRequest: "fetch",
143-
},
144-
},
145-
146-
"dangerous": {
147-
"enableCacheInterception": false
148-
}
149-
}`);
152+
throw new Error(
153+
"The `open-next.config.ts` should have a default export like this:\n\n" +
154+
`{
155+
default: {
156+
override: {
157+
wrapper: "cloudflare-node",
158+
converter: "edge",
159+
incrementalCache: "dummy" | function,
160+
tagCache: "dummy",
161+
queue: "dummy",
162+
},
163+
},
164+
165+
middleware: {
166+
external: true,
167+
override: {
168+
wrapper: "cloudflare-edge",
169+
converter: "edge",
170+
proxyExternalRequest: "fetch",
171+
},
172+
},
173+
174+
"dangerous": {
175+
"enableCacheInterception": false
176+
},
177+
}\n\n`.replace(/^ {8}/gm, "")
178+
);
150179
}
151180
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Enquirer from "enquirer";
2+
3+
export async function askConfirmation(message: string): Promise<boolean> {
4+
const questionName = crypto.randomUUID();
5+
6+
const enquirerAnswersObject = await Enquirer.prompt<Record<string, boolean>>({
7+
name: questionName,
8+
message,
9+
type: "confirm",
10+
initial: "y",
11+
});
12+
13+
console.log("");
14+
15+
const answer = !!enquirerAnswersObject[questionName];
16+
return answer;
17+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import * as path from "node:path";
2+
3+
const templatesDirPath = path.resolve(`${import.meta.dirname}/../../templates`);
4+
5+
/**
6+
* Utility for getting the resolved path to the package's templates directory
7+
*
8+
* @returns the resolved path of the templates directory
9+
*/
10+
export function getPackageTemplatesDirPath(): string {
11+
return templatesDirPath;
12+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// default open-next.config.ts file created by @opennextjs/cloudflare
2+
3+
import cache from "@opennextjs/cloudflare/kvCache";
4+
5+
const config = {
6+
default: {
7+
override: {
8+
wrapper: "cloudflare-node",
9+
converter: "edge",
10+
incrementalCache: async () => cache,
11+
tagCache: "dummy",
12+
queue: "dummy",
13+
},
14+
},
15+
16+
middleware: {
17+
external: true,
18+
override: {
19+
wrapper: "cloudflare-edge",
20+
converter: "edge",
21+
proxyExternalRequest: "fetch",
22+
},
23+
},
24+
25+
dangerous: {
26+
enableCacheInterception: false,
27+
},
28+
};
29+
30+
export default config;

0 commit comments

Comments
 (0)