diff --git a/apps/cli/src/constants.ts b/apps/cli/src/constants.ts index 2812d2f..2e1b16b 100644 --- a/apps/cli/src/constants.ts +++ b/apps/cli/src/constants.ts @@ -138,7 +138,7 @@ export const dependencyVersionMap = { "@sveltejs/adapter-cloudflare": "^7.2.1", "@cloudflare/workers-types": "^4.20250822.0", - alchemy: "^0.62.1", + alchemy: "^0.63.0", // temporary workaround for alchemy + tanstack start nitropack: "^2.12.4", diff --git a/apps/cli/src/helpers/core/create-project.ts b/apps/cli/src/helpers/core/create-project.ts index b971609..8fd797f 100644 --- a/apps/cli/src/helpers/core/create-project.ts +++ b/apps/cli/src/helpers/core/create-project.ts @@ -76,11 +76,12 @@ export async function createProject(options: ProjectConfig) { await handleExtras(projectDir, options); + await setupEnvironmentVariables(options); + await updatePackageConfigurations(projectDir, options); + await setupWebDeploy(options); await setupServerDeploy(options); - await setupEnvironmentVariables(options); - await updatePackageConfigurations(projectDir, options); await createReadme(projectDir, options); await writeBtsConfig(options); diff --git a/apps/cli/src/helpers/core/create-readme.ts b/apps/cli/src/helpers/core/create-readme.ts index 2604e38..b0957de 100644 --- a/apps/cli/src/helpers/core/create-readme.ts +++ b/apps/cli/src/helpers/core/create-readme.ts @@ -35,6 +35,8 @@ function generateReadmeContent(options: ProjectConfig): string { frontend = ["tanstack-router"], backend = "hono", api = "trpc", + webDeploy, + serverDeploy, } = options; const isConvex = backend === "convex"; @@ -103,6 +105,7 @@ Follow the prompts to create a new Convex project and connect it to your applica packageManagerRunCmd, orm, options.dbSetup, + options.serverDeploy, ) } @@ -120,6 +123,8 @@ ${ : "" } +${generateDeploymentCommands(packageManagerRunCmd, webDeploy, serverDeploy)} + ## Project Structure \`\`\` @@ -475,6 +480,7 @@ function generateDatabaseSetup( packageManagerRunCmd: string, orm: ORM, dbSetup: DatabaseSetup, + serverDeploy?: string, ): string { if (database === "none") { return ""; @@ -494,7 +500,9 @@ function generateDatabaseSetup( 1. Start the local SQLite database: ${ dbSetup === "d1" - ? "Local development for a Cloudflare D1 database will already be running as part of the `wrangler dev` command." + ? serverDeploy === "alchemy" + ? "D1 local development and migrations are handled automatically by Alchemy during dev and deploy." + : "Local development for a Cloudflare D1 database will already be running as part of the `wrangler dev` command." : `\`\`\`bash cd apps/server && ${packageManagerRunCmd} db:local \`\`\` @@ -632,3 +640,51 @@ function generateScriptsList( return scripts; } + +function generateDeploymentCommands( + packageManagerRunCmd: string, + webDeploy?: string, + serverDeploy?: string, +): string { + const lines: string[] = []; + + if (webDeploy === "alchemy" || serverDeploy === "alchemy") { + lines.push("## Deployment (Alchemy)"); + if (webDeploy === "alchemy" && serverDeploy !== "alchemy") { + lines.push( + `- Web dev: cd apps/web && ${packageManagerRunCmd} dev`, + `- Web deploy: cd apps/web && ${packageManagerRunCmd} deploy`, + `- Web destroy: cd apps/web && ${packageManagerRunCmd} destroy`, + ); + } + if (serverDeploy === "alchemy" && webDeploy !== "alchemy") { + lines.push( + `- Server dev: cd apps/server && ${packageManagerRunCmd} dev`, + `- Server deploy: cd apps/server && ${packageManagerRunCmd} deploy`, + `- Server destroy: cd apps/server && ${packageManagerRunCmd} destroy`, + ); + } + if (webDeploy === "alchemy" && serverDeploy === "alchemy") { + lines.push( + `- Dev: ${packageManagerRunCmd} dev`, + `- Deploy: ${packageManagerRunCmd} deploy`, + `- Destroy: ${packageManagerRunCmd} destroy`, + ); + } + } + + if (webDeploy === "wrangler" || serverDeploy === "wrangler") { + lines.push("\n## Deployment (Cloudflare Wrangler)"); + if (webDeploy === "wrangler") { + lines.push(`- Web deploy: cd apps/web && ${packageManagerRunCmd} deploy`); + } + if (serverDeploy === "wrangler") { + lines.push( + `- Server dev: cd apps/server && ${packageManagerRunCmd} dev`, + `- Server deploy: cd apps/server && ${packageManagerRunCmd} deploy`, + ); + } + } + + return lines.length ? `\n${lines.join("\n")}\n` : ""; +} diff --git a/apps/cli/src/helpers/core/post-installation.ts b/apps/cli/src/helpers/core/post-installation.ts index 6513ca4..1fe012d 100644 --- a/apps/cli/src/helpers/core/post-installation.ts +++ b/apps/cli/src/helpers/core/post-installation.ts @@ -412,15 +412,15 @@ function getAlchemyDeployInstructions( if (webDeploy === "alchemy" && serverDeploy !== "alchemy") { instructions.push( - `${pc.bold("Deploy web with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/web && ${runCmd} alchemy:dev`}\n${pc.cyan("•")} Deploy: ${`cd apps/web && ${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`cd apps/web && ${runCmd} destroy`}`, + `${pc.bold("Deploy web with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/web && ${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`cd apps/web && ${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`cd apps/web && ${runCmd} destroy`}`, ); } else if (serverDeploy === "alchemy" && webDeploy !== "alchemy") { instructions.push( - `${pc.bold("Deploy server with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/server && ${runCmd} alchemy:dev`}\n${pc.cyan("•")} Deploy: ${`cd apps/server && ${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`cd apps/server && ${runCmd} destroy`}`, + `${pc.bold("Deploy server with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/server && ${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`cd apps/server && ${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`cd apps/server && ${runCmd} destroy`}`, ); } else if (webDeploy === "alchemy" && serverDeploy === "alchemy") { instructions.push( - `${pc.bold("Deploy with Alchemy:")}\n${pc.cyan("•")} Dev: ${`${runCmd} alchemy:dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`, + `${pc.bold("Deploy with Alchemy:")}\n${pc.cyan("•")} Dev: ${`${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`, ); } diff --git a/apps/cli/src/helpers/core/template-manager.ts b/apps/cli/src/helpers/core/template-manager.ts index 5290d3a..1cfa235 100644 --- a/apps/cli/src/helpers/core/template-manager.ts +++ b/apps/cli/src/helpers/core/template-manager.ts @@ -835,12 +835,6 @@ export async function setupDeploymentTemplates( serverAppDir, context, ); - await processAndCopyFiles( - "wrangler.jsonc.hbs", - alchemyTemplateSrc, - serverAppDir, - context, - ); } } } else { @@ -885,12 +879,6 @@ export async function setupDeploymentTemplates( serverAppDir, context, ); - await processAndCopyFiles( - "wrangler.jsonc.hbs", - alchemyTemplateSrc, - serverAppDir, - context, - ); } } } diff --git a/apps/cli/src/helpers/deployment/alchemy/alchemy-combined-setup.ts b/apps/cli/src/helpers/deployment/alchemy/alchemy-combined-setup.ts index 4f7c09d..8ac379b 100644 --- a/apps/cli/src/helpers/deployment/alchemy/alchemy-combined-setup.ts +++ b/apps/cli/src/helpers/deployment/alchemy/alchemy-combined-setup.ts @@ -29,7 +29,7 @@ export async function setupCombinedAlchemyDeploy( ...pkg.scripts, deploy: "alchemy deploy", destroy: "alchemy destroy", - "alchemy:dev": "alchemy dev", + dev: "alchemy dev", }; await fs.writeJson(rootPkgPath, pkg, { spaces: 2 }); } @@ -49,18 +49,32 @@ export async function setupCombinedAlchemyDeploy( const isSolid = frontend.includes("solid"); if (isNext) { - await setupNextAlchemyDeploy(projectDir, packageManager); + await setupNextAlchemyDeploy(projectDir, packageManager, { + skipAppScripts: true, + }); } else if (isNuxt) { - await setupNuxtAlchemyDeploy(projectDir, packageManager); + await setupNuxtAlchemyDeploy(projectDir, packageManager, { + skipAppScripts: true, + }); } else if (isSvelte) { - await setupSvelteAlchemyDeploy(projectDir, packageManager); + await setupSvelteAlchemyDeploy(projectDir, packageManager, { + skipAppScripts: true, + }); } else if (isTanstackStart) { - await setupTanStackStartAlchemyDeploy(projectDir, packageManager); + await setupTanStackStartAlchemyDeploy(projectDir, packageManager, { + skipAppScripts: true, + }); } else if (isTanstackRouter) { - await setupTanStackRouterAlchemyDeploy(projectDir, packageManager); + await setupTanStackRouterAlchemyDeploy(projectDir, packageManager, { + skipAppScripts: true, + }); } else if (isReactRouter) { - await setupReactRouterAlchemyDeploy(projectDir, packageManager); + await setupReactRouterAlchemyDeploy(projectDir, packageManager, { + skipAppScripts: true, + }); } else if (isSolid) { - await setupSolidAlchemyDeploy(projectDir, packageManager); + await setupSolidAlchemyDeploy(projectDir, packageManager, { + skipAppScripts: true, + }); } } diff --git a/apps/cli/src/helpers/deployment/alchemy/alchemy-next-setup.ts b/apps/cli/src/helpers/deployment/alchemy/alchemy-next-setup.ts index 870d806..df5e8a4 100644 --- a/apps/cli/src/helpers/deployment/alchemy/alchemy-next-setup.ts +++ b/apps/cli/src/helpers/deployment/alchemy/alchemy-next-setup.ts @@ -6,6 +6,7 @@ import { addPackageDependency } from "../../../utils/add-package-deps"; export async function setupNextAlchemyDeploy( projectDir: string, _packageManager: PackageManager, + options?: { skipAppScripts?: boolean }, ) { const webAppDir = path.join(projectDir, "apps/web"); if (!(await fs.pathExists(webAppDir))) return; @@ -19,12 +20,14 @@ export async function setupNextAlchemyDeploy( if (await fs.pathExists(pkgPath)) { const pkg = await fs.readJson(pkgPath); - pkg.scripts = { - ...pkg.scripts, - deploy: "alchemy deploy", - destroy: "alchemy destroy", - "alchemy:dev": "alchemy dev", - }; + if (!options?.skipAppScripts) { + pkg.scripts = { + ...pkg.scripts, + deploy: "alchemy deploy", + destroy: "alchemy destroy", + dev: "alchemy dev", + }; + } await fs.writeJson(pkgPath, pkg, { spaces: 2 }); } } diff --git a/apps/cli/src/helpers/deployment/alchemy/alchemy-nuxt-setup.ts b/apps/cli/src/helpers/deployment/alchemy/alchemy-nuxt-setup.ts index 31fb1e7..409df11 100644 --- a/apps/cli/src/helpers/deployment/alchemy/alchemy-nuxt-setup.ts +++ b/apps/cli/src/helpers/deployment/alchemy/alchemy-nuxt-setup.ts @@ -7,6 +7,7 @@ import { addPackageDependency } from "../../../utils/add-package-deps"; export async function setupNuxtAlchemyDeploy( projectDir: string, _packageManager: PackageManager, + options?: { skipAppScripts?: boolean }, ) { const webAppDir = path.join(projectDir, "apps/web"); if (!(await fs.pathExists(webAppDir))) return; @@ -20,12 +21,14 @@ export async function setupNuxtAlchemyDeploy( if (await fs.pathExists(pkgPath)) { const pkg = await fs.readJson(pkgPath); - pkg.scripts = { - ...pkg.scripts, - deploy: "alchemy deploy", - destroy: "alchemy destroy", - "alchemy:dev": "alchemy dev", - }; + if (!options?.skipAppScripts) { + pkg.scripts = { + ...pkg.scripts, + deploy: "alchemy deploy", + destroy: "alchemy destroy", + dev: "alchemy dev", + }; + } await fs.writeJson(pkgPath, pkg, { spaces: 2 }); } diff --git a/apps/cli/src/helpers/deployment/alchemy/alchemy-react-router-setup.ts b/apps/cli/src/helpers/deployment/alchemy/alchemy-react-router-setup.ts index 1db34e6..b3dd582 100644 --- a/apps/cli/src/helpers/deployment/alchemy/alchemy-react-router-setup.ts +++ b/apps/cli/src/helpers/deployment/alchemy/alchemy-react-router-setup.ts @@ -1,18 +1,18 @@ import path from "node:path"; import fs from "fs-extra"; -import { IndentationText, Node, Project, QuoteKind } from "ts-morph"; import type { PackageManager } from "../../../types"; import { addPackageDependency } from "../../../utils/add-package-deps"; export async function setupReactRouterAlchemyDeploy( projectDir: string, _packageManager: PackageManager, + options?: { skipAppScripts?: boolean }, ) { const webAppDir = path.join(projectDir, "apps/web"); if (!(await fs.pathExists(webAppDir))) return; await addPackageDependency({ - devDependencies: ["alchemy", "@cloudflare/vite-plugin", "dotenv"], + devDependencies: ["alchemy", "dotenv"], projectDir: webAppDir, }); @@ -20,149 +20,14 @@ export async function setupReactRouterAlchemyDeploy( if (await fs.pathExists(pkgPath)) { const pkg = await fs.readJson(pkgPath); - pkg.scripts = { - ...pkg.scripts, - deploy: "alchemy deploy", - destroy: "alchemy destroy", - "alchemy:dev": "alchemy dev", - }; + if (!options?.skipAppScripts) { + pkg.scripts = { + ...pkg.scripts, + deploy: "alchemy deploy", + destroy: "alchemy destroy", + dev: "alchemy dev", + }; + } await fs.writeJson(pkgPath, pkg, { spaces: 2 }); } - - const viteConfigPath = path.join(webAppDir, "vite.config.ts"); - if (await fs.pathExists(viteConfigPath)) { - try { - const project = new Project({ - manipulationSettings: { - indentationText: IndentationText.TwoSpaces, - quoteKind: QuoteKind.Double, - }, - }); - - project.addSourceFileAtPath(viteConfigPath); - const sourceFile = project.getSourceFileOrThrow(viteConfigPath); - - const alchemyImport = sourceFile.getImportDeclaration( - "alchemy/cloudflare/react-router", - ); - if (!alchemyImport) { - sourceFile.addImportDeclaration({ - moduleSpecifier: "alchemy/cloudflare/react-router", - defaultImport: "alchemy", - }); - } - - const exportAssignment = sourceFile.getExportAssignment( - (d) => !d.isExportEquals(), - ); - if (!exportAssignment) return; - - const defineConfigCall = exportAssignment.getExpression(); - if ( - !Node.isCallExpression(defineConfigCall) || - defineConfigCall.getExpression().getText() !== "defineConfig" - ) - return; - - let configObject = defineConfigCall.getArguments()[0]; - if (!configObject) { - configObject = defineConfigCall.addArgument("{}"); - } - - if (Node.isObjectLiteralExpression(configObject)) { - const pluginsProperty = configObject.getProperty("plugins"); - if (pluginsProperty && Node.isPropertyAssignment(pluginsProperty)) { - const initializer = pluginsProperty.getInitializer(); - if (Node.isArrayLiteralExpression(initializer)) { - const hasCloudflarePlugin = initializer - .getElements() - .some((el) => el.getText().includes("cloudflare(")); - - if (!hasCloudflarePlugin) { - initializer.addElement("alchemy()"); - } - } - } else if (!pluginsProperty) { - configObject.addPropertyAssignment({ - name: "plugins", - initializer: "[alchemy()]", - }); - } - } - - await project.save(); - } catch (error) { - console.warn("Failed to update vite.config.ts:", error); - } - } - - const reactRouterConfigPath = path.join(webAppDir, "react-router.config.ts"); - if (await fs.pathExists(reactRouterConfigPath)) { - try { - const project = new Project({ - manipulationSettings: { - indentationText: IndentationText.TwoSpaces, - quoteKind: QuoteKind.Double, - }, - }); - - project.addSourceFileAtPath(reactRouterConfigPath); - const sourceFile = project.getSourceFileOrThrow(reactRouterConfigPath); - - const exportAssignment = sourceFile.getExportAssignment( - (d) => !d.isExportEquals(), - ); - if (!exportAssignment) return; - - const configExpression = exportAssignment.getExpression(); - let configObject: Node | undefined; - - if (Node.isObjectLiteralExpression(configExpression)) { - configObject = configExpression; - } else if (Node.isSatisfiesExpression(configExpression)) { - const expression = configExpression.getExpression(); - if (Node.isObjectLiteralExpression(expression)) { - configObject = expression; - } - } - - if (!configObject || !Node.isObjectLiteralExpression(configObject)) - return; - - const futureProperty = configObject.getProperty("future"); - - if (!futureProperty) { - configObject.addPropertyAssignment({ - name: "future", - initializer: `{ - unstable_viteEnvironmentApi: true, - }`, - }); - } else if (Node.isPropertyAssignment(futureProperty)) { - const futureInitializer = futureProperty.getInitializer(); - - if (Node.isObjectLiteralExpression(futureInitializer)) { - const viteEnvApiProp = futureInitializer.getProperty( - "unstable_viteEnvironmentApi", - ); - - if (!viteEnvApiProp) { - futureInitializer.addPropertyAssignment({ - name: "unstable_viteEnvironmentApi", - initializer: "true", - }); - } else if (Node.isPropertyAssignment(viteEnvApiProp)) { - const value = viteEnvApiProp.getInitializer()?.getText(); - if (value === "false") { - viteEnvApiProp.setInitializer("true"); - } - } - } - } - - await project.save(); - } catch (error) { - console.warn("Failed to update react-router.config.ts:", error); - } - } } diff --git a/apps/cli/src/helpers/deployment/alchemy/alchemy-solid-setup.ts b/apps/cli/src/helpers/deployment/alchemy/alchemy-solid-setup.ts index ca2dd47..5b542c0 100644 --- a/apps/cli/src/helpers/deployment/alchemy/alchemy-solid-setup.ts +++ b/apps/cli/src/helpers/deployment/alchemy/alchemy-solid-setup.ts @@ -6,6 +6,7 @@ import { addPackageDependency } from "../../../utils/add-package-deps"; export async function setupSolidAlchemyDeploy( projectDir: string, _packageManager: PackageManager, + options?: { skipAppScripts?: boolean }, ) { const webAppDir = path.join(projectDir, "apps/web"); if (!(await fs.pathExists(webAppDir))) return; @@ -19,12 +20,14 @@ export async function setupSolidAlchemyDeploy( if (await fs.pathExists(pkgPath)) { const pkg = await fs.readJson(pkgPath); - pkg.scripts = { - ...pkg.scripts, - deploy: "alchemy deploy", - destroy: "alchemy destroy", - "alchemy:dev": "alchemy dev", - }; + if (!options?.skipAppScripts) { + pkg.scripts = { + ...pkg.scripts, + deploy: "alchemy deploy", + destroy: "alchemy destroy", + dev: "alchemy dev", + }; + } await fs.writeJson(pkgPath, pkg, { spaces: 2 }); } } diff --git a/apps/cli/src/helpers/deployment/alchemy/alchemy-svelte-setup.ts b/apps/cli/src/helpers/deployment/alchemy/alchemy-svelte-setup.ts index 963c392..1d12471 100644 --- a/apps/cli/src/helpers/deployment/alchemy/alchemy-svelte-setup.ts +++ b/apps/cli/src/helpers/deployment/alchemy/alchemy-svelte-setup.ts @@ -7,6 +7,7 @@ import { addPackageDependency } from "../../../utils/add-package-deps"; export async function setupSvelteAlchemyDeploy( projectDir: string, _packageManager: PackageManager, + options?: { skipAppScripts?: boolean }, ) { const webAppDir = path.join(projectDir, "apps/web"); if (!(await fs.pathExists(webAppDir))) return; @@ -20,12 +21,15 @@ export async function setupSvelteAlchemyDeploy( if (await fs.pathExists(pkgPath)) { const pkg = await fs.readJson(pkgPath); - pkg.scripts = { - ...pkg.scripts, - deploy: "alchemy deploy", - destroy: "alchemy destroy", - "alchemy:dev": "alchemy dev", - }; + if (!options?.skipAppScripts) { + pkg.scripts = { + ...pkg.scripts, + deploy: "alchemy deploy", + destroy: "alchemy destroy", + dev: "alchemy dev", + }; + } + await fs.writeJson(pkgPath, pkg, { spaces: 2 }); } diff --git a/apps/cli/src/helpers/deployment/alchemy/alchemy-tanstack-router-setup.ts b/apps/cli/src/helpers/deployment/alchemy/alchemy-tanstack-router-setup.ts index 3f78ced..14140f9 100644 --- a/apps/cli/src/helpers/deployment/alchemy/alchemy-tanstack-router-setup.ts +++ b/apps/cli/src/helpers/deployment/alchemy/alchemy-tanstack-router-setup.ts @@ -6,6 +6,7 @@ import { addPackageDependency } from "../../../utils/add-package-deps"; export async function setupTanStackRouterAlchemyDeploy( projectDir: string, _packageManager: PackageManager, + options?: { skipAppScripts?: boolean }, ) { const webAppDir = path.join(projectDir, "apps/web"); if (!(await fs.pathExists(webAppDir))) return; @@ -19,12 +20,15 @@ export async function setupTanStackRouterAlchemyDeploy( if (await fs.pathExists(pkgPath)) { const pkg = await fs.readJson(pkgPath); - pkg.scripts = { - ...pkg.scripts, - deploy: "alchemy deploy", - destroy: "alchemy destroy", - "alchemy:dev": "alchemy dev", - }; + if (!options?.skipAppScripts) { + pkg.scripts = { + ...pkg.scripts, + deploy: "alchemy deploy", + destroy: "alchemy destroy", + dev: "alchemy dev", + }; + } + await fs.writeJson(pkgPath, pkg, { spaces: 2 }); } } diff --git a/apps/cli/src/helpers/deployment/alchemy/alchemy-tanstack-start-setup.ts b/apps/cli/src/helpers/deployment/alchemy/alchemy-tanstack-start-setup.ts index e894fca..832eb26 100644 --- a/apps/cli/src/helpers/deployment/alchemy/alchemy-tanstack-start-setup.ts +++ b/apps/cli/src/helpers/deployment/alchemy/alchemy-tanstack-start-setup.ts @@ -7,6 +7,7 @@ import { addPackageDependency } from "../../../utils/add-package-deps"; export async function setupTanStackStartAlchemyDeploy( projectDir: string, _packageManager: PackageManager, + options?: { skipAppScripts?: boolean }, ) { const webAppDir = path.join(projectDir, "apps/web"); if (!(await fs.pathExists(webAppDir))) return; @@ -20,12 +21,15 @@ export async function setupTanStackStartAlchemyDeploy( if (await fs.pathExists(pkgPath)) { const pkg = await fs.readJson(pkgPath); - pkg.scripts = { - ...pkg.scripts, - deploy: "alchemy deploy", - destroy: "alchemy destroy", - "alchemy:dev": "alchemy dev", - }; + if (!options?.skipAppScripts) { + pkg.scripts = { + ...pkg.scripts, + deploy: "alchemy deploy", + destroy: "alchemy destroy", + dev: "alchemy dev", + }; + } + await fs.writeJson(pkgPath, pkg, { spaces: 2 }); } diff --git a/apps/cli/src/helpers/deployment/server-deploy-setup.ts b/apps/cli/src/helpers/deployment/server-deploy-setup.ts index 8612844..154c931 100644 --- a/apps/cli/src/helpers/deployment/server-deploy-setup.ts +++ b/apps/cli/src/helpers/deployment/server-deploy-setup.ts @@ -99,11 +99,9 @@ export async function setupAlchemyServerDeploy( packageJson.scripts = { ...packageJson.scripts, - dev: "wrangler dev --port=3000", - build: "wrangler deploy --dry-run", + dev: "alchemy dev", deploy: "alchemy deploy", destroy: "alchemy destroy", - "alchemy:dev": "alchemy dev", }; await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 }); diff --git a/apps/cli/src/prompts/web-deploy.ts b/apps/cli/src/prompts/web-deploy.ts index c112c47..cf08530 100644 --- a/apps/cli/src/prompts/web-deploy.ts +++ b/apps/cli/src/prompts/web-deploy.ts @@ -47,9 +47,7 @@ export async function getDeploymentChoice( return "none"; } - const hasIncompatibleFrontend = frontend.some( - (f) => f === "next" || f === "react-router", - ); + const hasIncompatibleFrontend = frontend.some((f) => f === "next"); const availableDeployments = hasIncompatibleFrontend ? ["wrangler", "none"] : ["wrangler", "alchemy", "none"]; @@ -84,9 +82,7 @@ export async function getDeploymentToAdd( return "none"; } - const hasIncompatibleFrontend = frontend.some( - (f) => f === "next" || f === "react-router", - ); + const hasIncompatibleFrontend = frontend.some((f) => f === "next"); const options: DeploymentOption[] = []; diff --git a/apps/cli/src/utils/compatibility-rules.ts b/apps/cli/src/utils/compatibility-rules.ts index 08d2cfc..ca4abc4 100644 --- a/apps/cli/src/utils/compatibility-rules.ts +++ b/apps/cli/src/utils/compatibility-rules.ts @@ -324,9 +324,7 @@ export function validateAlchemyCompatibility( const isAlchemyServerDeploy = serverDeploy === "alchemy"; if (isAlchemyWebDeploy || isAlchemyServerDeploy) { - const incompatibleFrontends = frontends.filter( - (f) => f === "next" || f === "react-router", - ); + const incompatibleFrontends = frontends.filter((f) => f === "next"); if (incompatibleFrontends.length > 0) { const deployType = diff --git a/apps/cli/templates/deploy/alchemy/alchemy.run.ts.hbs b/apps/cli/templates/deploy/alchemy/alchemy.run.ts.hbs index 86a07a2..891d446 100644 --- a/apps/cli/templates/deploy/alchemy/alchemy.run.ts.hbs +++ b/apps/cli/templates/deploy/alchemy/alchemy.run.ts.hbs @@ -17,7 +17,7 @@ import { Vite } from "alchemy/cloudflare"; {{/if}} {{/if}} {{#if (eq serverDeploy "alchemy")}} -import { Worker, WranglerJson } from "alchemy/cloudflare"; +import { Worker } from "alchemy/cloudflare"; {{#if (eq dbSetup "d1")}} import { D1Database } from "alchemy/cloudflare"; {{/if}} @@ -44,7 +44,6 @@ await Exec("db-generate", { }); const db = await D1Database("database", { - name: `${app.name}-${app.stage}-db`, migrationsDir: "apps/server/src/db/migrations", }); {{/if}} @@ -53,7 +52,6 @@ const db = await D1Database("database", { {{#if (includes frontend "next")}} export const web = await Next("web", { {{#if (eq serverDeploy "alchemy")}}cwd: "apps/web",{{/if}} - name: `${app.name}-${app.stage}-web`, bindings: { {{#if (eq backend "convex")}} NEXT_PUBLIC_CONVEX_URL: process.env.NEXT_PUBLIC_CONVEX_URL || "", @@ -68,7 +66,6 @@ export const web = await Next("web", { {{else if (includes frontend "nuxt")}} export const web = await Nuxt("web", { {{#if (eq serverDeploy "alchemy")}}cwd: "apps/web",{{/if}} - name: `${app.name}-${app.stage}-web`, bindings: { {{#if (eq backend "convex")}} NUXT_PUBLIC_CONVEX_URL: process.env.NUXT_PUBLIC_CONVEX_URL || "", @@ -83,7 +80,6 @@ export const web = await Nuxt("web", { {{else if (includes frontend "svelte")}} export const web = await SvelteKit("web", { {{#if (eq serverDeploy "alchemy")}}cwd: "apps/web",{{/if}} - name: `${app.name}-${app.stage}-web`, bindings: { {{#if (eq backend "convex")}} PUBLIC_CONVEX_URL: process.env.PUBLIC_CONVEX_URL || "", @@ -98,7 +94,6 @@ export const web = await SvelteKit("web", { {{else if (includes frontend "tanstack-start")}} export const web = await TanStackStart("web", { {{#if (eq serverDeploy "alchemy")}}cwd: "apps/web",{{/if}} - name: `${app.name}-${app.stage}-web`, bindings: { {{#if (eq backend "convex")}} VITE_CONVEX_URL: process.env.VITE_CONVEX_URL || "", @@ -113,7 +108,6 @@ export const web = await TanStackStart("web", { {{else if (includes frontend "tanstack-router")}} export const web = await Vite("web", { {{#if (eq serverDeploy "alchemy")}}cwd: "apps/web",{{/if}} - name: `${app.name}-${app.stage}-web`, assets: "dist", bindings: { {{#if (eq backend "convex")}} @@ -129,7 +123,6 @@ export const web = await Vite("web", { {{else if (includes frontend "react-router")}} export const web = await ReactRouter("web", { {{#if (eq serverDeploy "alchemy")}}cwd: "apps/web",{{/if}} - name: `${app.name}-${app.stage}-web`, bindings: { {{#if (eq backend "convex")}} VITE_CONVEX_URL: process.env.VITE_CONVEX_URL || "", @@ -144,7 +137,6 @@ export const web = await ReactRouter("web", { {{else if (includes frontend "solid")}} export const web = await Vite("web", { {{#if (eq serverDeploy "alchemy")}}cwd: "apps/web",{{/if}} - name: `${app.name}-${app.stage}-web`, assets: "dist", bindings: { {{#if (eq backend "convex")}} @@ -163,7 +155,6 @@ export const web = await Vite("web", { {{#if (eq serverDeploy "alchemy")}} export const server = await Worker("server", { {{#if (eq webDeploy "alchemy")}}cwd: "apps/server",{{/if}} - name: `${app.name}-${app.stage}`, entrypoint: "src/index.ts", compatibility: "node", bindings: { @@ -188,14 +179,8 @@ export const server = await Worker("server", { port: 3000, }, }); - -await WranglerJson("wrangler", { - worker: server, -}); {{/if}} - - {{#if (and (eq webDeploy "alchemy") (eq serverDeploy "alchemy"))}} console.log(`Web -> ${web.url}`); console.log(`Server -> ${server.url}`); diff --git a/apps/cli/templates/deploy/alchemy/wrangler.jsonc.hbs b/apps/cli/templates/deploy/alchemy/wrangler.jsonc.hbs deleted file mode 100644 index 69413c5..0000000 --- a/apps/cli/templates/deploy/alchemy/wrangler.jsonc.hbs +++ /dev/null @@ -1,11 +0,0 @@ -// This is a temporary wrangler.jsonc file that will be overwritten by alchemy -// It's only here so that `wrangler dev` can work or use alchemy dev instead -{ - "name": "{{projectName}}", - "main": "src/index.ts", - "compatibility_date": "2025-08-16", - "compatibility_flags": [ - "nodejs_compat", - "nodejs_compat_populate_process_env" - ] -} diff --git a/apps/cli/test/cli.smoke.test.ts b/apps/cli/test/cli.smoke.test.ts index 9088db6..8c744e1 100644 --- a/apps/cli/test/cli.smoke.test.ts +++ b/apps/cli/test/cli.smoke.test.ts @@ -2804,27 +2804,8 @@ describe("create-better-t-stack smoke", () => { consola.success(`${dirName} built successfully`); } - if (scripts["check-types"]) { - consola.start(`Type checking ${dirName}...`); - const typeRes = await runScript( - pm, - projectDir, - "check-types", - [], - 120_000, - ); - expect(typeRes.exitCode).toBe(0); - consola.success(`${dirName} type check passed`); - } - - if (!scripts.build && !scripts["check-types"]) { - consola.info( - `No build or check-types script for ${dirName}, skipping`, - ); - } else if (!scripts.build && scripts["check-types"]) { - consola.info( - `Only check-types script available for ${dirName}, type checking will be performed`, - ); + if (!scripts.build) { + consola.info(`No build script for ${dirName}, skipping`); } } catch (error) { consola.error(`${dirName} failed`, error); diff --git a/apps/web/src/app/(home)/_components/stack-builder.tsx b/apps/web/src/app/(home)/_components/stack-builder.tsx index 36828f8..8eaf93d 100644 --- a/apps/web/src/app/(home)/_components/stack-builder.tsx +++ b/apps/web/src/app/(home)/_components/stack-builder.tsx @@ -1005,7 +1005,7 @@ const analyzeStackCompatibility = (stack: StackState): CompatibilityResult => { if (isAlchemyWebDeploy || isAlchemyServerDeploy) { const incompatibleFrontends = nextStack.webFrontend.filter( - (f) => f === "next" || f === "react-router", + (f) => f === "next", ); if (incompatibleFrontends.length > 0) { @@ -1029,9 +1029,7 @@ const analyzeStackCompatibility = (stack: StackState): CompatibilityResult => { notes.webDeploy.hasIssue = true; notes.serverDeploy.hasIssue = true; - nextStack.webFrontend = nextStack.webFrontend.filter( - (f) => f !== "next" && f !== "react-router", - ); + nextStack.webFrontend = nextStack.webFrontend.filter((f) => f !== "next"); if (nextStack.webFrontend.length === 0) { nextStack.webFrontend = ["tanstack-router"]; @@ -1632,10 +1630,7 @@ const StackBuilder = () => { const { adjustedStack } = analyzeStackCompatibility(simulatedStack); const finalStack = adjustedStack ?? simulatedStack; - if ( - category === "webFrontend" && - (optionId === "next" || optionId === "react-router") - ) { + if (category === "webFrontend" && optionId === "next") { const isAlchemyWebDeploy = finalStack.webDeploy === "alchemy"; const isAlchemyServerDeploy = finalStack.serverDeploy === "alchemy";