cli: organize file structure

This commit is contained in:
Aman Varshney
2025-05-26 00:13:08 +05:30
parent b9c9690e61
commit 1e9c6b2210
40 changed files with 900 additions and 928 deletions

View File

@@ -0,0 +1,138 @@
import path from "node:path";
import fs from "fs-extra";
import type { Frontend } from "../../types";
import { addPackageDependency } from "../../utils/add-package-deps";
import { setupStarlight } from "./starlight-setup";
import { setupTauri } from "./tauri-setup";
import type { ProjectConfig } from "../../types";
export async function setupAddons(config: ProjectConfig) {
const { addons, frontend, projectDir } = config;
const hasReactWebFrontend =
frontend.includes("react-router") ||
frontend.includes("tanstack-router") ||
frontend.includes("next");
const hasNuxtFrontend = frontend.includes("nuxt");
const hasSvelteFrontend = frontend.includes("svelte");
const hasSolidFrontend = frontend.includes("solid");
const hasNextFrontend = frontend.includes("next");
if (addons.includes("turborepo")) {
await addPackageDependency({
devDependencies: ["turbo"],
projectDir,
});
}
if (addons.includes("pwa") && (hasReactWebFrontend || hasSolidFrontend)) {
await setupPwa(projectDir, frontend);
}
if (
addons.includes("tauri") &&
(hasReactWebFrontend ||
hasNuxtFrontend ||
hasSvelteFrontend ||
hasSolidFrontend ||
hasNextFrontend)
) {
await setupTauri(config);
}
if (addons.includes("biome")) {
await setupBiome(projectDir);
}
if (addons.includes("husky")) {
await setupHusky(projectDir);
}
if (addons.includes("starlight")) {
await setupStarlight(config);
}
}
function getWebAppDir(projectDir: string, frontends: Frontend[]): string {
if (
frontends.some((f) =>
["react-router", "tanstack-router", "nuxt", "svelte", "solid"].includes(
f,
),
)
) {
return path.join(projectDir, "apps/web");
}
return path.join(projectDir, "apps/web");
}
async function setupBiome(projectDir: string) {
await addPackageDependency({
devDependencies: ["@biomejs/biome"],
projectDir,
});
const packageJsonPath = path.join(projectDir, "package.json");
if (await fs.pathExists(packageJsonPath)) {
const packageJson = await fs.readJson(packageJsonPath);
packageJson.scripts = {
...packageJson.scripts,
check: "biome check --write .",
};
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
}
}
async function setupHusky(projectDir: string) {
await addPackageDependency({
devDependencies: ["husky", "lint-staged"],
projectDir,
});
const packageJsonPath = path.join(projectDir, "package.json");
if (await fs.pathExists(packageJsonPath)) {
const packageJson = await fs.readJson(packageJsonPath);
packageJson.scripts = {
...packageJson.scripts,
prepare: "husky",
};
packageJson["lint-staged"] = {
"*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}": [
"biome check --write .",
],
};
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
}
}
async function setupPwa(projectDir: string, frontends: Frontend[]) {
const isCompatibleFrontend = frontends.some((f) =>
["react-router", "tanstack-router", "solid"].includes(f),
);
if (!isCompatibleFrontend) return;
const clientPackageDir = getWebAppDir(projectDir, frontends);
if (!(await fs.pathExists(clientPackageDir))) {
return;
}
await addPackageDependency({
dependencies: ["vite-plugin-pwa"],
devDependencies: ["@vite-pwa/assets-generator"],
projectDir: clientPackageDir,
});
const clientPackageJsonPath = path.join(clientPackageDir, "package.json");
if (await fs.pathExists(clientPackageJsonPath)) {
const packageJson = await fs.readJson(clientPackageJsonPath);
packageJson.scripts = {
...packageJson.scripts,
"generate-pwa-assets": "pwa-assets-generator",
};
await fs.writeJson(clientPackageJsonPath, packageJson, { spaces: 2 });
}
}

View File

