Skip to content

Commit 77078ef

Browse files
Make autoconfig work better for Next.js apps (#11704)
* Make autoconfig work better for Next.js apps * Update packages/wrangler/src/autoconfig/c3-vendor/packages.ts Co-authored-by: Matt Kane <m@mk.gg> * fail on older version of next * update changeset --------- Co-authored-by: Matt Kane <m@mk.gg>
1 parent e3c1120 commit 77078ef

File tree

3 files changed

+56
-13
lines changed

3 files changed

+56
-13
lines changed

.changeset/chilly-sites-remain.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"wrangler": patch
3+
---
4+
5+
Fix autoconfig handling of Next.js apps with CJS config files and incompatible Next.js versions
6+
7+
Previously, `wrangler setup` and `wrangler deploy --x-autoconfig` would fail when working with Next.js applications that use CommonJS config files (next.config.cjs) or have versions of Next.js that don't match the required peer dependencies. The autoconfig process now uses dynamic imports and forced installation to handle these scenarios gracefully.

packages/wrangler/src/autoconfig/c3-vendor/packages.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type InstallConfig = {
1010
startText?: string;
1111
doneText?: string;
1212
dev?: boolean;
13+
force?: boolean;
1314
};
1415

1516
/**
@@ -19,11 +20,14 @@ type InstallConfig = {
1920
* @param config.dev - Add packages as `devDependencies`
2021
* @param config.startText - Spinner start text
2122
* @param config.doneText - Spinner done text
23+
* @param config.force - Whether to install with `--force` or not
2224
*/
2325
export const installPackages = async (
2426
packages: string[],
2527
config: InstallConfig = {}
2628
) => {
29+
const { force, dev, startText, doneText } = config;
30+
2731
if (packages.length === 0) {
2832
const { type } = await getPackageManager();
2933

@@ -44,9 +48,11 @@ export const installPackages = async (
4448
...(cmd ? [cmd] : []),
4549
...packages,
4650
...(type === "pnpm" ? ["--no-frozen-lockfile"] : []),
51+
...(force === true ? ["--force"] : []),
4752
],
4853
{
49-
...config,
54+
startText,
55+
doneText,
5056
silent: true,
5157
}
5258
);
@@ -60,20 +66,30 @@ export const installPackages = async (
6066
switch (type) {
6167
case "yarn":
6268
cmd = "add";
63-
saveFlag = config.dev ? "-D" : "";
69+
saveFlag = dev ? "-D" : "";
6470
break;
6571
case "npm":
6672
case "pnpm":
6773
default:
6874
cmd = "install";
69-
saveFlag = config.dev ? "--save-dev" : "";
75+
saveFlag = dev ? "--save-dev" : "";
7076
break;
7177
}
7278

73-
await runCommand([type, cmd, ...(saveFlag ? [saveFlag] : []), ...packages], {
74-
...config,
75-
silent: true,
76-
});
79+
await runCommand(
80+
[
81+
type,
82+
cmd,
83+
...(saveFlag ? [saveFlag] : []),
84+
...packages,
85+
...(force === true ? ["--force"] : []),
86+
],
87+
{
88+
startText,
89+
doneText,
90+
silent: true,
91+
}
92+
);
7793

7894
if (type === "npm") {
7995
// Npm install will update the package.json with a caret-range rather than the exact version/range we asked for.

packages/wrangler/src/autoconfig/frameworks/next.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ import { statSync } from "node:fs";
22
import { readFile, writeFile } from "node:fs/promises";
33
import { brandColor, dim } from "@cloudflare/cli/colors";
44
import { spinner } from "@cloudflare/cli/interactive";
5+
import semiver from "semiver";
56
import { getPackageManager } from "../../package-manager";
67
import { dedent } from "../../utils/dedent";
78
import { installPackages } from "../c3-vendor/packages";
89
import { AutoConfigFrameworkConfigurationError } from "../errors";
910
import { appendToGitIgnore } from "../git";
1011
import { usesTypescript } from "../uses-typescript";
12+
import { getInstalledPackageVersion } from "./utils/packages";
1113
import { Framework } from ".";
1214
import type { ConfigurationOptions, ConfigurationResults } from ".";
1315

@@ -22,14 +24,33 @@ export class NextJs extends Framework {
2224
const nextConfigPath = findNextConfigPath(usesTs);
2325
if (!nextConfigPath) {
2426
throw new AutoConfigFrameworkConfigurationError(
25-
"No Next.js configuration file could be detected. Note: only next.config.ts and next.config.mjs files are supported."
27+
"No Next.js configuration file could be detected."
28+
);
29+
}
30+
31+
const firstNextVersionSupportedByOpenNext = "14.2.35";
32+
const installedNextVersion = getInstalledPackageVersion(
33+
"next",
34+
projectPath
35+
);
36+
37+
if (
38+
installedNextVersion &&
39+
semiver(installedNextVersion, firstNextVersionSupportedByOpenNext) < 0
40+
) {
41+
throw new AutoConfigFrameworkConfigurationError(
42+
`The detected Next.js version (${installedNextVersion}) is too old, please update the \`next\` dependency to at least ${firstNextVersionSupportedByOpenNext} and try again.`
2643
);
2744
}
2845

2946
if (!dryRun) {
3047
await installPackages(["@opennextjs/cloudflare@^1.12.0"], {
3148
startText: "Installing @opennextjs/cloudflare adapter",
3249
doneText: `${brandColor("installed")}`,
50+
// Note: we force install open-next so that even if an incompatible version of
51+
// Next.js is used this installation still succeeds, moving users to
52+
// (hopefully) the right direction (instead of failing at this step)
53+
force: true,
3354
});
3455

3556
await updateNextConfig(nextConfigPath);
@@ -81,7 +102,9 @@ function findNextConfigPath(usesTs: boolean): string | undefined {
81102
const pathsToCheck = [
82103
...(usesTs ? ["next.config.ts"] : []),
83104
"next.config.mjs",
84-
];
105+
"next.config.js",
106+
"next.config.cjs",
107+
] as const;
85108

86109
for (const path of pathsToCheck) {
87110
const stats = statSync(path, {
@@ -102,10 +125,7 @@ async function updateNextConfig(nextConfigPath: string) {
102125

103126
const updatedConfigFile =
104127
configContent +
105-
`
106-
import { initOpenNextCloudflareForDev } from '@opennextjs/cloudflare';
107-
initOpenNextCloudflareForDev();
108-
`.replace(/\n\t*/g, "\n");
128+
"\n\nimport('@opennextjs/cloudflare').then(m => m.initOpenNextCloudflareForDev());\n";
109129

110130
await writeFile(nextConfigPath, updatedConfigFile);
111131

0 commit comments

Comments
 (0)