diff --git a/.changeset/stale-snakes-boil.md b/.changeset/stale-snakes-boil.md new file mode 100644 index 000000000000..3308a40dd928 --- /dev/null +++ b/.changeset/stale-snakes-boil.md @@ -0,0 +1,7 @@ +--- +"create-cloudflare": patch +--- + +Graduate Next.js + Workers Assets template from experimental + +You no longer need the `--experimental` flag to access this template. diff --git a/packages/create-cloudflare/e2e-tests/cli.test.ts b/packages/create-cloudflare/e2e-tests/cli.test.ts index da1f128fac00..650ff99c1a93 100644 --- a/packages/create-cloudflare/e2e-tests/cli.test.ts +++ b/packages/create-cloudflare/e2e-tests/cli.test.ts @@ -476,7 +476,7 @@ describe.skipIf(frameworkToTest || isQuarantineMode())("help text", () => { npm create cloudflare -- --framework next -- --ts pnpm create cloudflare --framework next -- --ts Allowed Values: - next, solid + solid --platform= Whether the application should be deployed to Pages or Workers. This is only applicable for Frameworks templates that support both Pages and Workers. Allowed Values: diff --git a/packages/create-cloudflare/e2e-tests/frameworks/framework-test-config-experimental.ts b/packages/create-cloudflare/e2e-tests/frameworks/framework-test-config-experimental.ts index 42535451af90..f2ba3b1f2bf9 100644 --- a/packages/create-cloudflare/e2e-tests/frameworks/framework-test-config-experimental.ts +++ b/packages/create-cloudflare/e2e-tests/frameworks/framework-test-config-experimental.ts @@ -2,37 +2,6 @@ import { keys, LONG_TIMEOUT } from "../helpers"; export default function getFrameworkTestConfigExperimental() { return { - next: { - testCommitMessage: true, - flags: [ - "--ts", - "--tailwind", - "--eslint", - "--app", - "--import-alias", - "@/*", - "--src-dir", - ], - verifyBuildCfTypes: { - outputFile: "cloudflare-env.d.ts", - envInterfaceName: "CloudflareEnv", - }, - verifyPreview: { - route: "/test", - expectedText: "Create Next App", - }, - verifyDeploy: { - route: "/", - expectedText: "Create Next App", - }, - // see https://github.com/cloudflare/next-on-pages/blob/main/packages/next-on-pages/docs/supported.md#operating-systems - unsupportedOSs: ["win32"], - unsupportedPms: [ - // bun and yarn are failing in CI - "bun", - "yarn", - ], - }, solid: { promptHandlers: [ { diff --git a/packages/create-cloudflare/e2e-tests/frameworks/framework-test-config.ts b/packages/create-cloudflare/e2e-tests/frameworks/framework-test-config.ts index db3a592a1e6e..0dcaeaea2226 100644 --- a/packages/create-cloudflare/e2e-tests/frameworks/framework-test-config.ts +++ b/packages/create-cloudflare/e2e-tests/frameworks/framework-test-config.ts @@ -360,7 +360,8 @@ export default function getFrameworkTestConfig(pm: string) { }, flags: ["--typescript", "--no-install", "--no-git-init"], }, - next: { + "next:pages": { + argv: ["--platform", "pages"], promptHandlers: [ { matcher: /Do you want to use the next-on-pages eslint-plugin\?/, @@ -394,6 +395,38 @@ export default function getFrameworkTestConfig(pm: string) { "@/*", ], }, + "next:workers": { + argv: ["--platform", "workers"], + testCommitMessage: true, + flags: [ + "--ts", + "--tailwind", + "--eslint", + "--app", + "--import-alias", + "@/*", + "--src-dir", + ], + verifyBuildCfTypes: { + outputFile: "cloudflare-env.d.ts", + envInterfaceName: "CloudflareEnv", + }, + verifyPreview: { + route: "/test", + expectedText: "Create Next App", + }, + verifyDeploy: { + route: "/", + expectedText: "Create Next App", + }, + // see https://github.com/cloudflare/next-on-pages/blob/main/packages/next-on-pages/docs/supported.md#operating-systems + unsupportedOSs: ["win32"], + unsupportedPms: [ + // bun and yarn are failing in CI + "bun", + "yarn", + ], + }, "nuxt:pages": { argv: ["--platform", "pages"], testCommitMessage: true, diff --git a/packages/create-cloudflare/src/templates.ts b/packages/create-cloudflare/src/templates.ts index 04754a3777da..570b3259311d 100644 --- a/packages/create-cloudflare/src/templates.ts +++ b/packages/create-cloudflare/src/templates.ts @@ -18,7 +18,6 @@ import { writeFile, writeJSON, } from "helpers/files"; -import nextTemplateExperimental from "templates-experimental/next/c3"; import solidTemplateExperimental from "templates-experimental/solid/c3"; import analogTemplate from "templates/analog/c3"; import angularTemplate from "templates/angular/c3"; @@ -175,7 +174,6 @@ export type TemplateMap = Record< export function getFrameworkMap({ experimental = false }): TemplateMap { if (experimental) { return { - next: nextTemplateExperimental, solid: solidTemplateExperimental, }; } else { diff --git a/packages/create-cloudflare/templates/next/c3.ts b/packages/create-cloudflare/templates/next/c3.ts index 231f5ea9bf5b..f5146d4dab04 100644 --- a/packages/create-cloudflare/templates/next/c3.ts +++ b/packages/create-cloudflare/templates/next/c3.ts @@ -1,223 +1,9 @@ -import { join } from "path"; -import { updateStatus, warn } from "@cloudflare/cli"; -import { brandColor, dim } from "@cloudflare/cli/colors"; -import { inputPrompt, spinner } from "@cloudflare/cli/interactive"; -import { runFrameworkGenerator } from "frameworks/index"; -import { - copyFile, - probePaths, - readFile, - readJSON, - usesEslint, - usesTypescript, - writeFile, - writeJSON, -} from "helpers/files"; -import { detectPackageManager } from "helpers/packageManagers"; -import { installPackages } from "helpers/packages"; -import { getTemplatePath } from "../../src/templates"; -import type { TemplateConfig } from "../../src/templates"; -import type { C3Context } from "types"; +import pages from "./pages/c3"; +import workers from "./workers/c3"; +import type { MultiPlatformTemplateConfig } from "../../src/templates"; -const { npm, npx } = detectPackageManager(); - -const generate = async (ctx: C3Context) => { - const projectName = ctx.project.name; - - await runFrameworkGenerator(ctx, [projectName]); - - const wranglerConfig = readFile(join(getTemplatePath(ctx), "wrangler.jsonc")); - writeFile(join(ctx.project.path, "wrangler.jsonc"), wranglerConfig); - updateStatus("Created wrangler.jsonc file"); -}; - -const updateNextConfig = (usesTs: boolean) => { - const s = spinner(); - - const configFile = `next.config.${usesTs ? "ts" : "mjs"}`; - s.start(`Updating \`${configFile}\``); - - const configContent = readFile(configFile); - - const updatedConfigFile = - `import { setupDevPlatform } from '@cloudflare/next-on-pages/next-dev'; - - // Here we use the @cloudflare/next-on-pages next-dev module to allow us to - // use bindings during local development (when running the application with - // \`next dev\`). This function is only necessary during development and - // has no impact outside of that. For more information see: - // https://github.com/cloudflare/next-on-pages/blob/main/internal-packages/next-dev/README.md - setupDevPlatform().catch(console.error); - - `.replace(/\n\t*/g, "\n") + configContent; - - writeFile(configFile, updatedConfigFile); - - s.stop(`${brandColor(`updated`)} ${dim(`\`${configFile}\``)}`); -}; - -const configure = async (ctx: C3Context) => { - const projectPath = ctx.project.path; - - // Add a compatible function handler example - const path = probePaths([ - `${projectPath}/pages/api`, - `${projectPath}/src/pages/api`, - `${projectPath}/src/app/api`, - `${projectPath}/app/api`, - `${projectPath}/src/app`, - `${projectPath}/app`, - ]); - - if (!path) { - throw new Error("Could not find the `/api` or `/app` directory"); - } - - const usesTs = usesTypescript(ctx); - - if (usesTs) { - copyFile( - join(getTemplatePath(ctx), "env.d.ts"), - join(projectPath, "env.d.ts"), - ); - updateStatus("Created an env.d.ts file"); - } - - const installEslintPlugin = await shouldInstallNextOnPagesEslintPlugin(ctx); - - if (installEslintPlugin) { - await writeEslintrc(ctx); - } - - updateNextConfig(usesTs); - - copyFile( - join(getTemplatePath(ctx), "README.md"), - join(projectPath, "README.md"), - ); - updateStatus("Updated the README file"); - - await addDevDependencies(installEslintPlugin); -}; - -export const shouldInstallNextOnPagesEslintPlugin = async ( - ctx: C3Context, -): Promise => { - const eslintUsage = usesEslint(ctx); - - if (!eslintUsage.used) { - return false; - } - - if (eslintUsage.configType !== ".eslintrc.json") { - warn( - `Expected .eslintrc.json from Next.js scaffolding but found ${eslintUsage.configType} instead`, - ); - return false; - } - - return await inputPrompt({ - type: "confirm", - question: "Do you want to use the next-on-pages eslint-plugin?", - label: "eslint-plugin", - defaultValue: true, - }); -}; - -export const writeEslintrc = async (ctx: C3Context): Promise => { - const eslintConfig = readJSON(`${ctx.project.path}/.eslintrc.json`) as { - plugins: string[]; - extends: string | string[]; - }; - - eslintConfig.plugins ??= []; - eslintConfig.plugins.push("eslint-plugin-next-on-pages"); - - if (typeof eslintConfig.extends === "string") { - eslintConfig.extends = [eslintConfig.extends]; - } - eslintConfig.extends ??= []; - eslintConfig.extends.push("plugin:eslint-plugin-next-on-pages/recommended"); - - writeJSON(`${ctx.project.path}/.eslintrc.json`, eslintConfig); -}; - -const addDevDependencies = async (installEslintPlugin: boolean) => { - const packages = [ - "@cloudflare/next-on-pages@1", - "@cloudflare/workers-types", - "vercel", - ...(installEslintPlugin ? ["eslint-plugin-next-on-pages"] : []), - ]; - await installPackages(packages, { - dev: true, - startText: "Adding the Cloudflare Pages adapter", - doneText: `${brandColor(`installed`)} ${dim(packages.join(", "))}`, - }); -}; - -export default { - configVersion: 1, - id: "next", - frameworkCli: "create-next-app", - platform: "pages", +const config: MultiPlatformTemplateConfig = { displayName: "Next.js", - generate, - configure, - copyFiles: { - async selectVariant(ctx) { - const isApp = probePaths([ - `${ctx.project.path}/src/app`, - `${ctx.project.path}/app`, - ]); - - const isTypescript = usesTypescript(ctx); - - const dir = isApp ? "app" : "pages"; - return `${dir}/${isTypescript ? "ts" : "js"}`; - }, - destinationDir(ctx) { - const srcPath = probePaths([`${ctx.project.path}/src`]); - return srcPath ? "./src" : "./"; - }, - variants: { - "app/ts": { - path: "./app/ts", - }, - "app/js": { - path: "./app/js", - }, - "pages/ts": { - path: "./pages/ts", - }, - "pages/js": { - path: "./pages/js", - }, - }, - }, - transformPackageJson: async (_, ctx) => { - const isNpm = npm === "npm"; - const isBun = npm === "bun"; - const isNpmOrBun = isNpm || isBun; - const nextOnPagesScope = isNpmOrBun ? "@cloudflare/" : ""; - const nextOnPagesCommand = `${nextOnPagesScope}next-on-pages`; - const pmCommand = isNpmOrBun ? npx : npm; - const pagesBuildRunCommand = `${ - isNpm ? "npm run" : isBun ? "bun" : pmCommand - } pages:build`; - return { - scripts: { - "pages:build": `${pmCommand} ${nextOnPagesCommand}`, - preview: `${pagesBuildRunCommand} && wrangler pages dev`, - deploy: `${pagesBuildRunCommand} && wrangler pages deploy`, - ...(usesTypescript(ctx) && { - "cf-typegen": `wrangler types --env-interface CloudflareEnv env.d.ts`, - }), - }, - }; - }, - devScript: "dev", - previewScript: "preview", - deployScript: "deploy", - compatibilityFlags: ["nodejs_compat"], -} as TemplateConfig; + platformVariants: { pages, workers }, +}; +export default config; diff --git a/packages/create-cloudflare/templates/next/README.md b/packages/create-cloudflare/templates/next/pages/README.md similarity index 100% rename from packages/create-cloudflare/templates/next/README.md rename to packages/create-cloudflare/templates/next/pages/README.md diff --git a/packages/create-cloudflare/templates/next/app/js/app/api/hello/route.js b/packages/create-cloudflare/templates/next/pages/app/js/app/api/hello/route.js similarity index 100% rename from packages/create-cloudflare/templates/next/app/js/app/api/hello/route.js rename to packages/create-cloudflare/templates/next/pages/app/js/app/api/hello/route.js diff --git a/packages/create-cloudflare/templates/next/app/js/app/not-found.js b/packages/create-cloudflare/templates/next/pages/app/js/app/not-found.js similarity index 100% rename from packages/create-cloudflare/templates/next/app/js/app/not-found.js rename to packages/create-cloudflare/templates/next/pages/app/js/app/not-found.js diff --git a/packages/create-cloudflare/templates/next/app/ts/app/api/hello/route.ts b/packages/create-cloudflare/templates/next/pages/app/ts/app/api/hello/route.ts similarity index 100% rename from packages/create-cloudflare/templates/next/app/ts/app/api/hello/route.ts rename to packages/create-cloudflare/templates/next/pages/app/ts/app/api/hello/route.ts diff --git a/packages/create-cloudflare/templates/next/app/ts/app/not-found.tsx b/packages/create-cloudflare/templates/next/pages/app/ts/app/not-found.tsx similarity index 100% rename from packages/create-cloudflare/templates/next/app/ts/app/not-found.tsx rename to packages/create-cloudflare/templates/next/pages/app/ts/app/not-found.tsx diff --git a/packages/create-cloudflare/templates/next/pages/c3.ts b/packages/create-cloudflare/templates/next/pages/c3.ts new file mode 100644 index 000000000000..86f116f8ac28 --- /dev/null +++ b/packages/create-cloudflare/templates/next/pages/c3.ts @@ -0,0 +1,224 @@ +import { join } from "path"; +import { updateStatus, warn } from "@cloudflare/cli"; +import { brandColor, dim } from "@cloudflare/cli/colors"; +import { inputPrompt, spinner } from "@cloudflare/cli/interactive"; +import { runFrameworkGenerator } from "frameworks/index"; +import { + copyFile, + probePaths, + readFile, + readJSON, + usesEslint, + usesTypescript, + writeFile, + writeJSON, +} from "helpers/files"; +import { detectPackageManager } from "helpers/packageManagers"; +import { installPackages } from "helpers/packages"; +import { getTemplatePath } from "../../../src/templates"; +import type { TemplateConfig } from "../../../src/templates"; +import type { C3Context } from "types"; + +const { npm, npx } = detectPackageManager(); + +const generate = async (ctx: C3Context) => { + const projectName = ctx.project.name; + + await runFrameworkGenerator(ctx, [projectName]); + + const wranglerConfig = readFile(join(getTemplatePath(ctx), "wrangler.jsonc")); + writeFile(join(ctx.project.path, "wrangler.jsonc"), wranglerConfig); + updateStatus("Created wrangler.jsonc file"); +}; + +const updateNextConfig = (usesTs: boolean) => { + const s = spinner(); + + const configFile = `next.config.${usesTs ? "ts" : "mjs"}`; + s.start(`Updating \`${configFile}\``); + + const configContent = readFile(configFile); + + const updatedConfigFile = + `import { setupDevPlatform } from '@cloudflare/next-on-pages/next-dev'; + + // Here we use the @cloudflare/next-on-pages next-dev module to allow us to + // use bindings during local development (when running the application with + // \`next dev\`). This function is only necessary during development and + // has no impact outside of that. For more information see: + // https://github.com/cloudflare/next-on-pages/blob/main/internal-packages/next-dev/README.md + setupDevPlatform().catch(console.error); + + `.replace(/\n\t*/g, "\n") + configContent; + + writeFile(configFile, updatedConfigFile); + + s.stop(`${brandColor(`updated`)} ${dim(`\`${configFile}\``)}`); +}; + +const configure = async (ctx: C3Context) => { + const projectPath = ctx.project.path; + + // Add a compatible function handler example + const path = probePaths([ + `${projectPath}/pages/api`, + `${projectPath}/src/pages/api`, + `${projectPath}/src/app/api`, + `${projectPath}/app/api`, + `${projectPath}/src/app`, + `${projectPath}/app`, + ]); + + if (!path) { + throw new Error("Could not find the `/api` or `/app` directory"); + } + + const usesTs = usesTypescript(ctx); + + if (usesTs) { + copyFile( + join(getTemplatePath(ctx), "env.d.ts"), + join(projectPath, "env.d.ts"), + ); + updateStatus("Created an env.d.ts file"); + } + + const installEslintPlugin = await shouldInstallNextOnPagesEslintPlugin(ctx); + + if (installEslintPlugin) { + await writeEslintrc(ctx); + } + + updateNextConfig(usesTs); + + copyFile( + join(getTemplatePath(ctx), "README.md"), + join(projectPath, "README.md"), + ); + updateStatus("Updated the README file"); + + await addDevDependencies(installEslintPlugin); +}; + +export const shouldInstallNextOnPagesEslintPlugin = async ( + ctx: C3Context, +): Promise => { + const eslintUsage = usesEslint(ctx); + + if (!eslintUsage.used) { + return false; + } + + if (eslintUsage.configType !== ".eslintrc.json") { + warn( + `Expected .eslintrc.json from Next.js scaffolding but found ${eslintUsage.configType} instead`, + ); + return false; + } + + return await inputPrompt({ + type: "confirm", + question: "Do you want to use the next-on-pages eslint-plugin?", + label: "eslint-plugin", + defaultValue: true, + }); +}; + +export const writeEslintrc = async (ctx: C3Context): Promise => { + const eslintConfig = readJSON(`${ctx.project.path}/.eslintrc.json`) as { + plugins: string[]; + extends: string | string[]; + }; + + eslintConfig.plugins ??= []; + eslintConfig.plugins.push("eslint-plugin-next-on-pages"); + + if (typeof eslintConfig.extends === "string") { + eslintConfig.extends = [eslintConfig.extends]; + } + eslintConfig.extends ??= []; + eslintConfig.extends.push("plugin:eslint-plugin-next-on-pages/recommended"); + + writeJSON(`${ctx.project.path}/.eslintrc.json`, eslintConfig); +}; + +const addDevDependencies = async (installEslintPlugin: boolean) => { + const packages = [ + "@cloudflare/next-on-pages@1", + "@cloudflare/workers-types", + "vercel", + ...(installEslintPlugin ? ["eslint-plugin-next-on-pages"] : []), + ]; + await installPackages(packages, { + dev: true, + startText: "Adding the Cloudflare Pages adapter", + doneText: `${brandColor(`installed`)} ${dim(packages.join(", "))}`, + }); +}; + +export default { + configVersion: 1, + id: "next", + frameworkCli: "create-next-app", + platform: "pages", + displayName: "Next.js", + path: "templates/next/pages", + generate, + configure, + copyFiles: { + async selectVariant(ctx) { + const isApp = probePaths([ + `${ctx.project.path}/src/app`, + `${ctx.project.path}/app`, + ]); + + const isTypescript = usesTypescript(ctx); + + const dir = isApp ? "app" : "pages"; + return `${dir}/${isTypescript ? "ts" : "js"}`; + }, + destinationDir(ctx) { + const srcPath = probePaths([`${ctx.project.path}/src`]); + return srcPath ? "./src" : "./"; + }, + variants: { + "app/ts": { + path: "./app/ts", + }, + "app/js": { + path: "./app/js", + }, + "pages/ts": { + path: "./pages/ts", + }, + "pages/js": { + path: "./pages/js", + }, + }, + }, + transformPackageJson: async (_, ctx) => { + const isNpm = npm === "npm"; + const isBun = npm === "bun"; + const isNpmOrBun = isNpm || isBun; + const nextOnPagesScope = isNpmOrBun ? "@cloudflare/" : ""; + const nextOnPagesCommand = `${nextOnPagesScope}next-on-pages`; + const pmCommand = isNpmOrBun ? npx : npm; + const pagesBuildRunCommand = `${ + isNpm ? "npm run" : isBun ? "bun" : pmCommand + } pages:build`; + return { + scripts: { + "pages:build": `${pmCommand} ${nextOnPagesCommand}`, + preview: `${pagesBuildRunCommand} && wrangler pages dev`, + deploy: `${pagesBuildRunCommand} && wrangler pages deploy`, + ...(usesTypescript(ctx) && { + "cf-typegen": `wrangler types --env-interface CloudflareEnv env.d.ts`, + }), + }, + }; + }, + devScript: "dev", + previewScript: "preview", + deployScript: "deploy", + compatibilityFlags: ["nodejs_compat"], +} as TemplateConfig; diff --git a/packages/create-cloudflare/templates/next/env.d.ts b/packages/create-cloudflare/templates/next/pages/env.d.ts similarity index 100% rename from packages/create-cloudflare/templates/next/env.d.ts rename to packages/create-cloudflare/templates/next/pages/env.d.ts diff --git a/packages/create-cloudflare/templates/next/pages/js/pages/api/hello.js b/packages/create-cloudflare/templates/next/pages/pages/js/pages/api/hello.js similarity index 100% rename from packages/create-cloudflare/templates/next/pages/js/pages/api/hello.js rename to packages/create-cloudflare/templates/next/pages/pages/js/pages/api/hello.js diff --git a/packages/create-cloudflare/templates/next/pages/ts/pages/api/hello.ts b/packages/create-cloudflare/templates/next/pages/pages/ts/pages/api/hello.ts similarity index 100% rename from packages/create-cloudflare/templates/next/pages/ts/pages/api/hello.ts rename to packages/create-cloudflare/templates/next/pages/pages/ts/pages/api/hello.ts diff --git a/packages/create-cloudflare/templates/next/wrangler.jsonc b/packages/create-cloudflare/templates/next/pages/wrangler.jsonc similarity index 100% rename from packages/create-cloudflare/templates/next/wrangler.jsonc rename to packages/create-cloudflare/templates/next/pages/wrangler.jsonc diff --git a/packages/create-cloudflare/templates-experimental/next/c3.ts b/packages/create-cloudflare/templates/next/workers/c3.ts similarity index 92% rename from packages/create-cloudflare/templates-experimental/next/c3.ts rename to packages/create-cloudflare/templates/next/workers/c3.ts index 65f8b7d0eff4..59091419388b 100644 --- a/packages/create-cloudflare/templates-experimental/next/c3.ts +++ b/packages/create-cloudflare/templates/next/workers/c3.ts @@ -3,7 +3,7 @@ import { spinner } from "@cloudflare/cli/interactive"; import { runFrameworkGenerator } from "frameworks/index"; import { readFile, usesTypescript, writeFile } from "helpers/files"; import { installPackages } from "helpers/packages"; -import type { TemplateConfig } from "../../src/templates"; +import type { TemplateConfig } from "../../../src/templates"; import type { C3Context } from "types"; const generate = async (ctx: C3Context) => { @@ -51,11 +51,10 @@ export default { configVersion: 1, id: "next", frameworkCli: "create-next-app", - // TODO: Stop using a pinned version when the template graduates. frameworkCliPinnedVersion: "~15.2.2", platform: "workers", displayName: "Next.js (using Node.js compat + Workers Assets)", - path: "templates-experimental/next", + path: "templates/next/workers", copyFiles: { path: "./templates", }, diff --git a/packages/create-cloudflare/templates-experimental/next/templates/.dev.vars b/packages/create-cloudflare/templates/next/workers/templates/.dev.vars similarity index 100% rename from packages/create-cloudflare/templates-experimental/next/templates/.dev.vars rename to packages/create-cloudflare/templates/next/workers/templates/.dev.vars diff --git a/packages/create-cloudflare/templates-experimental/next/templates/.gitignore b/packages/create-cloudflare/templates/next/workers/templates/.gitignore similarity index 100% rename from packages/create-cloudflare/templates-experimental/next/templates/.gitignore rename to packages/create-cloudflare/templates/next/workers/templates/.gitignore diff --git a/packages/create-cloudflare/templates-experimental/next/templates/cloudflare-env.d.ts b/packages/create-cloudflare/templates/next/workers/templates/cloudflare-env.d.ts similarity index 100% rename from packages/create-cloudflare/templates-experimental/next/templates/cloudflare-env.d.ts rename to packages/create-cloudflare/templates/next/workers/templates/cloudflare-env.d.ts diff --git a/packages/create-cloudflare/templates-experimental/next/templates/open-next.config.ts b/packages/create-cloudflare/templates/next/workers/templates/open-next.config.ts similarity index 100% rename from packages/create-cloudflare/templates-experimental/next/templates/open-next.config.ts rename to packages/create-cloudflare/templates/next/workers/templates/open-next.config.ts diff --git a/packages/create-cloudflare/templates-experimental/next/templates/wrangler.jsonc b/packages/create-cloudflare/templates/next/workers/templates/wrangler.jsonc similarity index 100% rename from packages/create-cloudflare/templates-experimental/next/templates/wrangler.jsonc rename to packages/create-cloudflare/templates/next/workers/templates/wrangler.jsonc