@@ -0,0 +1,278 @@
import path from "node:path";
import fs from "fs-extra";
import type { AvailableDependencies } from "../../constants";
import type { Frontend, ProjectConfig } from "../../types";
import { addPackageDependency } from "../../utils/add-package-deps";
export async function setupApi(config: ProjectConfig): Promise<void> {
const { api, projectName, frontend, backend, packageManager, projectDir } =
config;
const isConvex = backend === "convex";
const webDir = path.join(projectDir, "apps/web");
const nativeDir = path.join(projectDir, "apps/native");
const webDirExists = await fs.pathExists(webDir);
const nativeDirExists = await fs.pathExists(nativeDir);
const hasReactWeb = frontend.some((f) =>
["tanstack-router", "react-router", "tanstack-start", "next"].includes(f),
);
const hasNuxtWeb = frontend.includes("nuxt");
const hasSvelteWeb = frontend.includes("svelte");
const hasSolidWeb = frontend.includes("solid");
if (!isConvex && api !== "none") {
const serverDir = path.join(projectDir, "apps/server");
const serverDirExists = await fs.pathExists(serverDir);
if (serverDirExists) {
if (api === "orpc") {
await addPackageDependency({
dependencies: ["@orpc/server", "@orpc/client"],
projectDir: serverDir,
});
} else if (api === "trpc") {
await addPackageDependency({
dependencies: ["@trpc/server", "@trpc/client"],
projectDir: serverDir,
});
if (config.backend === "hono") {
await addPackageDependency({
dependencies: ["@hono/trpc-server"],
projectDir: serverDir,
});
} else if (config.backend === "elysia") {
await addPackageDependency({
dependencies: ["@elysiajs/trpc"],
projectDir: serverDir,
});
}
}
} else {
}
if (webDirExists) {
if (hasReactWeb) {
if (api === "orpc") {
await addPackageDependency({
dependencies: ["@orpc/react-query", "@orpc/client", "@orpc/server"],
projectDir: webDir,
});
} else if (api === "trpc") {
await addPackageDependency({
dependencies: [
"@trpc/tanstack-react-query",
"@trpc/client",
"@trpc/server",
],
projectDir: webDir,
});
}
} else if (hasNuxtWeb) {
if (api === "orpc") {
await addPackageDependency({
dependencies: ["@orpc/vue-query", "@orpc/client", "@orpc/server"],
projectDir: webDir,
});
}
} else if (hasSvelteWeb) {
if (api === "orpc") {
await addPackageDependency({
dependencies: [
"@orpc/svelte-query",
"@orpc/client",
"@orpc/server",
"@tanstack/svelte-query",
],
projectDir: webDir,
});
}
} else if (hasSolidWeb) {
if (api === "orpc") {
await addPackageDependency({
dependencies: [
"@orpc/solid-query",
"@orpc/client",
"@orpc/server",
"@tanstack/solid-query",
],
projectDir: webDir,
});
}
}
}
if (nativeDirExists) {
if (api === "trpc") {
await addPackageDependency({
dependencies: [
"@trpc/tanstack-react-query",
"@trpc/client",
"@trpc/server",
],
projectDir: nativeDir,
});
} else if (api === "orpc") {
await addPackageDependency({
dependencies: ["@orpc/react-query", "@orpc/client", "@orpc/server"],
projectDir: nativeDir,
});
}
}
}
const reactBasedFrontends: Frontend[] = [
"react-router",
"tanstack-router",
"tanstack-start",
"next",
"native-nativewind",
"native-unistyles",
];
const needsSolidQuery = frontend.includes("solid");
const needsReactQuery = frontend.some((f) => reactBasedFrontends.includes(f));
if (needsReactQuery && !isConvex) {
const reactQueryDeps: AvailableDependencies[] = ["@tanstack/react-query"];
const reactQueryDevDeps: AvailableDependencies[] = [
"@tanstack/react-query-devtools",
];
const hasReactWeb = frontend.some(
(f) =>
f !== "native-nativewind" &&
f !== "native-unistyles" &&
reactBasedFrontends.includes(f),
);
const hasNative =
frontend.includes("native-nativewind") ||
frontend.includes("native-unistyles");
if (hasReactWeb && webDirExists) {
const webPkgJsonPath = path.join(webDir, "package.json");
if (await fs.pathExists(webPkgJsonPath)) {
try {
await addPackageDependency({
dependencies: reactQueryDeps,
devDependencies: reactQueryDevDeps,
projectDir: webDir,
});
} catch (_error) {}
} else {
}
}
if (hasNative && nativeDirExists) {
const nativePkgJsonPath = path.join(nativeDir, "package.json");
if (await fs.pathExists(nativePkgJsonPath)) {
try {
await addPackageDependency({
dependencies: reactQueryDeps,
projectDir: nativeDir,
});
} catch (_error) {}
} else {
}
}
}
if (needsSolidQuery && !isConvex) {
const solidQueryDeps: AvailableDependencies[] = ["@tanstack/solid-query"];
const solidQueryDevDeps: AvailableDependencies[] = [
"@tanstack/solid-query-devtools",
];
if (webDirExists) {
const webPkgJsonPath = path.join(webDir, "package.json");
if (await fs.pathExists(webPkgJsonPath)) {
try {
await addPackageDependency({
dependencies: solidQueryDeps,
devDependencies: solidQueryDevDeps,
projectDir: webDir,
});
} catch (_error) {}
}
}
}
if (isConvex) {
if (webDirExists) {
const webPkgJsonPath = path.join(webDir, "package.json");
if (await fs.pathExists(webPkgJsonPath)) {
try {
const webDepsToAdd: AvailableDependencies[] = ["convex"];
if (frontend.includes("tanstack-start")) {
webDepsToAdd.push("@convex-dev/react-query");
}
if (hasSvelteWeb) {
webDepsToAdd.push("convex-svelte");
}
await addPackageDependency({
dependencies: webDepsToAdd,
projectDir: webDir,
});
} catch (_error) {}
} else {
}
}
if (nativeDirExists) {
const nativePkgJsonPath = path.join(nativeDir, "package.json");
if (await fs.pathExists(nativePkgJsonPath)) {
try {
await addPackageDependency({
dependencies: ["convex"],
projectDir: nativeDir,
});
} catch (_error) {}
} else {
}
}
const backendPackageName = `@${projectName}/backend`;
const backendWorkspaceVersion =
packageManager === "npm" ? "*" : "workspace:*";
const addWorkspaceDepManually = async (
pkgJsonPath: string,
depName: string,
depVersion: string,
) => {
try {
const pkgJson = await fs.readJson(pkgJsonPath);
if (!pkgJson.dependencies) {
pkgJson.dependencies = {};
}
if (pkgJson.dependencies[depName] !== depVersion) {
pkgJson.dependencies[depName] = depVersion;
await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
} else {
}
} catch (_error) {}
};
if (webDirExists) {
const webPkgJsonPath = path.join(webDir, "package.json");
if (await fs.pathExists(webPkgJsonPath)) {
await addWorkspaceDepManually(
webPkgJsonPath,
backendPackageName,
backendWorkspaceVersion,
);
} else {
}
}
if (nativeDirExists) {
const nativePkgJsonPath = path.join(nativeDir, "package.json");
if (await fs.pathExists(nativePkgJsonPath)) {
await addWorkspaceDepManually(
nativePkgJsonPath,
backendPackageName,
backendWorkspaceVersion,
);
} else {
}
}
}
}

