@opennextjs/cloudflare 0.3.2 → 0.3.4

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.
@@ -1,5 +1,6 @@
1
1
  export declare function getArgs(): {
2
2
  skipNextBuild: boolean;
3
+ skipWranglerConfigCheck: boolean;
3
4
  outputDir?: string;
4
5
  minify: boolean;
5
6
  };
package/dist/cli/args.js CHANGED
@@ -2,7 +2,7 @@ import { mkdirSync, statSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
3
  import { parseArgs } from "node:util";
4
4
  export function getArgs() {
5
- const { skipBuild, output, noMinify } = parseArgs({
5
+ const { skipBuild, skipWranglerConfigCheck, output, noMinify } = parseArgs({
6
6
  options: {
7
7
  skipBuild: {
8
8
  type: "boolean",
@@ -17,6 +17,10 @@ export function getArgs() {
17
17
  type: "boolean",
18
18
  default: false,
19
19
  },
20
+ skipWranglerConfigCheck: {
21
+ type: "boolean",
22
+ default: false,
23
+ },
20
24
  },
21
25
  allowPositionals: false,
22
26
  }).values;
@@ -27,6 +31,8 @@ export function getArgs() {
27
31
  return {
28
32
  outputDir,
29
33
  skipNextBuild: skipBuild || ["1", "true", "yes"].includes(String(process.env.SKIP_NEXT_APP_BUILD)),
34
+ skipWranglerConfigCheck: skipWranglerConfigCheck ||
35
+ ["1", "true", "yes"].includes(String(process.env.SKIP_WRANGLER_CONFIG_CHECK)),
30
36
  minify: !noMinify,
31
37
  };
32
38
  }
@@ -4,3 +4,10 @@ import { Config } from "../config.js";
4
4
  * Bundle the Open Next server.
5
5
  */
6
6
  export declare function bundleServer(config: Config, openNextOptions: BuildOptions): Promise<void>;
7
+ /**
8
+ * Gets the path of the worker.js file generated by the build process
9
+ *
10
+ * @param openNextOptions the open-next build options
11
+ * @returns the path of the worker.js file that the build process generates
12
+ */
13
+ export declare function getOutputWorkerPath(openNextOptions: BuildOptions): string;
@@ -82,7 +82,7 @@ fetch = globalThis.fetch;
82
82
  const CustomRequest = class extends globalThis.Request {
83
83
  constructor(input, init) {
84
84
  if (init) {
85
- init.cache = undefined;
85
+ delete init.cache;
86
86
  // https://github.com/cloudflare/workerd/issues/2746
87
87
  // https://github.com/cloudflare/workerd/issues/3245
88
88
  Object.defineProperty(init, "body", {
@@ -106,7 +106,7 @@ globalThis.__BUILD_TIMESTAMP_MS__ = ${Date.now()};
106
106
  const packagePosixPath = packagePath.split(path.sep).join(path.posix.sep);
107
107
  fs.writeFileSync(path.join(outputPath, "handler.mjs"), `export * from "./${packagePosixPath}/handler.mjs";`);
108
108
  }
109
- console.log(`\x1b[35mWorker saved in \`${openNextServerBundle}\` 🚀\n\x1b[0m`);
109
+ console.log(`\x1b[35mWorker saved in \`${getOutputWorkerPath(openNextOptions)}\` 🚀\n\x1b[0m`);
110
110
  }
111
111
  /**
112
112
  * This function applies string replacements on the bundled worker code necessary to get it to run in workerd
@@ -185,3 +185,12 @@ async function patchCodeWithValidations(code, patches) {
185
185
  console.log(`All ${patches.length} patches applied\n`);
186
186
  return patchedCode;
187
187
  }
188
+ /**
189
+ * Gets the path of the worker.js file generated by the build process
190
+ *
191
+ * @param openNextOptions the open-next build options
192
+ * @returns the path of the worker.js file that the build process generates
193
+ */
194
+ export function getOutputWorkerPath(openNextOptions) {
195
+ return path.join(openNextOptions.outputDir, "worker.js");
196
+ }
@@ -7,3 +7,4 @@ import type { ProjectOptions } from "../config.js";
7
7
  * @param projectOpts The options for the project
8
8
  */
9
9
  export declare function build(projectOpts: ProjectOptions): Promise<void>;
10
+ export declare function getLatestCompatDate(): Promise<string | undefined>;
@@ -1,4 +1,4 @@
1
- import { cpSync, existsSync } from "node:fs";
1
+ import { cpSync, existsSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { createRequire } from "node:module";
3
3
  import { dirname, join } from "node:path";
4
4
  import { buildNextjsApp, setStandaloneBuildMode } from "@opennextjs/aws/build/buildNextApp.js";
@@ -76,6 +76,9 @@ export async function build(projectOpts) {
76
76
  const projConfig = getConfig(projectOpts);
77
77
  // TODO: rely on options only.
78
78
  await bundleServer(projConfig, options);
79
+ if (!projectOpts.skipWranglerConfigCheck) {
80
+ await createWranglerConfigIfNotExistent(projectOpts);
81
+ }
79
82
  logger.info("OpenNext build complete.");
80
83
  }
81
84
  /**
@@ -141,3 +144,68 @@ function ensureCloudflareConfig(config) {
141
144
  }\n\n`.replace(/^ {8}/gm, ""));
142
145
  }
143
146
  }
147
+ /**
148
+ * Creates a `wrangler.json` file for the user if a wrangler config file doesn't already exist,
149
+ * but only after asking for the user's confirmation.
150
+ *
151
+ * If the user refuses a warning is shown (which offers ways to opt out of this check to the user).
152
+ *
153
+ * Note: we generate a wrangler.json file with comments instead of using the jsonc extension,
154
+ * we decided to do that since json is more common than jsonc, wrangler also parses
155
+ * them in the same way and we also expect developers to associate `wrangler.json`
156
+ * files to the jsonc language
157
+ *
158
+ * @param projectOpts The options for the project
159
+ */
160
+ async function createWranglerConfigIfNotExistent(projectOpts) {
161
+ const possibleExts = ["toml", "json", "jsonc"];
162
+ const wranglerConfigFileExists = possibleExts.some((ext) => existsSync(join(projectOpts.sourceDir, `wrangler.${ext}`)));
163
+ if (wranglerConfigFileExists) {
164
+ return;
165
+ }
166
+ const answer = await askConfirmation("No `wrangler.(toml|json|jsonc)` config file found, do you want to create one?");
167
+ if (!answer) {
168
+ console.warn("No Wrangler config file created" +
169
+ "\n" +
170
+ "(to avoid this check use the `--skipWranglerConfigCheck` flag or set a `SKIP_WRANGLER_CONFIG_CHECK` environment variable to `yes`)");
171
+ return;
172
+ }
173
+ const wranglerConfigTemplate = readFileSync(join(getPackageTemplatesDirPath(), "defaults", "wrangler.jsonc"), "utf8");
174
+ let wranglerConfigContent = wranglerConfigTemplate;
175
+ const appName = getAppNameFromPackageJson(projectOpts.sourceDir) ?? "app-name";
176
+ if (appName) {
177
+ wranglerConfigContent = wranglerConfigContent.replace('"app-name"', JSON.stringify(appName.replaceAll("_", "-")));
178
+ }
179
+ const compatDate = await getLatestCompatDate();
180
+ if (compatDate) {
181
+ wranglerConfigContent = wranglerConfigContent.replace(/"compatibility_date": "\d{4}-\d{2}-\d{2}"/, `"compatibility_date": ${JSON.stringify(compatDate)}`);
182
+ }
183
+ writeFileSync(join(projectOpts.sourceDir, "wrangler.json"), wranglerConfigContent);
184
+ }
185
+ function getAppNameFromPackageJson(sourceDir) {
186
+ try {
187
+ const packageJsonStr = readFileSync(join(sourceDir, "package.json"), "utf8");
188
+ const packageJson = JSON.parse(packageJsonStr);
189
+ if (typeof packageJson.name === "string")
190
+ return packageJson.name;
191
+ }
192
+ catch {
193
+ /* empty */
194
+ }
195
+ }
196
+ export async function getLatestCompatDate() {
197
+ try {
198
+ const resp = await fetch(`https://registry.npmjs.org/workerd`);
199
+ const latestWorkerdVersion = (await resp.json())["dist-tags"].latest;
200
+ // The format of the workerd version is `major.yyyymmdd.patch`.
201
+ const match = latestWorkerdVersion.match(/\d+\.(\d{4})(\d{2})(\d{2})\.\d+/);
202
+ if (match) {
203
+ const [, year, month, date] = match;
204
+ const compatDate = `${year}-${month}-${date}`;
205
+ return compatDate;
206
+ }
207
+ }
208
+ catch {
209
+ /* empty */
210
+ }
211
+ }
@@ -3,4 +3,4 @@ import { Config } from "../../../config.js";
3
3
  /**
4
4
  * Copies the template files present in the cloudflare adapter package into the standalone node_modules folder
5
5
  */
6
- export declare function copyPackageCliFiles(packageDistDir: string, config: Config, openNextConfig: BuildOptions): void;
6
+ export declare function copyPackageCliFiles(packageDistDir: string, config: Config, openNextOptions: BuildOptions): void;
@@ -1,12 +1,13 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
+ import { getOutputWorkerPath } from "../../bundle-server.js";
3
4
  /**
4
5
  * Copies the template files present in the cloudflare adapter package into the standalone node_modules folder
5
6
  */
6
- export function copyPackageCliFiles(packageDistDir, config, openNextConfig) {
7
+ export function copyPackageCliFiles(packageDistDir, config, openNextOptions) {
7
8
  console.log("# copyPackageTemplateFiles");
8
9
  const sourceDir = path.join(packageDistDir, "cli");
9
10
  const destinationDir = path.join(config.paths.internal.package, "cli");
10
11
  fs.cpSync(sourceDir, destinationDir, { recursive: true });
11
- fs.copyFileSync(path.join(packageDistDir, "cli", "templates", "worker.js"), path.join(openNextConfig.outputDir, "worker.js"));
12
+ fs.copyFileSync(path.join(packageDistDir, "cli", "templates", "worker.js"), getOutputWorkerPath(openNextOptions));
12
13
  }
@@ -6,7 +6,7 @@ import type { BuildOptions } from "@opennextjs/aws/build/helper.js";
6
6
  *
7
7
  * Merged variables respect the following priority order.
8
8
  * 1. `.env.{mode}.local`
9
- * 2. `.env.local`
9
+ * 2. `.env.local` (when mode is not equal to `test`)
10
10
  * 3. `.env.{mode}`
11
11
  * 4. `.env`
12
12
  *
@@ -13,7 +13,7 @@ function readEnvFile(filePath) {
13
13
  *
14
14
  * Merged variables respect the following priority order.
15
15
  * 1. `.env.{mode}.local`
16
- * 2. `.env.local`
16
+ * 2. `.env.local` (when mode is not equal to `test`)
17
17
  * 3. `.env.{mode}`
18
18
  * 4. `.env`
19
19
  *
@@ -23,7 +23,7 @@ function readEnvFile(filePath) {
23
23
  * the env files at the root of the monorepo.
24
24
  */
25
25
  export function extractProjectEnvVars(mode, { monorepoRoot, appPath }) {
26
- return [".env", `.env.${mode}`, ".env.local", `.env.${mode}.local`]
26
+ return [".env", `.env.${mode}`, ...(mode !== "test" ? [".env.local"] : []), `.env.${mode}.local`]
27
27
  .flatMap((fileName) => [
28
28
  ...(monorepoRoot !== appPath ? [readEnvFile(path.join(monorepoRoot, fileName))] : []),
29
29
  readEnvFile(path.join(appPath, fileName)),
@@ -8,6 +8,8 @@ describe("extractProjectEnvVars", () => {
8
8
  mockFs({
9
9
  ".env": "ENV_VAR=value",
10
10
  ".env.local": "ENV_LOCAL_VAR=value",
11
+ ".env.test": "ENV_TEST_VAR=value",
12
+ ".env.test.local": "ENV_TEST_LOCAL_VAR=value",
11
13
  ".env.development": "ENV_DEV_VAR=value",
12
14
  ".env.development.local": "ENV_DEV_LOCAL_VAR=value",
13
15
  ".env.production": "ENV_PROD_VAR=value",
@@ -54,4 +56,12 @@ describe("extractProjectEnvVars", () => {
54
56
  ENV_VAR: "value",
55
57
  });
56
58
  });
59
+ it("should exclude .env.local files when extracting test env vars", () => {
60
+ const result = extractProjectEnvVars("test", options);
61
+ expect(result).toEqual({
62
+ ENV_TEST_LOCAL_VAR: "value",
63
+ ENV_TEST_VAR: "value",
64
+ ENV_VAR: "value",
65
+ });
66
+ });
57
67
  });
@@ -37,5 +37,6 @@ export type ProjectOptions = {
37
37
  sourceDir: string;
38
38
  outputDir: string;
39
39
  skipNextBuild: boolean;
40
+ skipWranglerConfigCheck: boolean;
40
41
  minify: boolean;
41
42
  };
package/dist/cli/index.js CHANGED
@@ -3,10 +3,11 @@ import { resolve } from "node:path";
3
3
  import { getArgs } from "./args.js";
4
4
  import { build } from "./build/index.js";
5
5
  const nextAppDir = process.cwd();
6
- const { skipNextBuild, outputDir, minify } = getArgs();
6
+ const { skipNextBuild, skipWranglerConfigCheck, outputDir, minify } = getArgs();
7
7
  await build({
8
8
  sourceDir: nextAppDir,
9
9
  outputDir: resolve(outputDir ?? nextAppDir, ".open-next"),
10
10
  skipNextBuild,
11
+ skipWranglerConfigCheck,
11
12
  minify,
12
13
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@opennextjs/cloudflare",
3
3
  "description": "Cloudflare builder for next apps",
4
- "version": "0.3.2",
4
+ "version": "0.3.4",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "opennextjs-cloudflare": "dist/cli/index.js"
@@ -61,7 +61,7 @@
61
61
  },
62
62
  "dependencies": {
63
63
  "@dotenvx/dotenvx": "1.31.0",
64
- "@opennextjs/aws": "https://pkg.pr.new/@opennextjs/aws@684",
64
+ "@opennextjs/aws": "https://pkg.pr.new/@opennextjs/aws@688",
65
65
  "glob": "^11.0.0",
66
66
  "rimraf": "^6.0.1",
67
67
  "ts-morph": "^23.0.0",
@@ -0,0 +1,18 @@
1
+ {
2
+ "main": ".open-next/worker.js",
3
+ "name": "app-name",
4
+ "compatibility_date": "2024-12-30",
5
+ "compatibility_flags": ["nodejs_compat"],
6
+ "assets": {
7
+ "directory": ".open-next/assets",
8
+ "binding": "ASSETS"
9
+ },
10
+ "kv_namespaces": [
11
+ // Create a KV binding with the binding name "NEXT_CACHE_WORKERS_KV"
12
+ // to enable the KV based caching:
13
+ // {
14
+ // "binding": "NEXT_CACHE_WORKERS_KV",
15
+ // "id": "<BINDING_ID>"
16
+ // }
17
+ ]
18
+ }