mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
Add Tauri desktop app support
Adds integration with Tauri for building native desktop apps from the web frontend, including CLI option, setup scripts, initialization logic, and post-installation instructions.
This commit is contained in:
5
.changeset/wise-crews-like.md
Normal file
5
.changeset/wise-crews-like.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"create-better-t-stack": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add Tauri Desktop App addon
|
||||||
@@ -31,6 +31,8 @@ export const dependencyVersionMap = {
|
|||||||
|
|
||||||
"vite-plugin-pwa": "^0.21.2",
|
"vite-plugin-pwa": "^0.21.2",
|
||||||
"@vite-pwa/assets-generator": "^0.2.6",
|
"@vite-pwa/assets-generator": "^0.2.6",
|
||||||
|
|
||||||
|
"@tauri-apps/cli": "^2.4.0",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type AvailableDependencies = keyof typeof dependencyVersionMap;
|
export type AvailableDependencies = keyof typeof dependencyVersionMap;
|
||||||
|
|||||||
@@ -1,16 +1,24 @@
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import fs from "fs-extra";
|
import fs from "fs-extra";
|
||||||
import { PKG_ROOT } from "../constants";
|
import { PKG_ROOT } from "../constants";
|
||||||
import type { ProjectAddons } from "../types";
|
import type { PackageManager, ProjectAddons } from "../types";
|
||||||
import { addPackageDependency } from "../utils/add-package-deps";
|
import { addPackageDependency } from "../utils/add-package-deps";
|
||||||
|
import { setupTauri } from "./tauri-setup";
|
||||||
|
|
||||||
export async function setupAddons(projectDir: string, addons: ProjectAddons[]) {
|
export async function setupAddons(
|
||||||
|
projectDir: string,
|
||||||
|
addons: ProjectAddons[],
|
||||||
|
packageManager: PackageManager,
|
||||||
|
) {
|
||||||
if (addons.includes("docker")) {
|
if (addons.includes("docker")) {
|
||||||
await setupDocker(projectDir);
|
await setupDocker(projectDir);
|
||||||
}
|
}
|
||||||
if (addons.includes("pwa")) {
|
if (addons.includes("pwa")) {
|
||||||
await setupPwa(projectDir);
|
await setupPwa(projectDir);
|
||||||
}
|
}
|
||||||
|
if (addons.includes("tauri")) {
|
||||||
|
await setupTauri(projectDir, packageManager);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setupDocker(projectDir: string) {
|
async function setupDocker(projectDir: string) {
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ export async function createProject(options: ProjectConfig): Promise<string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.addons.length > 0) {
|
if (options.addons.length > 0) {
|
||||||
await setupAddons(projectDir, options.addons);
|
await setupAddons(projectDir, options.addons, options.packageManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
await updatePackageConfigurations(projectDir, options);
|
await updatePackageConfigurations(projectDir, options);
|
||||||
@@ -138,6 +138,7 @@ export async function createProject(options: ProjectConfig): Promise<string> {
|
|||||||
options.packageManager,
|
options.packageManager,
|
||||||
!options.noInstall,
|
!options.noInstall,
|
||||||
options.orm,
|
options.orm,
|
||||||
|
options.addons,
|
||||||
);
|
);
|
||||||
|
|
||||||
return projectDir;
|
return projectDir;
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import { log } from "@clack/prompts";
|
import { log } from "@clack/prompts";
|
||||||
import pc from "picocolors";
|
import pc from "picocolors";
|
||||||
import type { PackageManager, ProjectDatabase, ProjectOrm } from "../types";
|
import type {
|
||||||
|
PackageManager,
|
||||||
|
ProjectAddons,
|
||||||
|
ProjectDatabase,
|
||||||
|
ProjectOrm,
|
||||||
|
} from "../types";
|
||||||
|
|
||||||
export function displayPostInstallInstructions(
|
export function displayPostInstallInstructions(
|
||||||
database: ProjectDatabase,
|
database: ProjectDatabase,
|
||||||
@@ -8,6 +13,7 @@ export function displayPostInstallInstructions(
|
|||||||
packageManager: PackageManager,
|
packageManager: PackageManager,
|
||||||
depsInstalled: boolean,
|
depsInstalled: boolean,
|
||||||
orm?: ProjectOrm,
|
orm?: ProjectOrm,
|
||||||
|
addons?: ProjectAddons[],
|
||||||
) {
|
) {
|
||||||
const runCmd = packageManager === "npm" ? "npm run" : packageManager;
|
const runCmd = packageManager === "npm" ? "npm run" : packageManager;
|
||||||
const cdCmd = `cd ${projectName}`;
|
const cdCmd = `cd ${projectName}`;
|
||||||
@@ -22,7 +28,8 @@ ${pc.bold("Your project will be available at:")}
|
|||||||
${pc.cyan("•")} Frontend: http://localhost:3001
|
${pc.cyan("•")} Frontend: http://localhost:3001
|
||||||
${pc.cyan("•")} API: http://localhost:3000
|
${pc.cyan("•")} API: http://localhost:3000
|
||||||
|
|
||||||
${database !== "none" ? getDatabaseInstructions(database, orm, runCmd) : ""}`);
|
${database !== "none" ? getDatabaseInstructions(database, orm, runCmd) : ""}
|
||||||
|
${addons?.includes("tauri") ? getTauriInstructions(runCmd) : ""}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDatabaseInstructions(
|
function getDatabaseInstructions(
|
||||||
@@ -63,3 +70,7 @@ function getDatabaseInstructions(
|
|||||||
? `${pc.bold("Database commands:")}\n${instructions.join("\n")}\n\n`
|
? `${pc.bold("Database commands:")}\n${instructions.join("\n")}\n\n`
|
||||||
: "";
|
: "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTauriInstructions(runCmd?: string): string {
|
||||||
|
return `${pc.bold("Desktop app with Tauri:")}\n${pc.cyan("•")} Start desktop app: ${pc.dim(`cd packages/client && ${runCmd} desktop:dev`)}\n${pc.cyan("•")} Build desktop app: ${pc.dim(`cd packages/client && ${runCmd} desktop:build`)}\n${pc.yellow("NOTE:")} Tauri requires Rust and platform-specific dependencies. See: ${pc.dim("https://v2.tauri.app/start/prerequisites/")}\n\n`;
|
||||||
|
}
|
||||||
|
|||||||
69
apps/cli/src/helpers/tauri-setup.ts
Normal file
69
apps/cli/src/helpers/tauri-setup.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import path from "node:path";
|
||||||
|
import { log, spinner } from "@clack/prompts";
|
||||||
|
import { $, execa } from "execa";
|
||||||
|
import fs from "fs-extra";
|
||||||
|
import pc from "picocolors";
|
||||||
|
import type { PackageManager } from "../types";
|
||||||
|
import { addPackageDependency } from "../utils/add-package-deps";
|
||||||
|
|
||||||
|
export async function setupTauri(
|
||||||
|
projectDir: string,
|
||||||
|
packageManager: PackageManager,
|
||||||
|
): Promise<void> {
|
||||||
|
const s = spinner();
|
||||||
|
const clientPackageDir = path.join(projectDir, "packages/client");
|
||||||
|
|
||||||
|
try {
|
||||||
|
s.start("Setting up Tauri desktop app support...");
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Add Tauri scripts
|
||||||
|
packageJson.scripts = {
|
||||||
|
...packageJson.scripts,
|
||||||
|
tauri: "tauri",
|
||||||
|
"desktop:dev": "tauri dev",
|
||||||
|
"desktop:build": "tauri build",
|
||||||
|
};
|
||||||
|
|
||||||
|
await fs.writeJson(clientPackageJsonPath, packageJson, { spaces: 2 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize Tauri in the client directory
|
||||||
|
// This creates the src-tauri folder structure with necessary config files
|
||||||
|
|
||||||
|
await execa(
|
||||||
|
"npx",
|
||||||
|
[
|
||||||
|
"@tauri-apps/cli@latest",
|
||||||
|
"init",
|
||||||
|
`--app-name=${path.basename(projectDir)}`,
|
||||||
|
`--window-title=${path.basename(projectDir)}`,
|
||||||
|
"--frontend-dist=dist",
|
||||||
|
"--dev-url=http://localhost:3001",
|
||||||
|
`--before-dev-command=${packageManager} run dev`,
|
||||||
|
`--before-build-command=${packageManager} run build`,
|
||||||
|
],
|
||||||
|
{
|
||||||
|
cwd: clientPackageDir,
|
||||||
|
env: {
|
||||||
|
CI: "true",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
s.stop("Tauri desktop app support configured successfully!");
|
||||||
|
} catch (error) {
|
||||||
|
s.stop(pc.red("Failed to set up Tauri"));
|
||||||
|
if (error instanceof Error) {
|
||||||
|
log.error(pc.red(error.message));
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,6 +32,7 @@ async function main() {
|
|||||||
.option("--no-auth", "Exclude authentication")
|
.option("--no-auth", "Exclude authentication")
|
||||||
.option("--docker", "Include Docker setup")
|
.option("--docker", "Include Docker setup")
|
||||||
.option("--pwa", "Include Progressive Web App support")
|
.option("--pwa", "Include Progressive Web App support")
|
||||||
|
.option("--tauri", "Include Tauri desktop app support")
|
||||||
.option("--no-addons", "Skip all additional addons")
|
.option("--no-addons", "Skip all additional addons")
|
||||||
.option("--git", "Include git setup")
|
.option("--git", "Include git setup")
|
||||||
.option("--no-git", "Skip git initialization")
|
.option("--no-git", "Skip git initialization")
|
||||||
@@ -71,13 +72,17 @@ async function main() {
|
|||||||
...("git" in options && { git: options.git }),
|
...("git" in options && { git: options.git }),
|
||||||
...("install" in options && { noInstall: !options.install }),
|
...("install" in options && { noInstall: !options.install }),
|
||||||
...("turso" in options && { turso: options.turso }),
|
...("turso" in options && { turso: options.turso }),
|
||||||
...((options.docker || options.pwa || options.addons === false) && {
|
...((options.docker ||
|
||||||
|
options.pwa ||
|
||||||
|
options.tauri ||
|
||||||
|
options.addons === false) && {
|
||||||
addons:
|
addons:
|
||||||
options.addons === false
|
options.addons === false
|
||||||
? []
|
? []
|
||||||
: ([
|
: ([
|
||||||
...(options.docker ? ["docker"] : []),
|
...(options.docker ? ["docker"] : []),
|
||||||
...(options.pwa ? ["pwa"] : []),
|
...(options.pwa ? ["pwa"] : []),
|
||||||
|
...(options.tauri ? ["tauri"] : []),
|
||||||
] as ProjectAddons[]),
|
] as ProjectAddons[]),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ export async function getAddonsChoice(
|
|||||||
label: "PWA (Progressive Web App)",
|
label: "PWA (Progressive Web App)",
|
||||||
hint: "Make your app installable and work offline",
|
hint: "Make your app installable and work offline",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
value: "tauri",
|
||||||
|
label: "Tauri Desktop App",
|
||||||
|
hint: "Build native desktop apps from your web frontend",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
required: false,
|
required: false,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export type ProjectDatabase = "sqlite" | "postgres" | "none";
|
export type ProjectDatabase = "sqlite" | "postgres" | "none";
|
||||||
export type ProjectOrm = "drizzle" | "prisma" | "none";
|
export type ProjectOrm = "drizzle" | "prisma" | "none";
|
||||||
export type PackageManager = "npm" | "pnpm" | "yarn" | "bun";
|
export type PackageManager = "npm" | "pnpm" | "yarn" | "bun";
|
||||||
export type ProjectAddons = "docker" | "pwa";
|
export type ProjectAddons = "docker" | "pwa" | "tauri";
|
||||||
|
|
||||||
export interface ProjectConfig {
|
export interface ProjectConfig {
|
||||||
projectName: string;
|
projectName: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user