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({
|
await addPackageDependency({
|
||||||
dependencies: ["ai", "@ai-sdk/google"],
|
dependencies: ["ai", "@ai-sdk/google"],
|
||||||
projectDir: serverDir,
|
projectDir: serverDir,
|
||||||
|
|||||||
@@ -213,15 +213,23 @@ export async function setupBackendFramework(
|
|||||||
projectDir: string,
|
projectDir: string,
|
||||||
context: ProjectConfig,
|
context: ProjectConfig,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
if (context.backend === "none") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverAppDir = path.join(projectDir, "apps/server");
|
||||||
|
|
||||||
if (context.backend === "convex") {
|
if (context.backend === "convex") {
|
||||||
|
if (await fs.pathExists(serverAppDir)) {
|
||||||
|
await fs.remove(serverAppDir);
|
||||||
|
}
|
||||||
|
|
||||||
const convexBackendDestDir = path.join(projectDir, "packages/backend");
|
const convexBackendDestDir = path.join(projectDir, "packages/backend");
|
||||||
const convexSrcDir = path.join(
|
const convexSrcDir = path.join(
|
||||||
PKG_ROOT,
|
PKG_ROOT,
|
||||||
"templates/backend/convex/packages/backend",
|
"templates/backend/convex/packages/backend",
|
||||||
);
|
);
|
||||||
|
|
||||||
await fs.ensureDir(convexBackendDestDir);
|
await fs.ensureDir(convexBackendDestDir);
|
||||||
|
|
||||||
if (await fs.pathExists(convexSrcDir)) {
|
if (await fs.pathExists(convexSrcDir)) {
|
||||||
await processAndCopyFiles(
|
await processAndCopyFiles(
|
||||||
"**/*",
|
"**/*",
|
||||||
@@ -229,17 +237,10 @@ export async function setupBackendFramework(
|
|||||||
convexBackendDestDir,
|
convexBackendDestDir,
|
||||||
context,
|
context,
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
}
|
|
||||||
|
|
||||||
const serverAppDir = path.join(projectDir, "apps/server");
|
|
||||||
if (await fs.pathExists(serverAppDir)) {
|
|
||||||
await fs.remove(serverAppDir);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverAppDir = path.join(projectDir, "apps/server");
|
|
||||||
await fs.ensureDir(serverAppDir);
|
await fs.ensureDir(serverAppDir);
|
||||||
|
|
||||||
const serverBaseDir = path.join(
|
const serverBaseDir = path.join(
|
||||||
@@ -540,7 +541,11 @@ export async function setupExamplesTemplate(
|
|||||||
|
|
||||||
const exampleBaseDir = path.join(PKG_ROOT, `templates/examples/${example}`);
|
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");
|
const exampleServerSrc = path.join(exampleBaseDir, "server");
|
||||||
|
|
||||||
if (example === "ai" && context.backend === "next") {
|
if (example === "ai" && context.backend === "next") {
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ async function main() {
|
|||||||
.option("backend", {
|
.option("backend", {
|
||||||
type: "string",
|
type: "string",
|
||||||
describe: "Backend framework",
|
describe: "Backend framework",
|
||||||
choices: ["hono", "express", "next", "elysia", "convex"],
|
choices: ["hono", "express", "next", "elysia", "convex", "none"],
|
||||||
})
|
})
|
||||||
.option("runtime", {
|
.option("runtime", {
|
||||||
type: "string",
|
type: "string",
|
||||||
@@ -303,6 +303,14 @@ async function main() {
|
|||||||
config.runtime = "none";
|
config.runtime = "none";
|
||||||
config.dbSetup = "none";
|
config.dbSetup = "none";
|
||||||
config.examples = ["todo"];
|
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") {
|
} else if (config.database === "none") {
|
||||||
config.orm = "none";
|
config.orm = "none";
|
||||||
config.auth = false;
|
config.auth = false;
|
||||||
@@ -389,17 +397,18 @@ function processAndValidateFlags(
|
|||||||
if (
|
if (
|
||||||
providedFlags.has("backend") &&
|
providedFlags.has("backend") &&
|
||||||
config.backend &&
|
config.backend &&
|
||||||
config.backend !== "convex"
|
config.backend !== "convex" &&
|
||||||
|
config.backend !== "none"
|
||||||
) {
|
) {
|
||||||
if (providedFlags.has("api") && options.api === "none") {
|
if (providedFlags.has("api") && options.api === "none") {
|
||||||
consola.fatal(
|
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);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
if (providedFlags.has("runtime") && options.runtime === "none") {
|
if (providedFlags.has("runtime") && options.runtime === "none") {
|
||||||
consola.fatal(
|
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);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
@@ -544,6 +553,48 @@ function processAndValidateFlags(
|
|||||||
config.runtime = "none";
|
config.runtime = "none";
|
||||||
config.dbSetup = "none";
|
config.dbSetup = "none";
|
||||||
config.examples = ["todo"];
|
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 {
|
} else {
|
||||||
const effectiveDatabase =
|
const effectiveDatabase =
|
||||||
config.database ?? (options.yes ? DEFAULT_CONFIG.database : undefined);
|
config.database ?? (options.yes ? DEFAULT_CONFIG.database : undefined);
|
||||||
@@ -635,7 +686,9 @@ function processAndValidateFlags(
|
|||||||
}
|
}
|
||||||
if (effectiveOrm !== "drizzle") {
|
if (effectiveOrm !== "drizzle") {
|
||||||
consola.fatal(
|
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);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
@@ -782,10 +835,11 @@ function processAndValidateFlags(
|
|||||||
if (
|
if (
|
||||||
config.examples.includes("todo") &&
|
config.examples.includes("todo") &&
|
||||||
effectiveBackend !== "convex" &&
|
effectiveBackend !== "convex" &&
|
||||||
|
effectiveBackend !== "none" &&
|
||||||
effectiveDatabase === "none"
|
effectiveDatabase === "none"
|
||||||
) {
|
) {
|
||||||
consola.fatal(
|
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);
|
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 pc from "picocolors";
|
||||||
import { DEFAULT_CONFIG } from "../constants";
|
import { DEFAULT_CONFIG } from "../constants";
|
||||||
import type { ProjectApi, ProjectBackend, ProjectFrontend } from "../types";
|
import type { ProjectApi, ProjectBackend, ProjectFrontend } from "../types";
|
||||||
@@ -8,7 +8,7 @@ export async function getApiChoice(
|
|||||||
frontend?: ProjectFrontend[],
|
frontend?: ProjectFrontend[],
|
||||||
backend?: ProjectBackend,
|
backend?: ProjectBackend,
|
||||||
): Promise<ProjectApi> {
|
): Promise<ProjectApi> {
|
||||||
if (backend === "convex") {
|
if (backend === "convex" || backend === "none") {
|
||||||
return "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;
|
let initialValue = DEFAULT_CONFIG.backend;
|
||||||
if (hasIncompatibleFrontend && initialValue === "convex") {
|
if (hasIncompatibleFrontend && initialValue === "convex") {
|
||||||
initialValue = "hono";
|
initialValue = "hono";
|
||||||
|
|||||||
@@ -106,6 +106,16 @@ export async function gatherConfig(
|
|||||||
result.dbSetup = "none";
|
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 {
|
return {
|
||||||
projectName: projectName,
|
projectName: projectName,
|
||||||
projectDir: projectDir,
|
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 pc from "picocolors";
|
||||||
import { DEFAULT_CONFIG } from "../constants";
|
import { DEFAULT_CONFIG } from "../constants";
|
||||||
import type { ProjectBackend, ProjectDatabase } from "../types";
|
import type { ProjectBackend, ProjectDatabase } from "../types";
|
||||||
@@ -7,7 +7,7 @@ export async function getDatabaseChoice(
|
|||||||
database?: ProjectDatabase,
|
database?: ProjectDatabase,
|
||||||
backend?: ProjectBackend,
|
backend?: ProjectBackend,
|
||||||
): Promise<ProjectDatabase> {
|
): Promise<ProjectDatabase> {
|
||||||
if (backend === "convex") {
|
if (backend === "convex" || backend === "none") {
|
||||||
return "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 pc from "picocolors";
|
||||||
import { DEFAULT_CONFIG } from "../constants";
|
import { DEFAULT_CONFIG } from "../constants";
|
||||||
import type {
|
import type {
|
||||||
@@ -20,6 +20,10 @@ export async function getExamplesChoice(
|
|||||||
return ["todo"];
|
return ["todo"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (backend === "none") {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
if (database === "none") return [];
|
if (database === "none") return [];
|
||||||
|
|
||||||
const onlyNative =
|
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 pc from "picocolors";
|
||||||
import { DEFAULT_CONFIG } from "../constants";
|
import { DEFAULT_CONFIG } from "../constants";
|
||||||
import type { ProjectBackend, ProjectRuntime } from "../types";
|
import type { ProjectBackend, ProjectRuntime } from "../types";
|
||||||
@@ -7,7 +7,7 @@ export async function getRuntimeChoice(
|
|||||||
runtime?: ProjectRuntime,
|
runtime?: ProjectRuntime,
|
||||||
backend?: ProjectBackend,
|
backend?: ProjectBackend,
|
||||||
): Promise<ProjectRuntime> {
|
): Promise<ProjectRuntime> {
|
||||||
if (backend === "convex") {
|
if (backend === "convex" || backend === "none") {
|
||||||
return "none";
|
return "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,13 @@ export type ProjectAddons =
|
|||||||
| "starlight"
|
| "starlight"
|
||||||
| "turborepo"
|
| "turborepo"
|
||||||
| "none";
|
| "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 ProjectRuntime = "node" | "bun" | "none";
|
||||||
export type ProjectExamples = "todo" | "ai" | "none";
|
export type ProjectExamples = "todo" | "ai" | "none";
|
||||||
export type ProjectFrontend =
|
export type ProjectFrontend =
|
||||||
|
|||||||
Reference in New Issue
Block a user