From 8209713bd644a812cfd2f9fa81adc5da97ab13cc Mon Sep 17 00:00:00 2001 From: Aman Varshney Date: Sat, 10 May 2025 08:10:23 +0530 Subject: [PATCH] fix: backend none templates (#241) --- .changeset/fair-pigs-wash.md | 5 + apps/cli/src/utils/display-config.ts | 4 +- .../utils/generate-reproducible-command.ts | 46 +++----- .../trpc/web/react/base/src/utils/trpc.ts.hbs | 7 +- .../web/react/next/src/app/todos/page.tsx.hbs | 99 +++++++++++++++-- .../react-router/src/routes/todos.tsx.hbs | 1 - .../nativewind/app/(drawer)/index.tsx.hbs | 48 ++++---- .../native/nativewind/app/_layout.tsx.hbs | 17 +++ .../unistyles/app/(drawer)/index.tsx.hbs | 46 +++++--- .../native/unistyles/app/_layout.tsx.hbs | 24 ++++ .../layouts/{default.vue => default.vue.hbs} | 0 .../app/pages/{index.vue => index.vue.hbs} | 7 +- .../{vue-query.ts => vue-query.ts.hbs} | 0 .../frontend/react/next/src/app/page.tsx.hbs | 34 +++--- .../next/src/components/providers.tsx.hbs | 67 +++++------ .../react/react-router/src/root.tsx.hbs | 104 ++++++++++-------- .../react-router/src/routes/_index.tsx.hbs | 38 ++++--- .../react/tanstack-router/src/main.tsx.hbs | 55 +++++---- .../tanstack-router/src/routes/__root.tsx.hbs | 58 +++------- .../tanstack-router/src/routes/index.tsx.hbs | 31 +++--- .../react/tanstack-start/src/router.tsx.hbs | 35 +++--- .../tanstack-start/src/routes/__root.tsx.hbs | 14 ++- .../tanstack-start/src/routes/index.tsx.hbs | 41 +++---- .../templates/frontend/solid/src/main.tsx.hbs | 6 + .../frontend/solid/src/routes/__root.tsx.hbs | 15 ++- .../frontend/solid/src/routes/index.tsx.hbs | 9 +- .../svelte/src/routes/+layout.svelte.hbs | 21 +++- .../svelte/src/routes/+page.svelte.hbs | 18 +-- bun.lock | 22 ++-- 29 files changed, 519 insertions(+), 353 deletions(-) create mode 100644 .changeset/fair-pigs-wash.md rename apps/cli/templates/frontend/nuxt/app/layouts/{default.vue => default.vue.hbs} (100%) rename apps/cli/templates/frontend/nuxt/app/pages/{index.vue => index.vue.hbs} (96%) rename apps/cli/templates/frontend/nuxt/app/plugins/{vue-query.ts => vue-query.ts.hbs} (100%) diff --git a/.changeset/fair-pigs-wash.md b/.changeset/fair-pigs-wash.md new file mode 100644 index 0000000..e462bc0 --- /dev/null +++ b/.changeset/fair-pigs-wash.md @@ -0,0 +1,5 @@ +--- +"create-better-t-stack": patch +--- + +fix templates when backend is none diff --git a/apps/cli/src/utils/display-config.ts b/apps/cli/src/utils/display-config.ts index d521bb3..76a2dbf 100644 --- a/apps/cli/src/utils/display-config.ts +++ b/apps/cli/src/utils/display-config.ts @@ -20,9 +20,7 @@ export function displayConfig(config: Partial) { } if (config.backend !== undefined) { - configDisplay.push( - `${pc.blue("Backend Framework:")} ${String(config.backend)}`, - ); + configDisplay.push(`${pc.blue("Backend:")} ${String(config.backend)}`); } if (config.runtime !== undefined) { diff --git a/apps/cli/src/utils/generate-reproducible-command.ts b/apps/cli/src/utils/generate-reproducible-command.ts index 38a9ad5..83f546b 100644 --- a/apps/cli/src/utils/generate-reproducible-command.ts +++ b/apps/cli/src/utils/generate-reproducible-command.ts @@ -3,40 +3,19 @@ import type { ProjectConfig } from "../types"; export function generateReproducibleCommand(config: ProjectConfig): string { const flags: string[] = []; - if (config.database === "none") { - flags.push("--database none"); - } else { - flags.push(`--database ${config.database}`); - - if (config.orm) { - flags.push(`--orm ${config.orm}`); - } - - if (config.dbSetup) { - flags.push(`--db-setup ${config.dbSetup}`); - } - } - - if (config.api) { - flags.push(`--api ${config.api}`); - } - - flags.push(config.auth ? "--auth" : "--no-auth"); - flags.push(config.git ? "--git" : "--no-git"); - flags.push(config.install ? "--install" : "--no-install"); - - if (config.runtime) { - flags.push(`--runtime ${config.runtime}`); - } - - if (config.backend) { - flags.push(`--backend ${config.backend}`); - } - if (config.frontend && config.frontend.length > 0) { flags.push(`--frontend ${config.frontend.join(" ")}`); + } else { + flags.push("--frontend none"); } + flags.push(`--backend ${config.backend}`); + flags.push(`--runtime ${config.runtime}`); + flags.push(`--database ${config.database}`); + flags.push(`--orm ${config.orm}`); + flags.push(`--api ${config.api}`); + flags.push(config.auth ? "--auth" : "--no-auth"); + if (config.addons && config.addons.length > 0) { flags.push(`--addons ${config.addons.join(" ")}`); } else { @@ -49,9 +28,10 @@ export function generateReproducibleCommand(config: ProjectConfig): string { flags.push("--examples none"); } - if (config.packageManager) { - flags.push(`--package-manager ${config.packageManager}`); - } + flags.push(`--db-setup ${config.dbSetup}`); + flags.push(config.git ? "--git" : "--no-git"); + flags.push(`--package-manager ${config.packageManager}`); + flags.push(config.install ? "--install" : "--no-install"); let baseCommand = ""; const pkgManager = config.packageManager; diff --git a/apps/cli/templates/api/trpc/web/react/base/src/utils/trpc.ts.hbs b/apps/cli/templates/api/trpc/web/react/base/src/utils/trpc.ts.hbs index 3d6cc97..90e0e56 100644 --- a/apps/cli/templates/api/trpc/web/react/base/src/utils/trpc.ts.hbs +++ b/apps/cli/templates/api/trpc/web/react/base/src/utils/trpc.ts.hbs @@ -1,5 +1,4 @@ {{#if (includes frontend 'next')}} -{{!-- Next.js tRPC Client Setup --}} import { QueryCache, QueryClient } from '@tanstack/react-query'; import { createTRPCClient, httpBatchLink } from '@trpc/client'; import { createTRPCOptionsProxy } from '@trpc/tanstack-react-query'; @@ -47,16 +46,14 @@ export const trpc = createTRPCOptionsProxy({ }); {{else if (includes frontend 'tanstack-start')}} -{{!-- TanStack Start tRPC Client Setup --}} import { createTRPCContext } from "@trpc/tanstack-react-query"; -import type { AppRouter } from "../../../server/src/routers"; {{! Adjust path if necessary }} +import type { AppRouter } from "../../../server/src/routers"; export const { TRPCProvider, useTRPC, useTRPCClient } = createTRPCContext(); {{else}} -{{!-- Default Web tRPC Client Setup (TanStack Router, React Router, etc.) --}} -import type { AppRouter } from "../../../server/src/routers"; {{! Adjust path if necessary }} +import type { AppRouter } from "../../../server/src/routers"; import { QueryCache, QueryClient } from "@tanstack/react-query"; import { createTRPCClient, httpBatchLink } from "@trpc/client"; import { createTRPCOptionsProxy } from "@trpc/tanstack-react-query"; diff --git a/apps/cli/templates/examples/todo/web/react/next/src/app/todos/page.tsx.hbs b/apps/cli/templates/examples/todo/web/react/next/src/app/todos/page.tsx.hbs index 662beb4..f20b3e4 100644 --- a/apps/cli/templates/examples/todo/web/react/next/src/app/todos/page.tsx.hbs +++ b/apps/cli/templates/examples/todo/web/react/next/src/app/todos/page.tsx.hbs @@ -12,20 +12,48 @@ import { Checkbox } from "@/components/ui/checkbox"; import { Input } from "@/components/ui/input"; import { Loader2, Trash2 } from "lucide-react"; import { useState } from "react"; -import { useMutation, useQuery } from "@tanstack/react-query"; -{{#if (eq api "orpc")}} +{{#if (eq backend "convex")}} +import { useMutation, useQuery } from "convex/react"; +import { api } from "@{{projectName}}/backend/convex/_generated/api.js"; +import type { Id } from "@{{projectName}}/backend/convex/_generated/dataModel.d.ts"; +{{else}} +import { useMutation, useQuery } from "@tanstack/react-query"; + {{#if (eq api "orpc")}} import { orpc } from "@/utils/orpc"; -{{/if}} -{{#if (eq api "trpc")}} + {{/if}} + {{#if (eq api "trpc")}} import { trpc } from "@/utils/trpc"; + {{/if}} {{/if}} export default function TodosPage() { const [newTodoText, setNewTodoText] = useState(""); - {{#if (eq api "orpc")}} + {{#if (eq backend "convex")}} + const todos = useQuery(api.todos.getAll); + const createTodoMutation = useMutation(api.todos.create); + const toggleTodoMutation = useMutation(api.todos.toggle); + const deleteTodoMutation = useMutation(api.todos.deleteTodo); + + const handleAddTodo = async (e: React.FormEvent) => { + e.preventDefault(); + const text = newTodoText.trim(); + if (!text) return; + await createTodoMutation({ text }); + setNewTodoText(""); + }; + + const handleToggleTodo = (id: Id<"todos">, currentCompleted: boolean) => { + toggleTodoMutation({ id, completed: !currentCompleted }); + }; + + const handleDeleteTodo = (id: Id<"todos">) => { + deleteTodoMutation({ id }); + }; + {{else}} + {{#if (eq api "orpc")}} const todos = useQuery(orpc.todo.getAll.queryOptions()); const createMutation = useMutation( orpc.todo.create.mutationOptions({ @@ -45,8 +73,8 @@ export default function TodosPage() { onSuccess: () => todos.refetch(), }), ); - {{/if}} - {{#if (eq api "trpc")}} + {{/if}} + {{#if (eq api "trpc")}} const todos = useQuery(trpc.todo.getAll.queryOptions()); const createMutation = useMutation( trpc.todo.create.mutationOptions({ @@ -66,7 +94,7 @@ export default function TodosPage() { onSuccess: () => todos.refetch(), }), ); - {{/if}} + {{/if}} const handleAddTodo = (e: React.FormEvent) => { e.preventDefault(); @@ -82,6 +110,7 @@ export default function TodosPage() { const handleDeleteTodo = (id: number) => { deleteMutation.mutate({ id }); }; + {{/if}} return (
@@ -99,20 +128,73 @@ export default function TodosPage() { value={newTodoText} onChange={(e) => setNewTodoText(e.target.value)} placeholder="Add a new task..." + {{#if (eq backend "convex")}} + {{else}} disabled={createMutation.isPending} + {{/if}} /> + {{#if (eq backend "convex")}} + {todos === undefined ? ( +
+ +
+ ) : todos.length === 0 ? ( +

No todos yet. Add one above!

+ ) : ( +
    + {todos.map((todo) => ( +
  • +
    + + handleToggleTodo(todo._id, todo.completed) + } + id={`todo-${todo._id}`} + /> + +
    + +
  • + ))} +
+ )} + {{else}} {todos.isLoading ? (
@@ -155,6 +237,7 @@ export default function TodosPage() { ))} )} + {{/if}}
diff --git a/apps/cli/templates/examples/todo/web/react/react-router/src/routes/todos.tsx.hbs b/apps/cli/templates/examples/todo/web/react/react-router/src/routes/todos.tsx.hbs index 069b93f..cb0abab 100644 --- a/apps/cli/templates/examples/todo/web/react/react-router/src/routes/todos.tsx.hbs +++ b/apps/cli/templates/examples/todo/web/react/react-router/src/routes/todos.tsx.hbs @@ -126,7 +126,6 @@ export default function Todos() { onChange={(e) => setNewTodoText(e.target.value)} placeholder="Add a new task..." {{#if (eq backend "convex")}} - {{!-- Convex mutations don't have an easy isPending state here, disable based on text --}} {{else}} disabled={createMutation.isPending} {{/if}} diff --git a/apps/cli/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs b/apps/cli/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs index d014e22..bf4952d 100644 --- a/apps/cli/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs +++ b/apps/cli/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs @@ -33,40 +33,48 @@ export default function Home() { API Status + {{#if (eq backend "convex")}} - {{#if (eq api "orpc")}} - {healthCheck.isLoading - ? "Checking..." - : healthCheck.data - ? "Connected" - : "Disconnected"} - {{/if}} - {{#if (eq api "trpc")}} - {healthCheck.isLoading - ? "Checking..." - : healthCheck.data - ? "Connected" - : "Disconnected"} - {{/if}} - {{#if (eq backend "convex")}} {healthCheck === undefined ? "Checking..." : healthCheck === "OK" ? "Connected" : "Error"} - {{/if}} + {{else}} + {{#unless (eq api "none")}} + + + + {{#if (eq api "orpc")}} + {healthCheck.isLoading + ? "Checking..." + : healthCheck.data + ? "Connected" + : "Disconnected"} + {{/if}} + {{#if (eq api "trpc")}} + {healthCheck.isLoading + ? "Checking..." + : healthCheck.data + ? "Connected" + : "Disconnected"} + {{/if}} + + + {{/unless}} + {{/if}} diff --git a/apps/cli/templates/frontend/native/nativewind/app/_layout.tsx.hbs b/apps/cli/templates/frontend/native/nativewind/app/_layout.tsx.hbs index 41b5e2f..ce86f64 100644 --- a/apps/cli/templates/frontend/native/nativewind/app/_layout.tsx.hbs +++ b/apps/cli/templates/frontend/native/nativewind/app/_layout.tsx.hbs @@ -1,7 +1,9 @@ {{#if (eq backend "convex")}} import { ConvexProvider, ConvexReactClient } from "convex/react"; {{else}} +{{#unless (eq api "none")}} import { QueryClientProvider } from "@tanstack/react-query"; +{{/unless}} {{/if}} import { Stack } from "expo-router"; import { @@ -82,6 +84,7 @@ export default function RootLayout() { {{else}} + {{#unless (eq api "none")}} @@ -96,6 +99,20 @@ export default function RootLayout() { + {{else}} + + + + + + + + + + {{/unless}} {{/if}} ); } diff --git a/apps/cli/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs b/apps/cli/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs index 3eca269..999f95a 100644 --- a/apps/cli/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs +++ b/apps/cli/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs @@ -33,38 +33,54 @@ export default function Home() { API Status + {{#if (eq backend "convex")}} - {{#if (or (eq api "orpc") (eq api "trpc"))}} - {healthCheck.isLoading - ? "Checking..." - : healthCheck.data - ? "Connected" - : "Disconnected"} - {{/if}} - {{#if (eq backend "convex")}} {healthCheck === undefined ? "Checking..." : healthCheck === "OK" ? "Connected" : "Error"} - {{/if}} + {{else}} + {{#unless (eq api "none")}} + + + + {{#if (eq api "orpc")}} + {healthCheck.isLoading + ? "Checking..." + : healthCheck.data + ? "Connected" + : "Disconnected"} + {{/if}} + {{#if (eq api "trpc")}} + {healthCheck.isLoading + ? "Checking..." + : healthCheck.data + ? "Connected" + : "Disconnected"} + {{/if}} + + + {{/unless}} + {{/if}} diff --git a/apps/cli/templates/frontend/native/unistyles/app/_layout.tsx.hbs b/apps/cli/templates/frontend/native/unistyles/app/_layout.tsx.hbs index 52d6a0d..11cd4f3 100644 --- a/apps/cli/templates/frontend/native/unistyles/app/_layout.tsx.hbs +++ b/apps/cli/templates/frontend/native/unistyles/app/_layout.tsx.hbs @@ -7,7 +7,9 @@ import { queryClient } from "@/utils/orpc"; {{#if (eq backend "convex")}} import { ConvexProvider, ConvexReactClient } from "convex/react"; {{else}} + {{#unless (eq api "none")}} import { QueryClientProvider } from "@tanstack/react-query"; + {{/unless}} {{/if}} import { Stack } from "expo-router"; import { GestureHandlerRootView } from "react-native-gesture-handler"; @@ -51,6 +53,7 @@ export default function RootLayout() { {{else}} + {{#unless (eq api "none")}} + {{else}} + + + + + + + {{/unless}} {{/if}} ); } diff --git a/apps/cli/templates/frontend/nuxt/app/layouts/default.vue b/apps/cli/templates/frontend/nuxt/app/layouts/default.vue.hbs similarity index 100% rename from apps/cli/templates/frontend/nuxt/app/layouts/default.vue rename to apps/cli/templates/frontend/nuxt/app/layouts/default.vue.hbs diff --git a/apps/cli/templates/frontend/nuxt/app/pages/index.vue b/apps/cli/templates/frontend/nuxt/app/pages/index.vue.hbs similarity index 96% rename from apps/cli/templates/frontend/nuxt/app/pages/index.vue rename to apps/cli/templates/frontend/nuxt/app/pages/index.vue.hbs index 6ca298b..6440660 100644 --- a/apps/cli/templates/frontend/nuxt/app/pages/index.vue +++ b/apps/cli/templates/frontend/nuxt/app/pages/index.vue.hbs @@ -1,6 +1,8 @@ diff --git a/apps/cli/templates/frontend/nuxt/app/plugins/vue-query.ts b/apps/cli/templates/frontend/nuxt/app/plugins/vue-query.ts.hbs similarity index 100% rename from apps/cli/templates/frontend/nuxt/app/plugins/vue-query.ts rename to apps/cli/templates/frontend/nuxt/app/plugins/vue-query.ts.hbs diff --git a/apps/cli/templates/frontend/react/next/src/app/page.tsx.hbs b/apps/cli/templates/frontend/react/next/src/app/page.tsx.hbs index cfe2209..516cc73 100644 --- a/apps/cli/templates/frontend/react/next/src/app/page.tsx.hbs +++ b/apps/cli/templates/frontend/react/next/src/app/page.tsx.hbs @@ -2,14 +2,14 @@ {{#if (eq backend "convex")}} import { useQuery } from "convex/react"; import { api } from "@{{projectName}}/backend/convex/_generated/api.js"; -{{else}} +{{else if (or (eq api "orpc") (eq api "trpc"))}} +import { useQuery } from "@tanstack/react-query"; {{#if (eq api "orpc")}} import { orpc } from "@/utils/orpc"; {{/if}} {{#if (eq api "trpc")}} import { trpc } from "@/utils/trpc"; {{/if}} -import { useQuery } from "@tanstack/react-query"; {{/if}} const TITLE_TEXT = ` @@ -43,8 +43,8 @@ export default function Home() {

API Status

+ {{#if (eq backend "convex")}}
- {{#if (eq backend "convex")}}
@@ -55,19 +55,23 @@ export default function Home() { ? "Connected" : "Error"} - {{else}} -
- - {healthCheck.isLoading - ? "Checking..." - : healthCheck.data - ? "Connected" - : "Disconnected"} - - {{/if}}
+ {{else}} + {{#unless (eq api "none")}} +
+
+ + {healthCheck.isLoading + ? "Checking..." + : healthCheck.data + ? "Connected" + : "Disconnected"} + +
+ {{/unless}} + {{/if}}
diff --git a/apps/cli/templates/frontend/react/next/src/components/providers.tsx.hbs b/apps/cli/templates/frontend/react/next/src/components/providers.tsx.hbs index 0d29e8a..cfa1d4d 100644 --- a/apps/cli/templates/frontend/react/next/src/components/providers.tsx.hbs +++ b/apps/cli/templates/frontend/react/next/src/components/providers.tsx.hbs @@ -1,49 +1,50 @@ "use client" {{#if (eq backend "convex")}} -import { ConvexProvider, ConvexReactClient } from "convex/react"; + import { ConvexProvider, ConvexReactClient } from "convex/react"; {{else}} -import { QueryClientProvider } from "@tanstack/react-query"; - {{#if (eq api "orpc")}} -import { orpc, ORPCContext, queryClient } from "@/utils/orpc"; - {{/if}} - {{#if (eq api "trpc")}} -import { queryClient } from "@/utils/trpc"; - {{/if}} + {{#unless (eq api "none")}} + import { QueryClientProvider } from "@tanstack/react-query"; + {{#if (eq api "orpc")}} + import { orpc, ORPCContext, queryClient } from "@/utils/orpc"; + {{/if}} + {{#if (eq api "trpc")}} + import { queryClient } from "@/utils/trpc"; + {{/if}} + {{/unless}} {{/if}} import { ThemeProvider } from "./theme-provider"; import { Toaster } from "./ui/sonner"; {{#if (eq backend "convex")}} -const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!); + const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!); {{/if}} -export default function Providers({ - children, -}: { - children: React.ReactNode -}) { - return ( - - {{#if (eq backend "convex")}} - {children} - {{else}} +export default function Providers({ children, }: { children: React.ReactNode }) +{ return ( + + {{#if (eq backend "convex")}} + {children} + {{else}} + {{#unless (eq api "none")}} {{#if (eq api "orpc")}} - - {children} - + + {children} + {{/if}} {{#if (eq api "trpc")}} - {children} + {children} {{/if}} - {{/if}} - - - ) -} + {{else}} + {children} + {{/unless}} + {{/if}} + + +) } diff --git a/apps/cli/templates/frontend/react/react-router/src/root.tsx.hbs b/apps/cli/templates/frontend/react/react-router/src/root.tsx.hbs index 3952c7f..54aff33 100644 --- a/apps/cli/templates/frontend/react/react-router/src/root.tsx.hbs +++ b/apps/cli/templates/frontend/react/react-router/src/root.tsx.hbs @@ -13,20 +13,25 @@ import { ThemeProvider } from "./components/theme-provider"; import { Toaster } from "./components/ui/sonner"; {{#if (eq backend "convex")}} -import { ConvexProvider, ConvexReactClient } from "convex/react"; + import { ConvexProvider, ConvexReactClient } from "convex/react"; {{else}} -import { QueryClientProvider } from "@tanstack/react-query"; -import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; - {{#if (eq api "orpc")}} - import { orpc, ORPCContext, queryClient } from "./utils/orpc"; - {{/if}} - {{#if (eq api "trpc")}} - import { queryClient } from "./utils/trpc"; - {{/if}} + {{#unless (eq api "none")}} + import { QueryClientProvider } from "@tanstack/react-query"; + import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; + {{#if (eq api "orpc")}} + import { orpc, ORPCContext, queryClient } from "./utils/orpc"; + {{/if}} + {{#if (eq api "trpc")}} + import { queryClient } from "./utils/trpc"; + {{/if}} + {{/unless}} {{/if}} export const links: Route.LinksFunction = () => [ - { rel: "preconnect", href: "https://fonts.googleapis.com" }, + { + rel: "preconnect", + href: "https://fonts.googleapis.com", + }, { rel: "preconnect", href: "https://fonts.gstatic.com", @@ -57,28 +62,12 @@ export function Layout({ children }: { children: React.ReactNode }) { } {{#if (eq backend "convex")}} -export default function App() { - const convex = new ConvexReactClient( - import.meta.env.VITE_CONVEX_URL as string, - ); - - return ( - - -
-
- -
- -
-
- ); -} -{{else if (eq api "orpc")}} -export default function App() { - return ( - - + export default function App() { + const convex = new ConvexReactClient( + import.meta.env.VITE_CONVEX_URL as string, + ); + return ( +
@@ -86,15 +75,44 @@ export default function App() {
-
- -
- ); -} + + ); + } +{{else if (eq api "orpc")}} + export default function App() { + return ( + + + +
+
+ +
+ +
+
+ +
+ ); + } {{else if (eq api "trpc")}} -export default function App() { - return ( - + export default function App() { + return ( + + +
+
+ +
+ +
+ +
+ ); + } +{{else}} + export default function App() { + return (
@@ -102,10 +120,8 @@ export default function App() {
- -
- ); -} + ); + } {{/if}} export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { diff --git a/apps/cli/templates/frontend/react/react-router/src/routes/_index.tsx.hbs b/apps/cli/templates/frontend/react/react-router/src/routes/_index.tsx.hbs index 1a925e9..34eb9ab 100644 --- a/apps/cli/templates/frontend/react/react-router/src/routes/_index.tsx.hbs +++ b/apps/cli/templates/frontend/react/react-router/src/routes/_index.tsx.hbs @@ -2,14 +2,14 @@ import type { Route } from "./+types/_index"; {{#if (eq backend "convex")}} import { useQuery } from "convex/react"; import { api } from "@{{projectName}}/backend/convex/_generated/api.js"; -{{else}} +{{else if (or (eq api "orpc") (eq api "trpc"))}} +import { useQuery } from "@tanstack/react-query"; {{#if (eq api "orpc")}} import { orpc } from "@/utils/orpc"; {{/if}} {{#if (eq api "trpc")}} import { trpc } from "@/utils/trpc"; {{/if}} -import { useQuery } from "@tanstack/react-query"; {{/if}} const TITLE_TEXT = ` @@ -47,8 +47,8 @@ export default function Home() {

API Status

+ {{#if (eq backend "convex")}}
- {{#if (eq backend "convex")}}
@@ -59,21 +59,25 @@ export default function Home() { ? "Connected" : "Error"} - {{else}} -
- - {healthCheck.isLoading - ? "Checking..." - : healthCheck.data - ? "Connected" - : "Disconnected"} - - {{/if}}
+ {{else}} + {{#unless (eq api "none")}} +
+
+ + {healthCheck.isLoading + ? "Checking..." + : healthCheck.data + ? "Connected" + : "Disconnected"} + +
+ {{/unless}} + {{/if}}
diff --git a/apps/cli/templates/frontend/react/tanstack-router/src/main.tsx.hbs b/apps/cli/templates/frontend/react/tanstack-router/src/main.tsx.hbs index 89ec7d5..2596dae 100644 --- a/apps/cli/templates/frontend/react/tanstack-router/src/main.tsx.hbs +++ b/apps/cli/templates/frontend/react/tanstack-router/src/main.tsx.hbs @@ -2,57 +2,51 @@ import { RouterProvider, createRouter } from "@tanstack/react-router"; import ReactDOM from "react-dom/client"; import Loader from "./components/loader"; import { routeTree } from "./routeTree.gen"; + {{#if (eq api "orpc")}} -import { QueryClientProvider } from "@tanstack/react-query"; -import { orpc, queryClient } from "./utils/orpc"; + import { QueryClientProvider } from "@tanstack/react-query"; + import { orpc, queryClient } from "./utils/orpc"; {{/if}} {{#if (eq api "trpc")}} -import { QueryClientProvider } from "@tanstack/react-query"; -import { queryClient, trpc } from "./utils/trpc"; + import { QueryClientProvider } from "@tanstack/react-query"; + import { queryClient, trpc } from "./utils/trpc"; {{/if}} {{#if (eq backend "convex")}} -import { ConvexProvider, ConvexReactClient } from "convex/react"; - -const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string); + import { ConvexProvider, ConvexReactClient } from "convex/react"; + const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string); {{/if}} -{{#if (eq api "orpc")}} const router = createRouter({ routeTree, defaultPreload: "intent", defaultPendingComponent: () => , + {{#if (eq api "orpc")}} context: { orpc, queryClient }, - Wrap: function WrapComponent({ children }) { + Wrap: function WrapComponent({ children }: { children: React.ReactNode }) { return ( - {children} + + {children} + ); }, -}); -{{/if}} -{{#if (eq api "trpc")}} -const router = createRouter({ - routeTree, - defaultPreload: "intent", - defaultPendingComponent: () => , + {{else if (eq api "trpc")}} context: { trpc, queryClient }, - Wrap: function WrapComponent({ children }) { + Wrap: function WrapComponent({ children }: { children: React.ReactNode }) { return ( - {children} + + {children} + ); }, -}); -{{/if}} -{{#if (eq backend "convex")}} -const router = createRouter({ - routeTree, - defaultPreload: "intent", - defaultPendingComponent: () => , + {{else if (eq backend "convex")}} context: {}, - Wrap: function WrapComponent({ children }) { + Wrap: function WrapComponent({ children }: { children: React.ReactNode }) { return {children}; }, + {{else}} + context: {}, + {{/if}} }); -{{/if}} declare module "@tanstack/react-router" { interface Register { @@ -61,7 +55,10 @@ declare module "@tanstack/react-router" { } const rootElement = document.getElementById("app"); -if (!rootElement) throw new Error("Root element not found"); + +if (!rootElement) { + throw new Error("Root element not found"); +} if (!rootElement.innerHTML) { const root = ReactDOM.createRoot(rootElement); diff --git a/apps/cli/templates/frontend/react/tanstack-router/src/routes/__root.tsx.hbs b/apps/cli/templates/frontend/react/tanstack-router/src/routes/__root.tsx.hbs index ea73819..0e21908 100644 --- a/apps/cli/templates/frontend/react/tanstack-router/src/routes/__root.tsx.hbs +++ b/apps/cli/templates/frontend/react/tanstack-router/src/routes/__root.tsx.hbs @@ -31,14 +31,12 @@ export interface RouterAppContext { orpc: typeof orpc; queryClient: QueryClient; } -{{/if}} -{{#if (eq api "trpc")}} +{{else if (eq api "trpc")}} export interface RouterAppContext { trpc: typeof trpc; queryClient: QueryClient; } -{{/if}} -{{#if (eq backend "convex")}} +{{else}} export interface RouterAppContext {} {{/if}} @@ -63,18 +61,21 @@ export const Route = createRootRouteWithContext()({ }), }); -{{#if (eq api "orpc")}} function RootComponent() { - const [client] = useState>(() => createORPCClient(link)) - const [orpc] = useState(() => createORPCReactQueryUtils(client)) - const isFetching = useRouterState({ select: (s) => s.isLoading, }); + + {{#if (eq api "orpc")}} + const [client] = useState>(() => createORPCClient(link)); + const [orpcUtils] = useState(() => createORPCReactQueryUtils(client)); + {{/if}} + return ( <> - + {{#if (eq api "orpc")}} +
@@ -83,20 +84,7 @@ function RootComponent() { - - - - ); -} -{{/if}} -{{#if (eq api "trpc")}} -function RootComponent() { - const isFetching = useRouterState({ - select: (s) => s.isLoading, - }); - return ( - <> - + {{else}}
@@ -104,29 +92,11 @@ function RootComponent() {
+ {{/if}} + {{#if (or (eq api "orpc") (eq api "trpc"))}} + {{/if}} ); } -{{/if}} -{{#if (eq backend "convex")}} -function RootComponent() { - const isFetching = useRouterState({ - select: (s) => s.isLoading, - }); - return ( - <> - - -
-
- {isFetching ? : } -
- -
- - - ); -} -{{/if}} diff --git a/apps/cli/templates/frontend/react/tanstack-router/src/routes/index.tsx.hbs b/apps/cli/templates/frontend/react/tanstack-router/src/routes/index.tsx.hbs index 2c0ff66..0791031 100644 --- a/apps/cli/templates/frontend/react/tanstack-router/src/routes/index.tsx.hbs +++ b/apps/cli/templates/frontend/react/tanstack-router/src/routes/index.tsx.hbs @@ -49,20 +49,8 @@ function HomeComponent() {

API Status

+ {{#if (eq backend "convex")}}
- {{#if (or (eq api "orpc") (eq api "trpc"))}} -
- - {healthCheck.isLoading - ? "Checking..." - : healthCheck.data - ? "Connected" - : "Disconnected"} - - {{/if}} - {{#if (eq backend "convex")}}
@@ -73,8 +61,23 @@ function HomeComponent() { ? "Connected" : "Error"} - {{/if}}
+ {{else}} + {{#unless (eq api "none")}} +
+
+ + {healthCheck.isLoading + ? "Checking..." + : healthCheck.data + ? "Connected" + : "Disconnected"} + +
+ {{/unless}} + {{/if}}
diff --git a/apps/cli/templates/frontend/react/tanstack-start/src/router.tsx.hbs b/apps/cli/templates/frontend/react/tanstack-start/src/router.tsx.hbs index 3a25518..839ba06 100644 --- a/apps/cli/templates/frontend/react/tanstack-start/src/router.tsx.hbs +++ b/apps/cli/templates/frontend/react/tanstack-start/src/router.tsx.hbs @@ -8,24 +8,20 @@ import { routeTree } from "./routeTree.gen"; import Loader from "./components/loader"; import "./index.css"; {{else}} -import { - QueryCache, - QueryClient, - QueryClientProvider, -} from "@tanstack/react-query"; import { createRouter as createTanstackRouter } from "@tanstack/react-router"; import Loader from "./components/loader"; import "./index.css"; import { routeTree } from "./routeTree.gen"; {{#if (eq api "trpc")}} +import { QueryCache, QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { createTRPCClient, httpBatchLink } from "@trpc/client"; import { createTRPCOptionsProxy } from "@trpc/tanstack-react-query"; import { toast } from "sonner"; import type { AppRouter } from "../../server/src/routers"; import { TRPCProvider } from "./utils/trpc"; - {{/if}} - {{#if (eq api "orpc")}} -import { orpc, ORPCContext, queryClient } from "./utils/orpc"; + {{else if (eq api "orpc")}} +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { orpc, ORPCContext, queryClient as orpcQueryClient } from "./utils/orpc"; {{/if}} {{/if}} @@ -62,7 +58,6 @@ export function createRouter() { }), queryClient, ); - return router; } {{else}} @@ -103,6 +98,8 @@ const trpc = createTRPCOptionsProxy({ client: trpcClient, queryClient: queryClient, }); + {{else if (eq api "orpc")}} + const queryClient = orpcQueryClient; {{/if}} export const createRouter = () => { @@ -112,33 +109,37 @@ export const createRouter = () => { defaultPreloadStaleTime: 0, {{#if (eq api "trpc")}} context: { trpc, queryClient }, - {{/if}} - {{#if (eq api "orpc")}} + {{else if (eq api "orpc")}} context: { orpc, queryClient }, + {{else}} + context: { }, {{/if}} defaultPendingComponent: () => , defaultNotFoundComponent: () =>
Not Found
, + {{#if (eq api "trpc")}} Wrap: ({ children }) => ( - {{#if (eq api "trpc")}} {children} - {{/if}} - {{#if (eq api "orpc")}} + + ), + {{else if (eq api "orpc")}} + Wrap: ({ children }) => ( + {children} - {{/if}} ), + {{else}} + Wrap: ({ children }) => <>{children}, + {{/if}} }); - return router; }; {{/if}} -// Register the router instance for type safety declare module "@tanstack/react-router" { interface Register { router: ReturnType; diff --git a/apps/cli/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs b/apps/cli/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs index 4c7b748..89240ea 100644 --- a/apps/cli/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +++ b/apps/cli/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs @@ -1,5 +1,7 @@ import { Toaster } from "@/components/ui/sonner"; +{{#unless (eq backend "convex")}} {{#unless (eq api "none")}} import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; +{{/unless}} {{/unless}} import { HeadContent, Outlet, @@ -10,7 +12,9 @@ import { import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; import Header from "../components/header"; import appCss from "../index.css?url"; +{{#unless (and (eq api "none") (not (eq backend "convex"))}} import type { QueryClient } from "@tanstack/react-query"; +{{/unless}} import Loader from "@/components/loader"; {{#if (eq backend "convex")}} @@ -25,12 +29,14 @@ export interface RouterAppContext { trpc: TRPCOptionsProxy; queryClient: QueryClient; } - {{/if}} - {{#if (eq api "orpc")}} + {{else if (eq api "orpc")}} import type { orpc } from "@/utils/orpc"; export interface RouterAppContext { orpc: typeof orpc; queryClient: QueryClient; +} + {{else}} +export interface RouterAppContext { } {{/if}} {{/if}} @@ -75,7 +81,11 @@ function RootDocument() { + {{#unless (eq backend "convex")}} + {{#unless (eq api "none")}} + {{/unless}} + {{/unless}} diff --git a/apps/cli/templates/frontend/react/tanstack-start/src/routes/index.tsx.hbs b/apps/cli/templates/frontend/react/tanstack-start/src/routes/index.tsx.hbs index 5ace888..675f855 100644 --- a/apps/cli/templates/frontend/react/tanstack-start/src/routes/index.tsx.hbs +++ b/apps/cli/templates/frontend/react/tanstack-start/src/routes/index.tsx.hbs @@ -3,14 +3,14 @@ import { createFileRoute } from "@tanstack/react-router"; import { convexQuery } from "@convex-dev/react-query"; import { useSuspenseQuery } from "@tanstack/react-query"; import { api } from "@{{projectName}}/backend/convex/_generated/api.js"; -{{else}} +{{else if (or (eq api "trpc") (eq api "orpc"))}} +import { useQuery } from "@tanstack/react-query"; {{#if (eq api "trpc")}} import { useTRPC } from "@/utils/trpc"; {{/if}} {{#if (eq api "orpc")}} import { useORPC } from "@/utils/orpc"; {{/if}} -import { useQuery } from "@tanstack/react-query"; {{/if}} export const Route = createFileRoute("/")({ @@ -36,15 +36,12 @@ const TITLE_TEXT = ` function HomeComponent() { {{#if (eq backend "convex")}} const healthCheck = useSuspenseQuery(convexQuery(api.healthCheck.get, {})); - {{else}} - {{#if (eq api "trpc")}} + {{else if (eq api "trpc")}} const trpc = useTRPC(); const healthCheck = useQuery(trpc.healthCheck.queryOptions()); - {{/if}} - {{#if (eq api "orpc")}} + {{else if (eq api "orpc")}} const orpc = useORPC(); const healthCheck = useQuery(orpc.healthCheck.queryOptions()); - {{/if}} {{/if}} return ( @@ -53,8 +50,8 @@ function HomeComponent() {

API Status

+ {{#if (eq backend "convex")}}
- {{#if (eq backend "convex")}}
@@ -65,19 +62,23 @@ function HomeComponent() { ? "Connected" : "Error"} - {{else}} -
- - {healthCheck.isLoading - ? "Checking..." - : healthCheck.data - ? "Connected" - : "Disconnected"} - - {{/if}}
+ {{else}} + {{#unless (eq api "none")}} +
+
+ + {healthCheck.isLoading + ? "Checking..." + : healthCheck.data + ? "Connected" + : "Disconnected"} + +
+ {{/unless}} + {{/if}}
diff --git a/apps/cli/templates/frontend/solid/src/main.tsx.hbs b/apps/cli/templates/frontend/solid/src/main.tsx.hbs index 39daf83..cfed685 100644 --- a/apps/cli/templates/frontend/solid/src/main.tsx.hbs +++ b/apps/cli/templates/frontend/solid/src/main.tsx.hbs @@ -2,8 +2,10 @@ import { RouterProvider, createRouter } from "@tanstack/solid-router"; import { render } from "solid-js/web"; import { routeTree } from "./routeTree.gen"; import "./styles.css"; +{{#if (eq api "orpc")}} import { QueryClientProvider } from "@tanstack/solid-query"; import { queryClient } from "./utils/orpc"; +{{/if}} const router = createRouter({ routeTree, @@ -20,9 +22,13 @@ declare module "@tanstack/solid-router" { function App() { return ( + {{#if (eq api "orpc")}} + {{/if}} + {{#if (eq api "orpc")}} + {{/if}} ); } diff --git a/apps/cli/templates/frontend/solid/src/routes/__root.tsx.hbs b/apps/cli/templates/frontend/solid/src/routes/__root.tsx.hbs index 8e6a35d..d021683 100644 --- a/apps/cli/templates/frontend/solid/src/routes/__root.tsx.hbs +++ b/apps/cli/templates/frontend/solid/src/routes/__root.tsx.hbs @@ -1,9 +1,20 @@ import Header from "@/components/header"; import { Outlet, createRootRouteWithContext } from "@tanstack/solid-router"; import { TanStackRouterDevtools } from "@tanstack/solid-router-devtools"; +{{#if (eq api "orpc")}} import { SolidQueryDevtools } from "@tanstack/solid-query-devtools"; +import type { QueryClient } from "@tanstack/solid-query"; +import type { orpc } from "../utils/orpc"; -export const Route = createRootRouteWithContext()({ +export interface RouterContext { + orpc: typeof orpc; + queryClient: QueryClient; +} +{{else}} +export interface RouterContext {} +{{/if}} + +export const Route = createRootRouteWithContext()({ component: RootComponent, }); @@ -14,7 +25,9 @@ function RootComponent() {
+ {{#if (eq api "orpc")}} + {{/if}} ); diff --git a/apps/cli/templates/frontend/solid/src/routes/index.tsx.hbs b/apps/cli/templates/frontend/solid/src/routes/index.tsx.hbs index 2f97106..38d0096 100644 --- a/apps/cli/templates/frontend/solid/src/routes/index.tsx.hbs +++ b/apps/cli/templates/frontend/solid/src/routes/index.tsx.hbs @@ -1,7 +1,10 @@ import { createFileRoute } from "@tanstack/solid-router"; +{{#if (eq api "orpc")}} import { useQuery } from "@tanstack/solid-query"; import { orpc } from "../utils/orpc"; import { Match, Switch } from "solid-js"; +{{else}} +{{/if}} export const Route = createFileRoute("/")({ component: App, @@ -24,12 +27,15 @@ const TITLE_TEXT = ` `; function App() { + {{#if (eq api "orpc")}} const healthCheck = useQuery(() => orpc.healthCheck.queryOptions()); + {{/if}} return (
{TITLE_TEXT}
+ {{#if (eq api "orpc")}}

API Status

@@ -53,12 +59,13 @@ function App() { {healthCheck.data ? "Connected" - : "Disconnected (Success but no data)"} + : "Disconnected"}
+ {{/if}}
); diff --git a/apps/cli/templates/frontend/svelte/src/routes/+layout.svelte.hbs b/apps/cli/templates/frontend/svelte/src/routes/+layout.svelte.hbs index b8e895d..0a93842 100644 --- a/apps/cli/templates/frontend/svelte/src/routes/+layout.svelte.hbs +++ b/apps/cli/templates/frontend/svelte/src/routes/+layout.svelte.hbs @@ -16,16 +16,12 @@ {{else}} + {{#if (eq api "orpc")}} + +
+
+
+ {@render children()} +
+
+ {{/if}} {{/if}} diff --git a/apps/cli/templates/frontend/svelte/src/routes/+page.svelte.hbs b/apps/cli/templates/frontend/svelte/src/routes/+page.svelte.hbs index 6881de0..b7c10dc 100644 --- a/apps/cli/templates/frontend/svelte/src/routes/+page.svelte.hbs +++ b/apps/cli/templates/frontend/svelte/src/routes/+page.svelte.hbs @@ -3,10 +3,8 @@ import { useQuery } from 'convex-svelte'; import { api } from "@{{projectName}}/backend/convex/_generated/api.js"; - const healthCheck = useQuery(api.healthCheck.get, {}); - const TITLE_TEXT = ` ██████╗ ███████╗████████╗████████╗███████╗██████╗ ██╔══██╗██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗ @@ -28,7 +26,7 @@ const TITLE_TEXT = `
{TITLE_TEXT}
-

API Status (Convex)

+

API Status

{{#if (eq api "orpc")}} import { orpc } from "$lib/orpc"; -{{/if}} -{{#if (eq api "trpc")}} -import { trpc } from "$lib/trpc"; -{{/if}} import { createQuery } from "@tanstack/svelte-query"; - -{{#if (eq api "orpc")}} const healthCheck = createQuery(orpc.healthCheck.queryOptions()); {{/if}} -{{#if (eq api "trpc")}} -const healthCheck = createQuery(trpc.healthCheck.queryOptions()); -{{/if}} - const TITLE_TEXT = ` ██████╗ ███████╗████████╗████████╗███████╗██████╗ @@ -82,8 +70,9 @@ const TITLE_TEXT = `
{TITLE_TEXT}
+ {{#if (eq api "orpc")}}
-

API Status{{#if (eq api "trpc")}} (tRPC){{/if}}{{#if (eq api "orpc")}} (oRPC){{/if}}

+

API Status

+ {{/if}}
{{/if}} diff --git a/bun.lock b/bun.lock index 1054c6e..16f1e8b 100644 --- a/bun.lock +++ b/bun.lock @@ -14,7 +14,7 @@ }, "apps/cli": { "name": "create-better-t-stack", - "version": "2.9.0", + "version": "2.9.2", "bin": { "create-better-t-stack": "dist/index.js", }, @@ -43,9 +43,9 @@ "version": "0.0.0", "dependencies": { "@radix-ui/react-dialog": "^1.1.13", - "@radix-ui/react-scroll-area": "^1.2.6", - "@radix-ui/react-switch": "^1.2.2", - "@radix-ui/react-tooltip": "^1.2.4", + "@radix-ui/react-scroll-area": "^1.2.8", + "@radix-ui/react-switch": "^1.2.4", + "@radix-ui/react-tooltip": "^1.2.6", "babel-plugin-react-compiler": "^19.1.0-rc.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -53,7 +53,7 @@ "fumadocs-mdx": "11.6.1", "fumadocs-ui": "15.2.10", "lucide-react": "^0.503.0", - "motion": "^12.8.0", + "motion": "^12.10.5", "next": "15.3.1", "next-themes": "^0.4.6", "nuqs": "^2.4.3", @@ -64,16 +64,16 @@ "tailwind-merge": "^3.2.0", }, "devDependencies": { - "@tailwindcss/postcss": "^4.1.4", + "@tailwindcss/postcss": "^4.1.5", "@types/mdx": "^2.0.13", "@types/node": "22.14.1", - "@types/react": "^19.1.2", - "@types/react-dom": "^19.1.2", - "eslint": "^9.25.1", + "@types/react": "^19.1.3", + "@types/react-dom": "^19.1.3", + "eslint": "^9.26.0", "eslint-config-next": "15.3.1", "postcss": "^8.5.3", - "tailwindcss": "^4.1.4", - "tw-animate-css": "^1.2.8", + "tailwindcss": "^4.1.5", + "tw-animate-css": "^1.2.9", "typescript": "^5.8.3", }, },