1- import { cpSync } from "node:fs" ;
1+ import { cpSync , existsSync } from "node:fs" ;
22import { createRequire } from "node:module" ;
33import { dirname , join } from "node:path" ;
44
@@ -12,8 +12,10 @@ import { printHeader, showWarningOnWindows } from "@opennextjs/aws/build/utils.j
1212import logger from "@opennextjs/aws/logger.js" ;
1313import type { OpenNextConfig } from "@opennextjs/aws/types/open-next.js" ;
1414
15+ import { getPackageTemplatesDirPath } from "../../utils/get-package-templates-dir-path.js" ;
1516import type { ProjectOptions } from "../config.js" ;
1617import { containsDotNextDir , getConfig } from "../config.js" ;
18+ import { askConfirmation } from "../utils/ask-confirmation.js" ;
1719import { bundleServer } from "./bundle-server.js" ;
1820import { compileEnvFiles } from "./open-next/compile-env-files.js" ;
1921import { 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}
0 commit comments