View File

@@ -0,0 +1,81 @@
import path from "node:path";
import consola from "consola";
import fs from "fs-extra";
import pc from "picocolors";
import type { ProjectConfig } from "../../types";
import { addPackageDependency } from "../../utils/add-package-deps";
export async function setupAuth(config: ProjectConfig): Promise<void> {
const { auth, frontend, backend, projectDir } = config;
if (backend === "convex" || !auth) {
return;
}
const serverDir = path.join(projectDir, "apps/server");
const clientDir = path.join(projectDir, "apps/web");
const nativeDir = path.join(projectDir, "apps/native");
const clientDirExists = await fs.pathExists(clientDir);
const nativeDirExists = await fs.pathExists(nativeDir);
const serverDirExists = await fs.pathExists(serverDir);
try {
if (serverDirExists) {
await addPackageDependency({
dependencies: ["better-auth"],
projectDir: serverDir,
});
}
const hasWebFrontend = frontend.some((f) =>
[
"react-router",
"tanstack-router",
"tanstack-start",
"next",
"nuxt",
"svelte",
].includes(f),
);
if (hasWebFrontend && clientDirExists) {
await addPackageDependency({
dependencies: ["better-auth"],
projectDir: clientDir,
});
}
if (
(frontend.includes("native-nativewind") ||
frontend.includes("native-unistyles")) &&
nativeDirExists
) {
await addPackageDependency({
dependencies: ["better-auth", "@better-auth/expo"],
projectDir: nativeDir,
});
if (serverDirExists) {
await addPackageDependency({
dependencies: ["@better-auth/expo"],
projectDir: serverDir,
});
}
}
} catch (error) {
consola.error(pc.red("Failed to configure authentication dependencies"));
if (error instanceof Error) {
consola.error(pc.red(error.message));
}
}
}
export function generateAuthSecret(length = 32): string {
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
const charactersLength = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}

