Skip to content

Commit 56637e3

Browse files
authored
graduate next + assets template (#8741)
* graduate next * changeset * fixups * fix test
1 parent da1ec13 commit 56637e3

File tree

22 files changed

+275
-259
lines changed

22 files changed

+275
-259
lines changed

.changeset/stale-snakes-boil.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"create-cloudflare": patch
3+
---
4+
5+
Graduate Next.js + Workers Assets template from experimental
6+
7+
You no longer need the `--experimental` flag to access this template.

packages/create-cloudflare/e2e-tests/cli.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ describe.skipIf(frameworkToTest || isQuarantineMode())("help text", () => {
476476
npm create cloudflare -- --framework next -- --ts
477477
pnpm create cloudflare --framework next -- --ts
478478
Allowed Values:
479-
next, solid
479+
solid
480480
--platform=<value>
481481
Whether the application should be deployed to Pages or Workers. This is only applicable for Frameworks templates that support both Pages and Workers.
482482
Allowed Values:

packages/create-cloudflare/e2e-tests/frameworks/framework-test-config-experimental.ts

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,6 @@ import { keys, LONG_TIMEOUT } from "../helpers";
22

33
export default function getFrameworkTestConfigExperimental() {
44
return {
5-
next: {
6-
testCommitMessage: true,
7-
flags: [
8-
"--ts",
9-
"--tailwind",
10-
"--eslint",
11-
"--app",
12-
"--import-alias",
13-
"@/*",
14-
"--src-dir",
15-
],
16-
verifyBuildCfTypes: {
17-
outputFile: "cloudflare-env.d.ts",
18-
envInterfaceName: "CloudflareEnv",
19-
},
20-
verifyPreview: {
21-
route: "/test",
22-
expectedText: "Create Next App",
23-
},
24-
verifyDeploy: {
25-
route: "/",
26-
expectedText: "Create Next App",
27-
},
28-
// see https://github.com/cloudflare/next-on-pages/blob/main/packages/next-on-pages/docs/supported.md#operating-systems
29-
unsupportedOSs: ["win32"],
30-
unsupportedPms: [
31-
// bun and yarn are failing in CI
32-
"bun",
33-
"yarn",
34-
],
35-
},
365
solid: {
376
promptHandlers: [
387
{

packages/create-cloudflare/e2e-tests/frameworks/framework-test-config.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,8 @@ export default function getFrameworkTestConfig(pm: string) {
359359
},
360360
flags: ["--typescript", "--no-install", "--no-git-init"],
361361
},
362-
next: {
362+
"next:pages": {
363+
argv: ["--platform", "pages"],
363364
promptHandlers: [
364365
{
365366
matcher: /Do you want to use the next-on-pages eslint-plugin\?/,
@@ -393,6 +394,38 @@ export default function getFrameworkTestConfig(pm: string) {
393394
"@/*",
394395
],
395396
},
397+
"next:workers": {
398+
argv: ["--platform", "workers"],
399+
testCommitMessage: true,
400+
flags: [
401+
"--ts",
402+
"--tailwind",
403+
"--eslint",
404+
"--app",
405+
"--import-alias",
406+
"@/*",
407+
"--src-dir",
408+
],
409+
verifyBuildCfTypes: {
410+
outputFile: "cloudflare-env.d.ts",
411+
envInterfaceName: "CloudflareEnv",
412+
},
413+
verifyPreview: {
414+
route: "/test",
415+
expectedText: "Create Next App",
416+
},
417+
verifyDeploy: {
418+
route: "/",
419+
expectedText: "Create Next App",
420+
},
421+
// see https://github.com/cloudflare/next-on-pages/blob/main/packages/next-on-pages/docs/supported.md#operating-systems
422+
unsupportedOSs: ["win32"],
423+
unsupportedPms: [
424+
// bun and yarn are failing in CI
425+
"bun",
426+
"yarn",
427+
],
428+
},
396429
"nuxt:pages": {
397430
argv: ["--platform", "pages"],
398431
testCommitMessage: true,

packages/create-cloudflare/src/templates.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {
1818
writeFile,
1919
writeJSON,
2020
} from "helpers/files";
21-
import nextTemplateExperimental from "templates-experimental/next/c3";
2221
import solidTemplateExperimental from "templates-experimental/solid/c3";
2322
import analogTemplate from "templates/analog/c3";
2423
import angularTemplate from "templates/angular/c3";
@@ -175,7 +174,6 @@ export type TemplateMap = Record<
175174
export function getFrameworkMap({ experimental = false }): TemplateMap {
176175
if (experimental) {
177176
return {
178-
next: nextTemplateExperimental,
179177
solid: solidTemplateExperimental,
180178
};
181179
} else {
Lines changed: 7 additions & 221 deletions
Original file line numberDiff line numberDiff line change
@@ -1,223 +1,9 @@
1-
import { join } from "path";
2-
import { updateStatus, warn } from "@cloudflare/cli";
3-
import { brandColor, dim } from "@cloudflare/cli/colors";
4-
import { inputPrompt, spinner } from "@cloudflare/cli/interactive";
5-
import { runFrameworkGenerator } from "frameworks/index";
6-
import {
7-
copyFile,
8-
probePaths,
9-
readFile,
10-
readJSON,
11-
usesEslint,
12-
usesTypescript,
13-
writeFile,
14-
writeJSON,
15-
} from "helpers/files";
16-
import { detectPackageManager } from "helpers/packageManagers";
17-
import { installPackages } from "helpers/packages";
18-
import { getTemplatePath } from "../../src/templates";
19-
import type { TemplateConfig } from "../../src/templates";
20-
import type { C3Context } from "types";
1+
import pages from "./pages/c3";
2+
import workers from "./workers/c3";
3+
import type { MultiPlatformTemplateConfig } from "../../src/templates";
214

22-
const { npm, npx } = detectPackageManager();
23-
24-
const generate = async (ctx: C3Context) => {
25-
const projectName = ctx.project.name;
26-
27-
await runFrameworkGenerator(ctx, [projectName]);
28-
29-
const wranglerConfig = readFile(join(getTemplatePath(ctx), "wrangler.jsonc"));
30-
writeFile(join(ctx.project.path, "wrangler.jsonc"), wranglerConfig);
31-
updateStatus("Created wrangler.jsonc file");
32-
};
33-
34-
const updateNextConfig = (usesTs: boolean) => {
35-
const s = spinner();
36-
37-
const configFile = `next.config.${usesTs ? "ts" : "mjs"}`;
38-
s.start(`Updating \`${configFile}\``);
39-
40-
const configContent = readFile(configFile);
41-
42-
const updatedConfigFile =
43-
`import { setupDevPlatform } from '@cloudflare/next-on-pages/next-dev';
44-
45-
// Here we use the @cloudflare/next-on-pages next-dev module to allow us to
46-
// use bindings during local development (when running the application with
47-
// \`next dev\`). This function is only necessary during development and
48-
// has no impact outside of that. For more information see:
49-
// https://github.com/cloudflare/next-on-pages/blob/main/internal-packages/next-dev/README.md
50-
setupDevPlatform().catch(console.error);
51-
52-
`.replace(/\n\t*/g, "\n") + configContent;
53-
54-
writeFile(configFile, updatedConfigFile);
55-
56-
s.stop(`${brandColor(`updated`)} ${dim(`\`${configFile}\``)}`);
57-
};
58-
59-
const configure = async (ctx: C3Context) => {
60-
const projectPath = ctx.project.path;
61-
62-
// Add a compatible function handler example
63-
const path = probePaths([
64-
`${projectPath}/pages/api`,
65-
`${projectPath}/src/pages/api`,
66-
`${projectPath}/src/app/api`,
67-
`${projectPath}/app/api`,
68-
`${projectPath}/src/app`,
69-
`${projectPath}/app`,
70-
]);
71-
72-
if (!path) {
73-
throw new Error("Could not find the `/api` or `/app` directory");
74-
}
75-
76-
const usesTs = usesTypescript(ctx);
77-
78-
if (usesTs) {
79-
copyFile(
80-
join(getTemplatePath(ctx), "env.d.ts"),
81-
join(projectPath, "env.d.ts"),
82-
);
83-
updateStatus("Created an env.d.ts file");
84-
}
85-
86-
const installEslintPlugin = await shouldInstallNextOnPagesEslintPlugin(ctx);
87-
88-
if (installEslintPlugin) {
89-
await writeEslintrc(ctx);
90-
}
91-
92-
updateNextConfig(usesTs);
93-
94-
copyFile(
95-
join(getTemplatePath(ctx), "README.md"),
96-
join(projectPath, "README.md"),
97-
);
98-
updateStatus("Updated the README file");
99-
100-
await addDevDependencies(installEslintPlugin);
101-
};
102-
103-
export const shouldInstallNextOnPagesEslintPlugin = async (
104-
ctx: C3Context,
105-
): Promise<boolean> => {
106-
const eslintUsage = usesEslint(ctx);
107-
108-
if (!eslintUsage.used) {
109-
return false;
110-
}
111-
112-
if (eslintUsage.configType !== ".eslintrc.json") {
113-
warn(
114-
`Expected .eslintrc.json from Next.js scaffolding but found ${eslintUsage.configType} instead`,
115-
);
116-
return false;
117-
}
118-
119-
return await inputPrompt({
120-
type: "confirm",
121-
question: "Do you want to use the next-on-pages eslint-plugin?",
122-
label: "eslint-plugin",
123-
defaultValue: true,
124-
});
125-
};
126-
127-
export const writeEslintrc = async (ctx: C3Context): Promise<void> => {
128-
const eslintConfig = readJSON(`${ctx.project.path}/.eslintrc.json`) as {
129-
plugins: string[];
130-
extends: string | string[];
131-
};
132-
133-
eslintConfig.plugins ??= [];
134-
eslintConfig.plugins.push("eslint-plugin-next-on-pages");
135-
136-
if (typeof eslintConfig.extends === "string") {
137-
eslintConfig.extends = [eslintConfig.extends];
138-
}
139-
eslintConfig.extends ??= [];
140-
eslintConfig.extends.push("plugin:eslint-plugin-next-on-pages/recommended");
141-
142-
writeJSON(`${ctx.project.path}/.eslintrc.json`, eslintConfig);
143-
};
144-
145-
const addDevDependencies = async (installEslintPlugin: boolean) => {
146-
const packages = [
147-
"@cloudflare/next-on-pages@1",
148-
"@cloudflare/workers-types",
149-
"vercel",
150-
...(installEslintPlugin ? ["eslint-plugin-next-on-pages"] : []),
151-
];
152-
await installPackages(packages, {
153-
dev: true,
154-
startText: "Adding the Cloudflare Pages adapter",
155-
doneText: `${brandColor(`installed`)} ${dim(packages.join(", "))}`,
156-
});
157-
};
158-
159-
export default {
160-
configVersion: 1,
161-
id: "next",
162-
frameworkCli: "create-next-app",
163-
platform: "pages",
5+
const config: MultiPlatformTemplateConfig = {
1646
displayName: "Next.js",
165-
generate,
166-
configure,
167-
copyFiles: {
168-
async selectVariant(ctx) {
169-
const isApp = probePaths([
170-
`${ctx.project.path}/src/app`,
171-
`${ctx.project.path}/app`,
172-
]);
173-
174-
const isTypescript = usesTypescript(ctx);
175-
176-
const dir = isApp ? "app" : "pages";
177-
return `${dir}/${isTypescript ? "ts" : "js"}`;
178-
},
179-
destinationDir(ctx) {
180-
const srcPath = probePaths([`${ctx.project.path}/src`]);
181-
return srcPath ? "./src" : "./";
182-
},
183-
variants: {
184-
"app/ts": {
185-
path: "./app/ts",
186-
},
187-
"app/js": {
188-
path: "./app/js",
189-
},
190-
"pages/ts": {
191-
path: "./pages/ts",
192-
},
193-
"pages/js": {
194-
path: "./pages/js",
195-
},
196-
},
197-
},
198-
transformPackageJson: async (_, ctx) => {
199-
const isNpm = npm === "npm";
200-
const isBun = npm === "bun";
201-
const isNpmOrBun = isNpm || isBun;
202-
const nextOnPagesScope = isNpmOrBun ? "@cloudflare/" : "";
203-
const nextOnPagesCommand = `${nextOnPagesScope}next-on-pages`;
204-
const pmCommand = isNpmOrBun ? npx : npm;
205-
const pagesBuildRunCommand = `${
206-
isNpm ? "npm run" : isBun ? "bun" : pmCommand
207-
} pages:build`;
208-
return {
209-
scripts: {
210-
"pages:build": `${pmCommand} ${nextOnPagesCommand}`,
211-
preview: `${pagesBuildRunCommand} && wrangler pages dev`,
212-
deploy: `${pagesBuildRunCommand} && wrangler pages deploy`,
213-
...(usesTypescript(ctx) && {
214-
"cf-typegen": `wrangler types --env-interface CloudflareEnv env.d.ts`,
215-
}),
216-
},
217-
};
218-
},
219-
devScript: "dev",
220-
previewScript: "preview",
221-
deployScript: "deploy",
222-
compatibilityFlags: ["nodejs_compat"],
223-
} as TemplateConfig;
7+
platformVariants: { pages, workers },
8+
};
9+
export default config;
File renamed without changes.

0 commit comments

Comments
 (0)