mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
make backend optional
This commit is contained in:
5
.changeset/few-dogs-grow.md
Normal file
5
.changeset/few-dogs-grow.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"create-better-t-stack": patch
|
||||
---
|
||||
|
||||
make backend optional
|
||||
@@ -39,7 +39,7 @@ export async function setupExamples(config: ProjectConfig): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
if (serverDirExists) {
|
||||
if (serverDirExists && backend !== "none") {
|
||||
await addPackageDependency({
|
||||
dependencies: ["ai", "@ai-sdk/google"],
|
||||
projectDir: serverDir,
|
||||
|
||||
@@ -213,15 +213,23 @@ export async function setupBackendFramework(
|
||||
projectDir: string,
|
||||
context: ProjectConfig,
|
||||
): Promise<void> {
|
||||
if (context.backend === "none") {
|
||||
return;
|
||||
}
|
||||
|
||||
const serverAppDir = path.join(projectDir, "apps/server");
|
||||
|
||||
if (context.backend === "convex") {
|
||||
if (await fs.pathExists(serverAppDir)) {
|
||||
await fs.remove(serverAppDir);
|
||||
}
|
||||
|
||||
const convexBackendDestDir = path.join(projectDir, "packages/backend");
|
||||
const convexSrcDir = path.join(
|
||||
PKG_ROOT,
|
||||
"templates/backend/convex/packages/backend",
|
||||
);
|
||||
|
||||
await fs.ensureDir(convexBackendDestDir);
|
||||
|
||||
if (await fs.pathExists(convexSrcDir)) {
|
||||
await processAndCopyFiles(
|
||||
"**/*",
|
||||
@@ -229,17 +237,10 @@ export async function setupBackendFramework(
|
||||
convexBackendDestDir,
|
||||
context,
|
||||
);
|
||||
} else {
|
||||
}
|
||||
|
||||
const serverAppDir = path.join(projectDir, "apps/server");
|
||||
if (await fs.pathExists(serverAppDir)) {
|
||||
await fs.remove(serverAppDir);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const serverAppDir = path.join(projectDir, "apps/server");
|
||||
await fs.ensureDir(serverAppDir);
|
||||
|
||||
const serverBaseDir = path.join(
|
||||
@@ -540,7 +541,11 @@ export async function setupExamplesTemplate(
|
||||
|
||||
const exampleBaseDir = path.join(PKG_ROOT, `templates/examples/${example}`);
|
||||
|
||||
if (serverAppDirExists && context.backend !== "convex") {
|
||||
if (
|
||||
serverAppDirExists &&
|
||||
context.backend !== "convex" &&
|
||||
context.backend !== "none"
|
||||
) {
|
||||
const exampleServerSrc = path.join(exampleBaseDir, "server");
|
||||
|
||||
if (example === "ai" && context.backend === "next") {
|
||||
|
||||
@@ -132,7 +132,7 @@ async function main() {
|
||||
.option("backend", {
|
||||
type: "string",
|
||||
describe: "Backend framework",
|
||||
choices: ["hono", "express", "next", "elysia", "convex"],
|
||||
choices: ["hono", "express", "next", "elysia", "convex", "none"],
|
||||
})
|
||||
.option("runtime", {
|
||||
type: "string",
|
||||
@@ -303,6 +303,14 @@ async function main() {
|
||||
config.runtime = "none";
|
||||
config.dbSetup = "none";
|
||||
config.examples = ["todo"];
|
||||
} else if (config.backend === "none") {
|
||||
config.auth = false;
|
||||
config.database = "none";
|
||||
config.orm = "none";
|
||||
config.api = "none";
|
||||
config.runtime = "none";
|
||||
config.dbSetup = "none";
|
||||
config.examples = [];
|
||||
} else if (config.database === "none") {
|
||||
config.orm = "none";
|
||||
config.auth = false;
|
||||
@@ -389,17 +397,18 @@ function processAndValidateFlags(
|
||||
if (
|
||||
providedFlags.has("backend") &&
|
||||
config.backend &&
|
||||
config.backend !== "convex"
|
||||
config.backend !== "convex" &&
|
||||
config.backend !== "none"
|
||||
) {
|
||||
if (providedFlags.has("api") && options.api === "none") {
|
||||
consola.fatal(
|
||||
`'--api none' is only supported with '--backend convex'. Please choose 'trpc', 'orpc', or remove the --api flag.`,
|
||||
`'--api none' is only supported with '--backend convex' or '--backend none'. Please choose 'trpc', 'orpc', or remove the --api flag.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
if (providedFlags.has("runtime") && options.runtime === "none") {
|
||||
consola.fatal(
|
||||
`'--runtime none' is only supported with '--backend convex'. Please choose 'bun', 'node', or remove the --runtime flag.`,
|
||||
`'--runtime none' is only supported with '--backend convex' or '--backend none'. Please choose 'bun', 'node', or remove the --runtime flag.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -544,6 +553,48 @@ function processAndValidateFlags(
|
||||
config.runtime = "none";
|
||||
config.dbSetup = "none";
|
||||
config.examples = ["todo"];
|
||||
} else if (config.backend === "none") {
|
||||
const incompatibleFlags: string[] = [];
|
||||
|
||||
if (providedFlags.has("auth") && options.auth === true)
|
||||
incompatibleFlags.push("--auth");
|
||||
if (providedFlags.has("database") && options.database !== "none")
|
||||
incompatibleFlags.push(`--database ${options.database}`);
|
||||
if (providedFlags.has("orm") && options.orm !== "none")
|
||||
incompatibleFlags.push(`--orm ${options.orm}`);
|
||||
if (providedFlags.has("api") && options.api !== "none")
|
||||
incompatibleFlags.push(`--api ${options.api}`);
|
||||
if (providedFlags.has("runtime") && options.runtime !== "none")
|
||||
incompatibleFlags.push(`--runtime ${options.runtime}`);
|
||||
if (providedFlags.has("dbSetup") && options.dbSetup !== "none")
|
||||
incompatibleFlags.push(`--db-setup ${options.dbSetup}`);
|
||||
|
||||
if (incompatibleFlags.length > 0) {
|
||||
consola.fatal(
|
||||
`The following flags are incompatible with '--backend none': ${incompatibleFlags.join(
|
||||
", ",
|
||||
)}. Please remove them.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
config.auth = false;
|
||||
config.database = "none";
|
||||
config.orm = "none";
|
||||
config.api = "none";
|
||||
config.runtime = "none";
|
||||
config.dbSetup = "none";
|
||||
if (
|
||||
options.examples &&
|
||||
!options.examples.includes("none") &&
|
||||
options.examples.length > 0
|
||||
) {
|
||||
consola.fatal(
|
||||
"Cannot select examples when backend is 'none'. Please remove the --examples flag or set --examples none.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
config.examples = [];
|
||||
} else {
|
||||
const effectiveDatabase =
|
||||
config.database ?? (options.yes ? DEFAULT_CONFIG.database : undefined);
|
||||
@@ -635,7 +686,9 @@ function processAndValidateFlags(
|
||||
}
|
||||
if (effectiveOrm !== "drizzle") {
|
||||
consola.fatal(
|
||||
`Turso setup requires Drizzle ORM. Cannot use --db-setup turso with --orm ${effectiveOrm ?? "none"}.`,
|
||||
`Turso setup requires Drizzle ORM. Cannot use --db-setup turso with --orm ${
|
||||
effectiveOrm ?? "none"
|
||||
}.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -782,10 +835,11 @@ function processAndValidateFlags(
|
||||
if (
|
||||
config.examples.includes("todo") &&
|
||||
effectiveBackend !== "convex" &&
|
||||
effectiveBackend !== "none" &&
|
||||
effectiveDatabase === "none"
|
||||
) {
|
||||
consola.fatal(
|
||||
"The 'todo' example requires a database (unless using Convex). Cannot use --examples todo when database is 'none'.",
|
||||
"The 'todo' example requires a database if a backend (other than Convex) is present. Cannot use --examples todo when database is 'none' and a backend is selected.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { cancel, isCancel, log, select } from "@clack/prompts";
|
||||
import { cancel, isCancel, select } from "@clack/prompts";
|
||||
import pc from "picocolors";
|
||||
import { DEFAULT_CONFIG } from "../constants";
|
||||
import type { ProjectApi, ProjectBackend, ProjectFrontend } from "../types";
|
||||
@@ -8,7 +8,7 @@ export async function getApiChoice(
|
||||
frontend?: ProjectFrontend[],
|
||||
backend?: ProjectBackend,
|
||||
): Promise<ProjectApi> {
|
||||
if (backend === "convex") {
|
||||
if (backend === "convex" || backend === "none") {
|
||||
return "none";
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,13 @@ export async function getBackendFrameworkChoice(
|
||||
});
|
||||
}
|
||||
|
||||
// Add "None" option
|
||||
backendOptions.push({
|
||||
value: "none" as const,
|
||||
label: "None",
|
||||
hint: "No backend server (e.g., for a static site or client-only app)",
|
||||
});
|
||||
|
||||
let initialValue = DEFAULT_CONFIG.backend;
|
||||
if (hasIncompatibleFrontend && initialValue === "convex") {
|
||||
initialValue = "hono";
|
||||
|
||||
@@ -106,6 +106,16 @@ export async function gatherConfig(
|
||||
result.dbSetup = "none";
|
||||
}
|
||||
|
||||
if (result.backend === "none") {
|
||||
result.runtime = "none";
|
||||
result.database = "none";
|
||||
result.orm = "none";
|
||||
result.api = "none";
|
||||
result.auth = false;
|
||||
result.dbSetup = "none";
|
||||
result.examples = [];
|
||||
}
|
||||
|
||||
return {
|
||||
projectName: projectName,
|
||||
projectDir: projectDir,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { cancel, isCancel, log, select } from "@clack/prompts";
|
||||
import { cancel, isCancel, select } from "@clack/prompts";
|
||||
import pc from "picocolors";
|
||||
import { DEFAULT_CONFIG } from "../constants";
|
||||
import type { ProjectBackend, ProjectDatabase } from "../types";
|
||||
@@ -7,7 +7,7 @@ export async function getDatabaseChoice(
|
||||
database?: ProjectDatabase,
|
||||
backend?: ProjectBackend,
|
||||
): Promise<ProjectDatabase> {
|
||||
if (backend === "convex") {
|
||||
if (backend === "convex" || backend === "none") {
|
||||
return "none";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { cancel, isCancel, log, multiselect } from "@clack/prompts";
|
||||
import { cancel, isCancel, multiselect } from "@clack/prompts";
|
||||
import pc from "picocolors";
|
||||
import { DEFAULT_CONFIG } from "../constants";
|
||||
import type {
|
||||
@@ -20,6 +20,10 @@ export async function getExamplesChoice(
|
||||
return ["todo"];
|
||||
}
|
||||
|
||||
if (backend === "none") {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (database === "none") return [];
|
||||
|
||||
const onlyNative =
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { cancel, isCancel, log, select } from "@clack/prompts";
|
||||
import { cancel, isCancel, select } from "@clack/prompts";
|
||||
import pc from "picocolors";
|
||||
import { DEFAULT_CONFIG } from "../constants";
|
||||
import type { ProjectBackend, ProjectRuntime } from "../types";
|
||||
@@ -7,7 +7,7 @@ export async function getRuntimeChoice(
|
||||
runtime?: ProjectRuntime,
|
||||
backend?: ProjectBackend,
|
||||
): Promise<ProjectRuntime> {
|
||||
if (backend === "convex") {
|
||||
if (backend === "convex" || backend === "none") {
|
||||
return "none";
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,13 @@ export type ProjectAddons =
|
||||
| "starlight"
|
||||
| "turborepo"
|
||||
| "none";
|
||||
export type ProjectBackend = "hono" | "elysia" | "express" | "next" | "convex";
|
||||
export type ProjectBackend =
|
||||
| "hono"
|
||||
| "express"
|
||||
| "next"
|
||||
| "elysia"
|
||||
| "convex"
|
||||
| "none";
|
||||
export type ProjectRuntime = "node" | "bun" | "none";
|
||||
export type ProjectExamples = "todo" | "ai" | "none";
|
||||
export type ProjectFrontend =
|
||||
|
||||
Reference in New Issue
Block a user