View File

@@ -0,0 +1,67 @@
import path from "node:path";
import type { AvailableDependencies } from "../../constants";
import { addPackageDependency } from "../../utils/add-package-deps";
import type { ProjectConfig } from "../../types";
export async function setupBackendDependencies(
config: ProjectConfig,
): Promise<void> {
const { backend, runtime, api, projectDir } = config;
if (backend === "convex") {
return;
}
const framework = backend;
const serverDir = path.join(projectDir, "apps/server");
const dependencies: AvailableDependencies[] = [];
const devDependencies: AvailableDependencies[] = [];
if (framework === "hono") {
dependencies.push("hono");
if (api === "trpc") {
dependencies.push("@hono/trpc-server");
}
if (runtime === "node") {
dependencies.push("@hono/node-server");
devDependencies.push("tsx", "@types/node");
}
} else if (framework === "elysia") {
dependencies.push("elysia", "@elysiajs/cors");
if (api === "trpc") {
dependencies.push("@elysiajs/trpc");
}
if (runtime === "node") {
dependencies.push("@elysiajs/node");
devDependencies.push("tsx", "@types/node");
}
} else if (framework === "express") {
dependencies.push("express", "cors");
devDependencies.push("@types/express", "@types/cors");
if (runtime === "node") {
devDependencies.push("tsx", "@types/node");
}
} else if (framework === "fastify") {
dependencies.push("fastify", "@fastify/cors");
if (runtime === "node") {
devDependencies.push("tsx", "@types/node");
}
}
if (runtime === "bun") {
devDependencies.push("@types/bun");
}
if (dependencies.length > 0 || devDependencies.length > 0) {
await addPackageDependency({
dependencies,
devDependencies,
projectDir: serverDir,
});
}
}

View File

@@ -0,0 +1,91 @@
import path from "node:path";
import { spinner } from "@clack/prompts";
import consola from "consola";
import fs from "fs-extra";
import pc from "picocolors";
import { addPackageDependency } from "../../utils/add-package-deps";
import { setupMongoDBAtlas } from "../database-providers/mongodb-atlas-setup";
import { setupPrismaPostgres } from "../database-providers/prisma-postgres-setup";
import { setupSupabase } from "../database-providers/supabase-setup";
import { setupTurso } from "../database-providers/turso-setup";
import { setupNeonPostgres } from "../database-providers/neon-setup";
import type { ProjectConfig } from "../../types";
export async function setupDatabase(config: ProjectConfig): Promise<void> {
const { database, orm, dbSetup, backend, projectDir } = config;
if (backend === "convex" || database === "none") {
if (backend !== "convex") {
const serverDir = path.join(projectDir, "apps/server");
const serverDbDir = path.join(serverDir, "src/db");
if (await fs.pathExists(serverDbDir)) {
await fs.remove(serverDbDir);
}
}
return;
}
const s = spinner();
const serverDir = path.join(projectDir, "apps/server");
if (!(await fs.pathExists(serverDir))) {
return;
}
try {
if (orm === "prisma") {
await addPackageDependency({
dependencies: ["@prisma/client"],
devDependencies: ["prisma"],
projectDir: serverDir,
});
} else if (orm === "drizzle") {
if (database === "sqlite") {
await addPackageDependency({
dependencies: ["drizzle-orm", "@libsql/client"],
devDependencies: ["drizzle-kit"],
projectDir: serverDir,
});
} else if (database === "postgres") {
await addPackageDependency({
dependencies: ["drizzle-orm", "pg"],
devDependencies: ["drizzle-kit", "@types/pg"],
projectDir: serverDir,
});
} else if (database === "mysql") {
await addPackageDependency({
dependencies: ["drizzle-orm", "mysql2"],
devDependencies: ["drizzle-kit"],
projectDir: serverDir,
});
}
} else if (orm === "mongoose") {
await addPackageDependency({
dependencies: ["mongoose"],
devDependencies: [],
projectDir: serverDir,
});
}
if (database === "sqlite" && dbSetup === "turso") {
await setupTurso(config);
} else if (database === "postgres") {
if (orm === "prisma" && dbSetup === "prisma-postgres") {
await setupPrismaPostgres(config);
} else if (dbSetup === "neon") {
await setupNeonPostgres(config);
} else if (dbSetup === "supabase") {
await setupSupabase(config);
}
} else if (database === "mongodb" && dbSetup === "mongodb-atlas") {
await setupMongoDBAtlas(config);
}
} catch (error) {
s.stop(pc.red("Failed to set up database"));
if (error instanceof Error) {
consola.error(pc.red(error.message));
}
}
}

