mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
feat(cli): prisma + workers, prisma + turso, planetscale (postgres/mysql) support (#567)
This commit is contained in:
@@ -3,7 +3,6 @@ import fs from "fs-extra";
|
||||
import type { ProjectConfig } from "../../types";
|
||||
import { writeBtsConfig } from "../../utils/bts-config";
|
||||
import { exitWithError } from "../../utils/errors";
|
||||
import { formatProjectWithBiome } from "../../utils/format-with-biome";
|
||||
import { setupAddons } from "../addons/addons-setup";
|
||||
import { setupExamples } from "../addons/examples-setup";
|
||||
import { setupApi } from "../core/api-setup";
|
||||
@@ -86,8 +85,6 @@ export async function createProject(options: ProjectConfig) {
|
||||
|
||||
await writeBtsConfig(options);
|
||||
|
||||
await formatProjectWithBiome(projectDir);
|
||||
|
||||
if (isConvex) {
|
||||
await runConvexCodegen(projectDir, options.packageManager);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { setupCloudflareD1 } from "../database-providers/d1-setup";
|
||||
import { setupDockerCompose } from "../database-providers/docker-compose-setup";
|
||||
import { setupMongoDBAtlas } from "../database-providers/mongodb-atlas-setup";
|
||||
import { setupNeonPostgres } from "../database-providers/neon-setup";
|
||||
import { setupPlanetScale } from "../database-providers/planetscale-setup";
|
||||
import { setupPrismaPostgres } from "../database-providers/prisma-postgres-setup";
|
||||
import { setupSupabase } from "../database-providers/supabase-setup";
|
||||
import { setupTurso } from "../database-providers/turso-setup";
|
||||
@@ -36,11 +37,29 @@ export async function setupDatabase(config: ProjectConfig) {
|
||||
|
||||
try {
|
||||
if (orm === "prisma") {
|
||||
await addPackageDependency({
|
||||
dependencies: ["@prisma/client"],
|
||||
devDependencies: ["prisma"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
if (database === "mysql" && dbSetup === "planetscale") {
|
||||
await addPackageDependency({
|
||||
dependencies: [
|
||||
"@prisma/client",
|
||||
"@prisma/adapter-planetscale",
|
||||
"@planetscale/database",
|
||||
],
|
||||
devDependencies: ["prisma"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
} else if (database === "sqlite" && dbSetup === "turso") {
|
||||
await addPackageDependency({
|
||||
dependencies: ["@prisma/client", "@prisma/adapter-libsql"],
|
||||
devDependencies: ["prisma"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
} else {
|
||||
await addPackageDependency({
|
||||
dependencies: ["@prisma/client"],
|
||||
devDependencies: ["prisma"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
}
|
||||
} else if (orm === "drizzle") {
|
||||
if (database === "sqlite") {
|
||||
await addPackageDependency({
|
||||
@@ -55,6 +74,12 @@ export async function setupDatabase(config: ProjectConfig) {
|
||||
devDependencies: ["drizzle-kit", "@types/ws"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
} else if (dbSetup === "planetscale") {
|
||||
await addPackageDependency({
|
||||
dependencies: ["drizzle-orm", "pg"],
|
||||
devDependencies: ["drizzle-kit", "@types/pg"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
} else {
|
||||
await addPackageDependency({
|
||||
dependencies: ["drizzle-orm", "pg"],
|
||||
@@ -63,11 +88,19 @@ export async function setupDatabase(config: ProjectConfig) {
|
||||
});
|
||||
}
|
||||
} else if (database === "mysql") {
|
||||
await addPackageDependency({
|
||||
dependencies: ["drizzle-orm", "mysql2"],
|
||||
devDependencies: ["drizzle-kit"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
if (dbSetup === "planetscale") {
|
||||
await addPackageDependency({
|
||||
dependencies: ["drizzle-orm", "@planetscale/database"],
|
||||
devDependencies: ["drizzle-kit"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
} else {
|
||||
await addPackageDependency({
|
||||
dependencies: ["drizzle-orm", "mysql2"],
|
||||
devDependencies: ["drizzle-kit"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (orm === "mongoose") {
|
||||
await addPackageDependency({
|
||||
@@ -88,9 +121,15 @@ export async function setupDatabase(config: ProjectConfig) {
|
||||
await setupPrismaPostgres(config);
|
||||
} else if (dbSetup === "neon") {
|
||||
await setupNeonPostgres(config);
|
||||
} else if (dbSetup === "planetscale") {
|
||||
await setupPlanetScale(config);
|
||||
} else if (dbSetup === "supabase") {
|
||||
await setupSupabase(config);
|
||||
}
|
||||
} else if (database === "mysql") {
|
||||
if (dbSetup === "planetscale") {
|
||||
await setupPlanetScale(config);
|
||||
}
|
||||
} else if (database === "mongodb" && dbSetup === "mongodb-atlas") {
|
||||
await setupMongoDBAtlas(config);
|
||||
}
|
||||
|
||||
@@ -232,16 +232,8 @@ export async function setupEnvironmentVariables(config: ProjectConfig) {
|
||||
}
|
||||
|
||||
let databaseUrl: string | null = null;
|
||||
const specializedSetup =
|
||||
dbSetup === "turso" ||
|
||||
dbSetup === "prisma-postgres" ||
|
||||
dbSetup === "mongodb-atlas" ||
|
||||
dbSetup === "neon" ||
|
||||
dbSetup === "supabase" ||
|
||||
dbSetup === "d1" ||
|
||||
dbSetup === "docker";
|
||||
|
||||
if (database !== "none" && !specializedSetup) {
|
||||
if (database !== "none" && dbSetup === "none") {
|
||||
switch (database) {
|
||||
case "postgres":
|
||||
databaseUrl = "postgresql://postgres:password@localhost:5432/postgres";
|
||||
@@ -281,7 +273,7 @@ export async function setupEnvironmentVariables(config: ProjectConfig) {
|
||||
{
|
||||
key: "DATABASE_URL",
|
||||
value: databaseUrl,
|
||||
condition: database !== "none" && !specializedSetup,
|
||||
condition: database !== "none" && dbSetup === "none",
|
||||
},
|
||||
{
|
||||
key: "GOOGLE_GENERATIVE_AI_API_KEY",
|
||||
|
||||
@@ -287,22 +287,40 @@ async function getDatabaseInstructions(
|
||||
}
|
||||
|
||||
if (dbSetup === "d1" && serverDeploy === "alchemy") {
|
||||
instructions.push(
|
||||
`${pc.yellow(
|
||||
"NOTE:",
|
||||
)} D1 migrations are automatically handled by Alchemy`,
|
||||
);
|
||||
}
|
||||
|
||||
if (orm === "prisma") {
|
||||
if (dbSetup === "turso") {
|
||||
if (orm === "drizzle") {
|
||||
instructions.push(
|
||||
`${pc.yellow(
|
||||
"NOTE:",
|
||||
)} Turso support with Prisma is in Early Access and requires\n additional setup. Learn more at:\n https://www.prisma.io/docs/orm/overview/databases/turso`,
|
||||
)} D1 migrations are automatically handled by Alchemy`,
|
||||
);
|
||||
} else if (orm === "prisma") {
|
||||
instructions.push(
|
||||
`${pc.cyan("•")} Generate migrations: ${`${runCmd} db:generate`}`,
|
||||
);
|
||||
instructions.push(
|
||||
`${pc.cyan("•")} Apply migrations: ${`${runCmd} db:migrate`}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (dbSetup === "planetscale") {
|
||||
if (database === "mysql" && orm === "drizzle") {
|
||||
instructions.push(
|
||||
`${pc.yellow(
|
||||
"NOTE:",
|
||||
)} Enable foreign key constraints in PlanetScale database settings`,
|
||||
);
|
||||
}
|
||||
if (database === "mysql" && orm === "prisma") {
|
||||
instructions.push(
|
||||
`${pc.yellow(
|
||||
"NOTE:",
|
||||
)} How to handle Prisma migrations with PlanetScale:\n https://github.com/prisma/prisma/issues/7292`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (orm === "prisma") {
|
||||
if (database === "mongodb" && dbSetup === "docker") {
|
||||
instructions.push(
|
||||
`${pc.yellow(
|
||||
|
||||
@@ -76,9 +76,7 @@ async function updateRootPackageJson(
|
||||
}
|
||||
if (options.orm === "prisma") {
|
||||
scripts["db:generate"] = `turbo -F ${backendPackageName} db:generate`;
|
||||
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) {
|
||||
scripts["db:migrate"] = `turbo -F ${backendPackageName} db:migrate`;
|
||||
}
|
||||
scripts["db:migrate"] = `turbo -F ${backendPackageName} db:migrate`;
|
||||
} else if (options.orm === "drizzle") {
|
||||
scripts["db:generate"] = `turbo -F ${backendPackageName} db:generate`;
|
||||
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) {
|
||||
@@ -110,10 +108,8 @@ async function updateRootPackageJson(
|
||||
if (options.orm === "prisma") {
|
||||
scripts["db:generate"] =
|
||||
`pnpm --filter ${backendPackageName} db:generate`;
|
||||
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) {
|
||||
scripts["db:migrate"] =
|
||||
`pnpm --filter ${backendPackageName} db:migrate`;
|
||||
}
|
||||
scripts["db:migrate"] =
|
||||
`pnpm --filter ${backendPackageName} db:migrate`;
|
||||
} else if (options.orm === "drizzle") {
|
||||
scripts["db:generate"] =
|
||||
`pnpm --filter ${backendPackageName} db:generate`;
|
||||
@@ -149,10 +145,8 @@ async function updateRootPackageJson(
|
||||
if (options.orm === "prisma") {
|
||||
scripts["db:generate"] =
|
||||
`npm run db:generate --workspace ${backendPackageName}`;
|
||||
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) {
|
||||
scripts["db:migrate"] =
|
||||
`npm run db:migrate --workspace ${backendPackageName}`;
|
||||
}
|
||||
scripts["db:migrate"] =
|
||||
`npm run db:migrate --workspace ${backendPackageName}`;
|
||||
} else if (options.orm === "drizzle") {
|
||||
scripts["db:generate"] =
|
||||
`npm run db:generate --workspace ${backendPackageName}`;
|
||||
@@ -189,10 +183,8 @@ async function updateRootPackageJson(
|
||||
if (options.orm === "prisma") {
|
||||
scripts["db:generate"] =
|
||||
`bun run --filter ${backendPackageName} db:generate`;
|
||||
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) {
|
||||
scripts["db:migrate"] =
|
||||
`bun run --filter ${backendPackageName} db:migrate`;
|
||||
}
|
||||
scripts["db:migrate"] =
|
||||
`bun run --filter ${backendPackageName} db:migrate`;
|
||||
} else if (options.orm === "drizzle") {
|
||||
scripts["db:generate"] =
|
||||
`bun run --filter ${backendPackageName} db:generate`;
|
||||
@@ -278,9 +270,7 @@ async function updateServerPackageJson(
|
||||
scripts["db:studio"] = "prisma studio";
|
||||
}
|
||||
scripts["db:generate"] = "prisma generate";
|
||||
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) {
|
||||
scripts["db:migrate"] = "prisma migrate dev";
|
||||
}
|
||||
scripts["db:migrate"] = "prisma migrate dev";
|
||||
} else if (options.orm === "drizzle") {
|
||||
scripts["db:push"] = "drizzle-kit push";
|
||||
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import path from "node:path";
|
||||
import type { ProjectConfig } from "../../types";
|
||||
import { addPackageDependency } from "../../utils/add-package-deps";
|
||||
import { addEnvVariablesToFile, type EnvVariable } from "../core/env-setup";
|
||||
|
||||
export async function setupCloudflareD1(config: ProjectConfig) {
|
||||
const { projectDir, serverDeploy } = config;
|
||||
const { projectDir, serverDeploy, orm } = config;
|
||||
|
||||
if (serverDeploy === "wrangler") {
|
||||
const envPath = path.join(projectDir, "apps/server", ".env");
|
||||
@@ -30,4 +31,28 @@ export async function setupCloudflareD1(config: ProjectConfig) {
|
||||
await addEnvVariablesToFile(envPath, variables);
|
||||
} catch (_err) {}
|
||||
}
|
||||
|
||||
if (
|
||||
(serverDeploy === "wrangler" || serverDeploy === "alchemy") &&
|
||||
orm === "prisma"
|
||||
) {
|
||||
const envPath = path.join(projectDir, "apps/server", ".env");
|
||||
const variables: EnvVariable[] = [
|
||||
{
|
||||
key: "DATABASE_URL",
|
||||
value: "file:./local.db",
|
||||
condition: true,
|
||||
},
|
||||
];
|
||||
|
||||
try {
|
||||
await addEnvVariablesToFile(envPath, variables);
|
||||
} catch (_err) {}
|
||||
|
||||
const serverDir = path.join(projectDir, "apps/server");
|
||||
await addPackageDependency({
|
||||
dependencies: ["@prisma/adapter-d1"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import path from "node:path";
|
||||
import { cancel, isCancel, log, spinner, text } from "@clack/prompts";
|
||||
import { cancel, isCancel, log, select, spinner, text } from "@clack/prompts";
|
||||
import consola from "consola";
|
||||
import { execa } from "execa";
|
||||
import fs from "fs-extra";
|
||||
import pc from "picocolors";
|
||||
import type { ProjectConfig } from "../../types";
|
||||
import { commandExists } from "../../utils/command-exists";
|
||||
import { exitCancelled } from "../../utils/errors";
|
||||
import { addEnvVariablesToFile, type EnvVariable } from "../core/env-setup";
|
||||
|
||||
type MongoDBConfig = {
|
||||
@@ -130,6 +131,32 @@ export async function setupMongoDBAtlas(config: ProjectConfig) {
|
||||
try {
|
||||
await fs.ensureDir(serverDir);
|
||||
|
||||
const mode = await select({
|
||||
message: "MongoDB Atlas setup: choose mode",
|
||||
options: [
|
||||
{
|
||||
label: "Automatic",
|
||||
value: "auto",
|
||||
hint: "Automated setup with provider CLI, sets .env",
|
||||
},
|
||||
{
|
||||
label: "Manual",
|
||||
value: "manual",
|
||||
hint: "Manual setup, add env vars yourself",
|
||||
},
|
||||
],
|
||||
initialValue: "auto",
|
||||
});
|
||||
|
||||
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
||||
|
||||
if (mode === "manual") {
|
||||
mainSpinner.stop("MongoDB Atlas manual setup selected");
|
||||
await writeEnvFile(projectDir);
|
||||
displayManualSetupInstructions();
|
||||
return;
|
||||
}
|
||||
|
||||
mainSpinner.stop("MongoDB Atlas setup ready");
|
||||
|
||||
const config = await initMongoDBAtlas(serverDir);
|
||||
|
||||
@@ -158,6 +158,31 @@ export async function setupNeonPostgres(config: ProjectConfig) {
|
||||
const { packageManager, projectDir } = config;
|
||||
|
||||
try {
|
||||
const mode = await select({
|
||||
message: "Neon setup: choose mode",
|
||||
options: [
|
||||
{
|
||||
label: "Automatic",
|
||||
value: "auto",
|
||||
hint: "Automated setup with provider CLI, sets .env",
|
||||
},
|
||||
{
|
||||
label: "Manual",
|
||||
value: "manual",
|
||||
hint: "Manual setup, add env vars yourself",
|
||||
},
|
||||
],
|
||||
initialValue: "auto",
|
||||
});
|
||||
|
||||
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
||||
|
||||
if (mode === "manual") {
|
||||
await writeEnvFile(projectDir);
|
||||
displayManualSetupInstructions();
|
||||
return;
|
||||
}
|
||||
|
||||
const setupMethod = await select({
|
||||
message: "Choose your Neon setup method:",
|
||||
options: [
|
||||
|
||||
79
apps/cli/src/helpers/database-providers/planetscale-setup.ts
Normal file
79
apps/cli/src/helpers/database-providers/planetscale-setup.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import path from "node:path";
|
||||
import fs from "fs-extra";
|
||||
import type { ProjectConfig } from "../../types";
|
||||
import { addEnvVariablesToFile, type EnvVariable } from "../core/env-setup";
|
||||
|
||||
export async function setupPlanetScale(config: ProjectConfig) {
|
||||
const { projectDir, database, orm } = config;
|
||||
|
||||
const envPath = path.join(projectDir, "apps/server", ".env");
|
||||
|
||||
if (database === "mysql" && orm === "drizzle") {
|
||||
const variables: EnvVariable[] = [
|
||||
{
|
||||
key: "DATABASE_URL",
|
||||
value:
|
||||
'mysql://username:password@host/database?ssl={"rejectUnauthorized":true}',
|
||||
condition: true,
|
||||
},
|
||||
{
|
||||
key: "DATABASE_HOST",
|
||||
value: "",
|
||||
condition: true,
|
||||
},
|
||||
{
|
||||
key: "DATABASE_USERNAME",
|
||||
value: "",
|
||||
condition: true,
|
||||
},
|
||||
{
|
||||
key: "DATABASE_PASSWORD",
|
||||
value: "",
|
||||
condition: true,
|
||||
},
|
||||
];
|
||||
|
||||
await fs.ensureDir(path.join(projectDir, "apps/server"));
|
||||
await addEnvVariablesToFile(envPath, variables);
|
||||
}
|
||||
|
||||
if (database === "postgres" && orm === "prisma") {
|
||||
const variables: EnvVariable[] = [
|
||||
{
|
||||
key: "DATABASE_URL",
|
||||
value: "postgresql://username:password@host/database?sslaccept=strict",
|
||||
condition: true,
|
||||
},
|
||||
];
|
||||
|
||||
await fs.ensureDir(path.join(projectDir, "apps/server"));
|
||||
await addEnvVariablesToFile(envPath, variables);
|
||||
}
|
||||
|
||||
if (database === "postgres" && orm === "drizzle") {
|
||||
const variables: EnvVariable[] = [
|
||||
{
|
||||
key: "DATABASE_URL",
|
||||
value:
|
||||
"postgresql://username:password@host/database?sslmode=verify-full",
|
||||
condition: true,
|
||||
},
|
||||
];
|
||||
|
||||
await fs.ensureDir(path.join(projectDir, "apps/server"));
|
||||
await addEnvVariablesToFile(envPath, variables);
|
||||
}
|
||||
|
||||
if (database === "mysql" && orm === "prisma") {
|
||||
const variables: EnvVariable[] = [
|
||||
{
|
||||
key: "DATABASE_URL",
|
||||
value: "mysql://username:password@host/database?sslaccept=strict",
|
||||
condition: true,
|
||||
},
|
||||
];
|
||||
|
||||
await fs.ensureDir(path.join(projectDir, "apps/server"));
|
||||
await addEnvVariablesToFile(envPath, variables);
|
||||
}
|
||||
}
|
||||
@@ -245,6 +245,31 @@ export async function setupPrismaPostgres(config: ProjectConfig) {
|
||||
try {
|
||||
await fs.ensureDir(serverDir);
|
||||
|
||||
const mode = await select({
|
||||
message: "Prisma Postgres setup: choose mode",
|
||||
options: [
|
||||
{
|
||||
label: "Automatic",
|
||||
value: "auto",
|
||||
hint: "Automated setup with provider CLI, sets .env",
|
||||
},
|
||||
{
|
||||
label: "Manual",
|
||||
value: "manual",
|
||||
hint: "Manual setup, add env vars yourself",
|
||||
},
|
||||
],
|
||||
initialValue: "auto",
|
||||
});
|
||||
|
||||
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
||||
|
||||
if (mode === "manual") {
|
||||
await writeEnvFile(projectDir);
|
||||
displayManualSetupInstructions();
|
||||
return;
|
||||
}
|
||||
|
||||
const setupOptions = [
|
||||
{
|
||||
label: "Quick setup with create-db",
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import path from "node:path";
|
||||
import { log } from "@clack/prompts";
|
||||
import { isCancel, log, select } from "@clack/prompts";
|
||||
import { consola } from "consola";
|
||||
import { type ExecaError, execa } from "execa";
|
||||
import fs from "fs-extra";
|
||||
import pc from "picocolors";
|
||||
import type { PackageManager, ProjectConfig } from "../../types";
|
||||
import { exitCancelled } from "../../utils/errors";
|
||||
import { getPackageExecutionCommand } from "../../utils/package-runner";
|
||||
import { addEnvVariablesToFile, type EnvVariable } from "../core/env-setup";
|
||||
|
||||
@@ -159,6 +160,31 @@ export async function setupSupabase(config: ProjectConfig) {
|
||||
try {
|
||||
await fs.ensureDir(serverDir);
|
||||
|
||||
const mode = await select({
|
||||
message: "Supabase setup: choose mode",
|
||||
options: [
|
||||
{
|
||||
label: "Automatic",
|
||||
value: "auto",
|
||||
hint: "Automated setup with provider CLI, sets .env",
|
||||
},
|
||||
{
|
||||
label: "Manual",
|
||||
value: "manual",
|
||||
hint: "Manual setup, add env vars yourself",
|
||||
},
|
||||
],
|
||||
initialValue: "auto",
|
||||
});
|
||||
|
||||
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
||||
|
||||
if (mode === "manual") {
|
||||
displayManualSupabaseInstructions();
|
||||
await writeSupabaseEnvFile(projectDir, "");
|
||||
return;
|
||||
}
|
||||
|
||||
const initialized = await initializeSupabase(serverDir, packageManager);
|
||||
if (!initialized) {
|
||||
displayManualSupabaseInstructions();
|
||||
|
||||
@@ -197,23 +197,49 @@ export async function setupTurso(config: ProjectConfig) {
|
||||
const { orm, projectDir } = config;
|
||||
const _isDrizzle = orm === "drizzle";
|
||||
const setupSpinner = spinner();
|
||||
setupSpinner.start("Checking Turso CLI availability...");
|
||||
|
||||
try {
|
||||
const mode = await select({
|
||||
message: "Turso setup: choose mode",
|
||||
options: [
|
||||
{
|
||||
label: "Automatic",
|
||||
value: "auto",
|
||||
hint: "Automated setup with provider CLI, sets .env",
|
||||
},
|
||||
{
|
||||
label: "Manual",
|
||||
value: "manual",
|
||||
hint: "Manual setup, add env vars yourself",
|
||||
},
|
||||
],
|
||||
initialValue: "auto",
|
||||
});
|
||||
|
||||
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
||||
|
||||
if (mode === "manual") {
|
||||
await writeEnvFile(projectDir);
|
||||
displayManualSetupInstructions();
|
||||
return;
|
||||
}
|
||||
|
||||
setupSpinner.start("Checking Turso CLI availability...");
|
||||
const platform = os.platform();
|
||||
const isMac = platform === "darwin";
|
||||
const _isLinux = platform === "linux";
|
||||
const isWindows = platform === "win32";
|
||||
|
||||
if (isWindows) {
|
||||
setupSpinner.stop(pc.yellow("Turso setup not supported on Windows"));
|
||||
if (setupSpinner)
|
||||
setupSpinner.stop(pc.yellow("Turso setup not supported on Windows"));
|
||||
log.warn(pc.yellow("Automatic Turso setup is not supported on Windows."));
|
||||
await writeEnvFile(projectDir);
|
||||
displayManualSetupInstructions();
|
||||
return;
|
||||
}
|
||||
|
||||
setupSpinner.stop("Turso CLI availability checked");
|
||||
if (setupSpinner) setupSpinner.stop("Turso CLI availability checked");
|
||||
|
||||
const isCliInstalled = await isTursoInstalled();
|
||||
|
||||
@@ -273,7 +299,8 @@ export async function setupTurso(config: ProjectConfig) {
|
||||
|
||||
log.success("Turso database setup completed successfully!");
|
||||
} catch (error) {
|
||||
setupSpinner.stop(pc.red("Turso CLI availability check failed"));
|
||||
if (setupSpinner)
|
||||
setupSpinner.stop(pc.red("Turso CLI availability check failed"));
|
||||
consola.error(
|
||||
pc.red(
|
||||
`Error during Turso setup: ${
|
||||
|
||||
@@ -12,7 +12,8 @@ export async function setupNextAlchemyDeploy(
|
||||
if (!(await fs.pathExists(webAppDir))) return;
|
||||
|
||||
await addPackageDependency({
|
||||
devDependencies: ["alchemy", "dotenv"],
|
||||
dependencies: ["@opennextjs/cloudflare"],
|
||||
devDependencies: ["alchemy", "dotenv", "wrangler"],
|
||||
projectDir: webAppDir,
|
||||
});
|
||||
|
||||
@@ -29,4 +30,22 @@ export async function setupNextAlchemyDeploy(
|
||||
}
|
||||
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
||||
}
|
||||
|
||||
const openNextConfigPath = path.join(webAppDir, "open-next.config.ts");
|
||||
const openNextConfigContent = `import { defineCloudflareConfig } from "@opennextjs/cloudflare";
|
||||
|
||||
export default defineCloudflareConfig({});
|
||||
`;
|
||||
|
||||
await fs.writeFile(openNextConfigPath, openNextConfigContent);
|
||||
|
||||
const gitignorePath = path.join(webAppDir, ".gitignore");
|
||||
if (await fs.pathExists(gitignorePath)) {
|
||||
const gitignoreContent = await fs.readFile(gitignorePath, "utf-8");
|
||||
if (!gitignoreContent.includes("wrangler.jsonc")) {
|
||||
await fs.appendFile(gitignorePath, "\nwrangler.jsonc\n");
|
||||
}
|
||||
} else {
|
||||
await fs.writeFile(gitignorePath, "wrangler.jsonc\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import fs from "fs-extra";
|
||||
import pc from "picocolors";
|
||||
import type { PackageManager, ProjectConfig } from "../../types";
|
||||
import { addPackageDependency } from "../../utils/add-package-deps";
|
||||
import { getPackageExecutionCommand } from "../../utils/package-runner";
|
||||
|
||||
export async function setupServerDeploy(config: ProjectConfig) {
|
||||
const { serverDeploy, webDeploy, projectDir } = config;
|
||||
@@ -64,8 +65,11 @@ async function generateCloudflareWorkerTypes({
|
||||
const s = spinner();
|
||||
try {
|
||||
s.start("Generating Cloudflare Workers types...");
|
||||
const runCmd = packageManager === "npm" ? "npm" : packageManager;
|
||||
await execa(runCmd, ["run", "cf-typegen"], { cwd: serverDir });
|
||||
const runCmd = getPackageExecutionCommand(
|
||||
packageManager,
|
||||
"wrangler types --env-interface CloudflareBindings",
|
||||
);
|
||||
await execa(runCmd, { cwd: serverDir, shell: true });
|
||||
s.stop("Cloudflare Workers types generated successfully!");
|
||||
} catch {
|
||||
s.stop(pc.yellow("Failed to generate Cloudflare Workers types"));
|
||||
|
||||
Reference in New Issue
Block a user