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
6 changes: 4 additions & 2 deletions packages/cloudflare/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
},
"files": [
"README.md",
"dist"
"dist",
"templates"
],
"repository": {
"type": "git",
Expand Down Expand Up @@ -73,7 +74,8 @@
"@opennextjs/aws": "https://pkg.pr.new/@opennextjs/aws@684",
"glob": "catalog:",
"rimraf": "catalog:",
"ts-morph": "catalog:"
"ts-morph": "catalog:",
"enquirer": "^2.4.1"
},
"peerDependencies": {
"wrangler": "catalog:"
Expand Down
81 changes: 55 additions & 26 deletions packages/cloudflare/src/cli/build/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { cpSync } from "node:fs";
import { cpSync, existsSync } from "node:fs";
import { createRequire } from "node:module";
import { dirname, join } from "node:path";

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

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

await createOpenNextConfigIfNotExistent(projectOpts);

const { config, buildDir } = await compileOpenNextConfig(baseDir);

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

/**
* Creates a `open-next.config.ts` file for the user if it doesn't exist, but only after asking for the user's confirmation.
*
* If the user refuses an error is thrown (since the file is mandatory).
*
* @param projectOpts The options for the project
*/
async function createOpenNextConfigIfNotExistent(projectOpts: ProjectOptions): Promise<void> {
const openNextConfigPath = join(projectOpts.sourceDir, "open-next.config.ts");

if (!existsSync(openNextConfigPath)) {
const answer = await askConfirmation(
"Missing required `open-next.config.ts` file, do you want to create one?"
);

if (!answer) {
throw new Error("The `open-next.config.ts` file is required, aborting!");
}

cpSync(join(getPackageTemplatesDirPath(), "defaults", "open-next.config.ts"), openNextConfigPath);
}
}

/**
* Ensures open next is configured for cloudflare.
*
Expand All @@ -122,30 +149,32 @@ function ensureCloudflareConfig(config: OpenNextConfig) {
};

if (Object.values(requirements).some((satisfied) => !satisfied)) {
throw new Error(`open-next.config.ts should contain:
{
default: {
override: {
wrapper: "cloudflare-node",
converter: "edge",
incrementalCache: "dummy" | function,
tagCache: "dummy",
queue: "dummy",
},
},

middleware: {
external: true,
override: {
wrapper: "cloudflare-edge",
converter: "edge",
proxyExternalRequest: "fetch",
},
},

"dangerous": {
"enableCacheInterception": false
}
}`);
throw new Error(
"The `open-next.config.ts` should have a default export like this:\n\n" +
`{
default: {
override: {
wrapper: "cloudflare-node",
converter: "edge",
incrementalCache: "dummy" | function,
tagCache: "dummy",
queue: "dummy",
},
},

middleware: {
external: true,
override: {
wrapper: "cloudflare-edge",
converter: "edge",
proxyExternalRequest: "fetch",
},
},

"dangerous": {
"enableCacheInterception": false
},
}\n\n`.replace(/^ {8}/gm, "")
);
}
}
17 changes: 17 additions & 0 deletions packages/cloudflare/src/cli/utils/ask-confirmation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Enquirer from "enquirer";

export async function askConfirmation(message: string): Promise<boolean> {
const questionName = crypto.randomUUID();

const enquirerAnswersObject = await Enquirer.prompt<Record<string, boolean>>({
name: questionName,
message,
type: "confirm",
initial: "y",
});

console.log("");

const answer = !!enquirerAnswersObject[questionName];
return answer;
}
12 changes: 12 additions & 0 deletions packages/cloudflare/src/utils/get-package-templates-dir-path.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as path from "node:path";

const templatesDirPath = path.resolve(`${import.meta.dirname}/../../templates`);

/**
* Utility for getting the resolved path to the package's templates directory
*
* @returns the resolved path of the templates directory
*/
export function getPackageTemplatesDirPath(): string {
return templatesDirPath;
}
30 changes: 30 additions & 0 deletions packages/cloudflare/templates/defaults/open-next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// default open-next.config.ts file created by @opennextjs/cloudflare

import cache from "@opennextjs/cloudflare/kvCache";

const config = {
default: {
override: {
wrapper: "cloudflare-node",
converter: "edge",
incrementalCache: async () => cache,
tagCache: "dummy",
queue: "dummy",
},
},

middleware: {
external: true,
override: {
wrapper: "cloudflare-edge",
converter: "edge",
proxyExternalRequest: "fetch",
},
},

dangerous: {
enableCacheInterception: false,
},
};

export default config;
Loading
Loading