View File

@@ -0,0 +1,55 @@
import path from "node:path";
import fs from "fs-extra";
import type { AvailableDependencies } from "../../constants";
import type { ProjectConfig } from "../../types";
import { addPackageDependency } from "../../utils/add-package-deps";
export async function setupExamples(config: ProjectConfig): Promise<void> {
const { examples, frontend, backend, projectDir } = config;
if (
backend === "convex" ||
!examples ||
examples.length === 0 ||
examples[0] === "none"
) {
return;
}
if (examples.includes("ai")) {
const clientDir = path.join(projectDir, "apps/web");
const serverDir = path.join(projectDir, "apps/server");
const clientDirExists = await fs.pathExists(clientDir);
const serverDirExists = await fs.pathExists(serverDir);
const hasNuxt = frontend.includes("nuxt");
const hasSvelte = frontend.includes("svelte");
const hasReact =
frontend.includes("react-router") ||
frontend.includes("tanstack-router") ||
frontend.includes("next") ||
frontend.includes("tanstack-start");
if (clientDirExists) {
const dependencies: AvailableDependencies[] = ["ai"];
if (hasNuxt) {
dependencies.push("@ai-sdk/vue");
} else if (hasSvelte) {
dependencies.push("@ai-sdk/svelte");
} else if (hasReact) {
dependencies.push("@ai-sdk/react");
}
await addPackageDependency({
dependencies,
projectDir: clientDir,
});
}
if (serverDirExists && backend !== "none") {
await addPackageDependency({
dependencies: ["ai", "@ai-sdk/google"],
projectDir: serverDir,
});
}
}
}

View File

@@ -0,0 +1,82 @@
import path from "node:path";
import fs from "fs-extra";
import type { Backend, ProjectConfig } from "../../types";
import { addPackageDependency } from "../../utils/add-package-deps";
export async function setupRuntime(config: ProjectConfig): Promise<void> {
const { runtime, backend, projectDir } = config;
if (backend === "convex" || backend === "next" || runtime === "none") {
return;
}
const serverDir = path.join(projectDir, "apps/server");
if (!(await fs.pathExists(serverDir))) {
return;
}
if (runtime === "bun") {
await setupBunRuntime(serverDir, backend);
} else if (runtime === "node") {
await setupNodeRuntime(serverDir, backend);
}
}
async function setupBunRuntime(
serverDir: string,
_backend: Backend,
): Promise<void> {
const packageJsonPath = path.join(serverDir, "package.json");
if (!(await fs.pathExists(packageJsonPath))) return;
const packageJson = await fs.readJson(packageJsonPath);
packageJson.scripts = {
...packageJson.scripts,
dev: "bun run --hot src/index.ts",
start: "bun run dist/src/index.js",
};
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
await addPackageDependency({
devDependencies: ["@types/bun"],
projectDir: serverDir,
});
}
async function setupNodeRuntime(
serverDir: string,
backend: Backend,
): Promise<void> {
const packageJsonPath = path.join(serverDir, "package.json");
if (!(await fs.pathExists(packageJsonPath))) return;
const packageJson = await fs.readJson(packageJsonPath);
packageJson.scripts = {
...packageJson.scripts,
dev: "tsx watch src/index.ts",
start: "node dist/src/index.js",
};
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
await addPackageDependency({
devDependencies: ["tsx", "@types/node"],
projectDir: serverDir,
});
if (backend === "hono") {
await addPackageDependency({
dependencies: ["@hono/node-server"],
projectDir: serverDir,
});
} else if (backend === "elysia") {
await addPackageDependency({
dependencies: ["@elysiajs/node"],
projectDir: serverDir,
});
}
}

View File

@@ -0,0 +1,50 @@
import path from "node:path";
import { spinner } from "@clack/prompts";
import consola from "consola";
import { execa } from "execa";
import pc from "picocolors";
import type { ProjectConfig } from "../../types";
import { getPackageExecutionCommand } from "../../utils/get-package-execution-command";
export async function setupStarlight(config: ProjectConfig): Promise<void> {
const { packageManager, projectDir } = config;
const s = spinner();
try {
s.start("Setting up Starlight docs...");
const starlightArgs = [
"docs",
"--template",
"starlight",
"--no-install",
"--add",
"tailwind",
"--no-git",
"--skip-houston",
];
const starlightArgsString = starlightArgs.join(" ");
const commandWithArgs = `create-astro@latest ${starlightArgsString}`;
const starlightInitCommand = getPackageExecutionCommand(
packageManager,
commandWithArgs,
);
await execa(starlightInitCommand, {
cwd: path.join(projectDir, "apps"),
env: {
CI: "true",
},
shell: true,
});
s.stop("Starlight docs setup successfully!");
} catch (error) {
s.stop(pc.red("Failed to set up Starlight docs"));
if (error instanceof Error) {
consola.error(pc.red(error.message));
}
}
}

View File

@@ -0,0 +1,100 @@
import path from "node:path";
import { spinner } from "@clack/prompts";
import { consola } from "consola";
import { execa } from "execa";
import fs from "fs-extra";
import pc from "picocolors";
import { addPackageDependency } from "../../utils/add-package-deps";
import { getPackageExecutionCommand } from "../../utils/get-package-execution-command";
import type { ProjectConfig } from "../../types";
export async function setupTauri(config: ProjectConfig): Promise<void> {
const { packageManager, frontend, projectDir } = config;
const s = spinner();
const clientPackageDir = path.join(projectDir, "apps/web");
if (!(await fs.pathExists(clientPackageDir))) {
return;
}
try {
s.start("Setting up Tauri desktop app support...");
await addPackageDependency({
devDependencies: ["@tauri-apps/cli"],
projectDir: clientPackageDir,
});
const clientPackageJsonPath = path.join(clientPackageDir, "package.json");
if (await fs.pathExists(clientPackageJsonPath)) {
const packageJson = await fs.readJson(clientPackageJsonPath);
packageJson.scripts = {
...packageJson.scripts,
tauri: "tauri",
"desktop:dev": "tauri dev",
"desktop:build": "tauri build",
};
await fs.writeJson(clientPackageJsonPath, packageJson, { spaces: 2 });
}
const _hasTanstackRouter = frontend.includes("tanstack-router");
const hasReactRouter = frontend.includes("react-router");
const hasNuxt = frontend.includes("nuxt");
const hasSvelte = frontend.includes("svelte");
const _hasSolid = frontend.includes("solid");
const hasNext = frontend.includes("next");
const devUrl =
hasReactRouter || hasSvelte
? "http://localhost:5173"
: hasNext
? "http://localhost:3001"
: "http://localhost:3001";
const frontendDist = hasNuxt
? "../.output/public"
: hasSvelte
? "../build"
: hasNext
? "../.next"
: hasReactRouter
? "../build/client"
: "../dist";
const tauriArgs = [
"init",
`--app-name=${path.basename(projectDir)}`,
`--window-title=${path.basename(projectDir)}`,
`--frontend-dist=${frontendDist}`,
`--dev-url=${devUrl}`,
`--before-dev-command=\"${packageManager} run dev\"`,
`--before-build-command=\"${packageManager} run build\"`,
];
const tauriArgsString = tauriArgs.join(" ");
const commandWithArgs = `@tauri-apps/cli@latest ${tauriArgsString}`;
const tauriInitCommand = getPackageExecutionCommand(
packageManager,
commandWithArgs,
);
await execa(tauriInitCommand, {
cwd: clientPackageDir,
env: {
CI: "true",
},
shell: true,
});
s.stop("Tauri desktop app support configured successfully!");
} catch (error) {
s.stop(pc.red("Failed to set up Tauri"));
if (error instanceof Error) {
consola.error(pc.red(error.message));
}
}
}