mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
Rename packages directory to apps for consistent monorepo structure
This commit is contained in:
5
.changeset/loose-otters-yell.md
Normal file
5
.changeset/loose-otters-yell.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"create-better-t-stack": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
rename packages folder to apps
|
||||||
@@ -87,7 +87,7 @@ async function setupPwa(projectDir: string) {
|
|||||||
await fs.copy(pwaTemplateDir, projectDir, { overwrite: true });
|
await fs.copy(pwaTemplateDir, projectDir, { overwrite: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const clientPackageDir = path.join(projectDir, "packages/client");
|
const clientPackageDir = path.join(projectDir, "apps/client");
|
||||||
|
|
||||||
addPackageDependency({
|
addPackageDependency({
|
||||||
dependencies: ["vite-plugin-pwa"],
|
dependencies: ["vite-plugin-pwa"],
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ export async function setupAuth(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverDir = path.join(projectDir, "packages/server");
|
const serverDir = path.join(projectDir, "apps/server");
|
||||||
const clientDir = path.join(projectDir, "packages/client");
|
const clientDir = path.join(projectDir, "apps/client");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
addPackageDependency({
|
addPackageDependency({
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ The API is running at [http://localhost:3000](http://localhost:3000).
|
|||||||
|
|
||||||
\`\`\`
|
\`\`\`
|
||||||
${projectName}/
|
${projectName}/
|
||||||
├── packages/
|
├── apps/
|
||||||
│ ├── client/ # Frontend application (React, TanStack Router)
|
│ ├── client/ # Frontend application (React, TanStack Router)
|
||||||
│ └── server/ # Backend API (Hono, tRPC)
|
│ └── server/ # Backend API (Hono, tRPC)
|
||||||
\`\`\`
|
\`\`\`
|
||||||
@@ -122,16 +122,16 @@ function generateDatabaseSetup(
|
|||||||
|
|
||||||
1. Start the local SQLite database:
|
1. Start the local SQLite database:
|
||||||
\`\`\`bash
|
\`\`\`bash
|
||||||
cd packages/server && ${packageManagerRunCmd} db:local
|
cd apps/server && ${packageManagerRunCmd} db:local
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
2. Update your \`.env\` file in the \`packages/server\` directory with the appropriate connection details if needed.
|
2. Update your \`.env\` file in the \`apps/server\` directory with the appropriate connection details if needed.
|
||||||
`;
|
`;
|
||||||
} else if (database === "postgres") {
|
} else if (database === "postgres") {
|
||||||
setup += `This project uses PostgreSQL${orm === "drizzle" ? " with Drizzle ORM" : " with Prisma"}.
|
setup += `This project uses PostgreSQL${orm === "drizzle" ? " with Drizzle ORM" : " with Prisma"}.
|
||||||
|
|
||||||
1. Make sure you have a PostgreSQL database set up.
|
1. Make sure you have a PostgreSQL database set up.
|
||||||
2. Update your \`packages/server/.env\` file with your PostgreSQL connection details.
|
2. Update your \`apps/server/.env\` file with your PostgreSQL connection details.
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ function generateScriptsList(
|
|||||||
- \`${packageManagerRunCmd} build\`: Build both client and server
|
- \`${packageManagerRunCmd} build\`: Build both client and server
|
||||||
- \`${packageManagerRunCmd} dev:client\`: Start only the client
|
- \`${packageManagerRunCmd} dev:client\`: Start only the client
|
||||||
- \`${packageManagerRunCmd} dev:server\`: Start only the server
|
- \`${packageManagerRunCmd} dev:server\`: Start only the server
|
||||||
- \`${packageManagerRunCmd} check-types\`: Check TypeScript types across all packages`;
|
- \`${packageManagerRunCmd} check-types\`: Check TypeScript types across all apps`;
|
||||||
|
|
||||||
if (database !== "none") {
|
if (database !== "none") {
|
||||||
scripts += `
|
scripts += `
|
||||||
@@ -170,7 +170,7 @@ function generateScriptsList(
|
|||||||
- \`${packageManagerRunCmd} db:studio\`: Open database studio UI`;
|
- \`${packageManagerRunCmd} db:studio\`: Open database studio UI`;
|
||||||
|
|
||||||
if (database === "sqlite" && orm === "drizzle") {
|
if (database === "sqlite" && orm === "drizzle") {
|
||||||
scripts += `\n- \`cd packages/server && ${packageManagerRunCmd} db:local\`: Start the local SQLite database`;
|
scripts += `\n- \`cd apps/server && ${packageManagerRunCmd} db:local\`: Start the local SQLite database`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export async function setupDatabase(
|
|||||||
setupTursoDb = true,
|
setupTursoDb = true,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const s = spinner();
|
const s = spinner();
|
||||||
const serverDir = path.join(projectDir, "packages/server");
|
const serverDir = path.join(projectDir, "apps/server");
|
||||||
|
|
||||||
if (databaseType === "none") {
|
if (databaseType === "none") {
|
||||||
await fs.remove(path.join(serverDir, "src/db"));
|
await fs.remove(path.join(serverDir, "src/db"));
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ export async function setupEnvironmentVariables(
|
|||||||
projectDir: string,
|
projectDir: string,
|
||||||
options: ProjectConfig,
|
options: ProjectConfig,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const serverDir = path.join(projectDir, "packages/server");
|
const serverDir = path.join(projectDir, "apps/server");
|
||||||
const clientDir = path.join(projectDir, "packages/client");
|
const clientDir = path.join(projectDir, "apps/client");
|
||||||
|
|
||||||
const envPath = path.join(serverDir, ".env");
|
const envPath = path.join(serverDir, ".env");
|
||||||
let envContent = "";
|
let envContent = "";
|
||||||
|
|||||||
@@ -23,21 +23,18 @@ async function setupTodoExample(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const todoExampleDir = path.join(PKG_ROOT, "template/examples/todo");
|
const todoExampleDir = path.join(PKG_ROOT, "template/examples/todo");
|
||||||
if (await fs.pathExists(todoExampleDir)) {
|
if (await fs.pathExists(todoExampleDir)) {
|
||||||
const todoRouteDir = path.join(
|
const todoRouteDir = path.join(todoExampleDir, "apps/client/src/routes");
|
||||||
todoExampleDir,
|
const targetRouteDir = path.join(projectDir, "apps/client/src/routes");
|
||||||
"packages/client/src/routes",
|
|
||||||
);
|
|
||||||
const targetRouteDir = path.join(projectDir, "packages/client/src/routes");
|
|
||||||
await fs.copy(todoRouteDir, targetRouteDir, { overwrite: true });
|
await fs.copy(todoRouteDir, targetRouteDir, { overwrite: true });
|
||||||
|
|
||||||
if (orm !== "none") {
|
if (orm !== "none") {
|
||||||
const todoRouterSourceFile = path.join(
|
const todoRouterSourceFile = path.join(
|
||||||
todoExampleDir,
|
todoExampleDir,
|
||||||
`packages/server/src/routers/with-${orm}-todo.ts`,
|
`apps/server/src/routers/with-${orm}-todo.ts`,
|
||||||
);
|
);
|
||||||
const todoRouterTargetFile = path.join(
|
const todoRouterTargetFile = path.join(
|
||||||
projectDir,
|
projectDir,
|
||||||
"packages/server/src/routers/todo.ts",
|
"apps/server/src/routers/todo.ts",
|
||||||
);
|
);
|
||||||
|
|
||||||
if (await fs.pathExists(todoRouterSourceFile)) {
|
if (await fs.pathExists(todoRouterSourceFile)) {
|
||||||
@@ -58,7 +55,7 @@ async function updateHeaderWithTodoLink(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const headerPath = path.join(
|
const headerPath = path.join(
|
||||||
projectDir,
|
projectDir,
|
||||||
"packages/client/src/components/header.tsx",
|
"apps/client/src/components/header.tsx",
|
||||||
);
|
);
|
||||||
|
|
||||||
if (await fs.pathExists(headerPath)) {
|
if (await fs.pathExists(headerPath)) {
|
||||||
@@ -87,7 +84,7 @@ async function cleanupTodoFiles(
|
|||||||
if (orm === "drizzle") {
|
if (orm === "drizzle") {
|
||||||
const todoSchemaFile = path.join(
|
const todoSchemaFile = path.join(
|
||||||
projectDir,
|
projectDir,
|
||||||
"packages/server/src/db/schema/todo.ts",
|
"apps/server/src/db/schema/todo.ts",
|
||||||
);
|
);
|
||||||
if (await fs.pathExists(todoSchemaFile)) {
|
if (await fs.pathExists(todoSchemaFile)) {
|
||||||
await fs.remove(todoSchemaFile);
|
await fs.remove(todoSchemaFile);
|
||||||
@@ -95,7 +92,7 @@ async function cleanupTodoFiles(
|
|||||||
} else if (orm === "prisma") {
|
} else if (orm === "prisma") {
|
||||||
const todoPrismaFile = path.join(
|
const todoPrismaFile = path.join(
|
||||||
projectDir,
|
projectDir,
|
||||||
"packages/server/prisma/schema/todo.prisma",
|
"apps/server/prisma/schema/todo.prisma",
|
||||||
);
|
);
|
||||||
if (await fs.pathExists(todoPrismaFile)) {
|
if (await fs.pathExists(todoPrismaFile)) {
|
||||||
await fs.remove(todoPrismaFile);
|
await fs.remove(todoPrismaFile);
|
||||||
@@ -104,7 +101,7 @@ async function cleanupTodoFiles(
|
|||||||
|
|
||||||
const todoRouterFile = path.join(
|
const todoRouterFile = path.join(
|
||||||
projectDir,
|
projectDir,
|
||||||
"packages/server/src/routers/todo.ts",
|
"apps/server/src/routers/todo.ts",
|
||||||
);
|
);
|
||||||
if (await fs.pathExists(todoRouterFile)) {
|
if (await fs.pathExists(todoRouterFile)) {
|
||||||
await fs.remove(todoRouterFile);
|
await fs.remove(todoRouterFile);
|
||||||
@@ -114,10 +111,7 @@ async function cleanupTodoFiles(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function updateRouterIndex(projectDir: string): Promise<void> {
|
async function updateRouterIndex(projectDir: string): Promise<void> {
|
||||||
const routerFile = path.join(
|
const routerFile = path.join(projectDir, "apps/server/src/routers/index.ts");
|
||||||
projectDir,
|
|
||||||
"packages/server/src/routers/index.ts",
|
|
||||||
);
|
|
||||||
|
|
||||||
if (await fs.pathExists(routerFile)) {
|
if (await fs.pathExists(routerFile)) {
|
||||||
let routerContent = await fs.readFile(routerFile, "utf8");
|
let routerContent = await fs.readFile(routerFile, "utf8");
|
||||||
@@ -131,10 +125,7 @@ async function updateRouterIndex(projectDir: string): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function addTodoButtonToHomepage(projectDir: string): Promise<void> {
|
async function addTodoButtonToHomepage(projectDir: string): Promise<void> {
|
||||||
const indexPath = path.join(
|
const indexPath = path.join(projectDir, "apps/client/src/routes/index.tsx");
|
||||||
projectDir,
|
|
||||||
"packages/client/src/routes/index.tsx",
|
|
||||||
);
|
|
||||||
|
|
||||||
if (await fs.pathExists(indexPath)) {
|
if (await fs.pathExists(indexPath)) {
|
||||||
let indexContent = await fs.readFile(indexPath, "utf8");
|
let indexContent = await fs.readFile(indexPath, "utf8");
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ function getDatabaseInstructions(
|
|||||||
} else if (orm === "drizzle") {
|
} else if (orm === "drizzle") {
|
||||||
if (database === "sqlite") {
|
if (database === "sqlite") {
|
||||||
instructions.push(
|
instructions.push(
|
||||||
`${pc.cyan("•")} Start local DB: ${pc.dim(`cd packages/server && ${runCmd} db:local`)}`,
|
`${pc.cyan("•")} Start local DB: ${pc.dim(`cd apps/server && ${runCmd} db:local`)}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
instructions.push(
|
instructions.push(
|
||||||
@@ -85,5 +85,5 @@ function getDatabaseInstructions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getTauriInstructions(runCmd?: string): string {
|
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`;
|
return `${pc.bold("Desktop app with Tauri:")}\n${pc.cyan("•")} Start desktop app: ${pc.dim(`cd apps/client && ${runCmd} desktop:dev`)}\n${pc.cyan("•")} Build desktop app: ${pc.dim(`cd apps/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`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ async function updateServerPackageJson(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const serverPackageJsonPath = path.join(
|
const serverPackageJsonPath = path.join(
|
||||||
projectDir,
|
projectDir,
|
||||||
"packages/server/package.json",
|
"apps/server/package.json",
|
||||||
);
|
);
|
||||||
|
|
||||||
if (await fs.pathExists(serverPackageJsonPath)) {
|
if (await fs.pathExists(serverPackageJsonPath)) {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export async function setupTauri(
|
|||||||
packageManager: PackageManager,
|
packageManager: PackageManager,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const s = spinner();
|
const s = spinner();
|
||||||
const clientPackageDir = path.join(projectDir, "packages/client");
|
const clientPackageDir = path.join(projectDir, "apps/client");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
s.start("Setting up Tauri desktop app support...");
|
s.start("Setting up Tauri desktop app support...");
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export async function setupOrmTemplate(
|
|||||||
if (await fs.pathExists(ormTemplateDir)) {
|
if (await fs.pathExists(ormTemplateDir)) {
|
||||||
await fs.copy(ormTemplateDir, projectDir, { overwrite: true });
|
await fs.copy(ormTemplateDir, projectDir, { overwrite: true });
|
||||||
|
|
||||||
const serverSrcPath = path.join(projectDir, "packages/server/src");
|
const serverSrcPath = path.join(projectDir, "apps/server/src");
|
||||||
const libPath = path.join(serverSrcPath, "lib");
|
const libPath = path.join(serverSrcPath, "lib");
|
||||||
const withAuthLibPath = path.join(serverSrcPath, "with-auth-lib");
|
const withAuthLibPath = path.join(serverSrcPath, "with-auth-lib");
|
||||||
|
|
||||||
@@ -54,8 +54,8 @@ export async function setupOrmTemplate(
|
|||||||
export async function fixGitignoreFiles(projectDir: string): Promise<void> {
|
export async function fixGitignoreFiles(projectDir: string): Promise<void> {
|
||||||
const gitignorePaths = [
|
const gitignorePaths = [
|
||||||
path.join(projectDir, "_gitignore"),
|
path.join(projectDir, "_gitignore"),
|
||||||
path.join(projectDir, "packages/client/_gitignore"),
|
path.join(projectDir, "apps/client/_gitignore"),
|
||||||
path.join(projectDir, "packages/server/_gitignore"),
|
path.join(projectDir, "apps/server/_gitignore"),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const gitignorePath of gitignorePaths) {
|
for (const gitignorePath of gitignorePaths) {
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ async function createTursoDatabase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function writeEnvFile(projectDir: string, config?: TursoConfig) {
|
async function writeEnvFile(projectDir: string, config?: TursoConfig) {
|
||||||
const envPath = path.join(projectDir, "packages/server", ".env");
|
const envPath = path.join(projectDir, "apps/server", ".env");
|
||||||
const envContent = config
|
const envContent = config
|
||||||
? `TURSO_CONNECTION_URL="${config.dbUrl}"
|
? `TURSO_CONNECTION_URL="${config.dbUrl}"
|
||||||
TURSO_AUTH_TOKEN="${config.authToken}"`
|
TURSO_AUTH_TOKEN="${config.authToken}"`
|
||||||
@@ -175,7 +175,7 @@ function displayManualSetupInstructions() {
|
|||||||
1. Visit https://turso.tech and create an account
|
1. Visit https://turso.tech and create an account
|
||||||
2. Create a new database from the dashboard
|
2. Create a new database from the dashboard
|
||||||
3. Get your database URL and authentication token
|
3. Get your database URL and authentication token
|
||||||
4. Add these credentials to the .env file in packages/server/.env
|
4. Add these credentials to the .env file in apps/server/.env
|
||||||
|
|
||||||
TURSO_CONNECTION_URL=your_database_url
|
TURSO_CONNECTION_URL=your_database_url
|
||||||
TURSO_AUTH_TOKEN=your_auth_token`);
|
TURSO_AUTH_TOKEN=your_auth_token`);
|
||||||
|
|||||||
@@ -11,8 +11,10 @@
|
|||||||
"check-types": "tsc --noEmit"
|
"check-types": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@tanstack/react-query-devtools": "^5.69.0",
|
||||||
|
"@tanstack/react-router-devtools": "^1.114.27",
|
||||||
"@tanstack/router-plugin": "^1.114.27",
|
"@tanstack/router-plugin": "^1.114.27",
|
||||||
"@types/node": "^22.13.11",
|
"@types/node": "^22.13.13",
|
||||||
"@types/react": "^19.0.12",
|
"@types/react": "^19.0.12",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
@@ -29,9 +31,7 @@
|
|||||||
"@tanstack/react-form": "^1.0.5",
|
"@tanstack/react-form": "^1.0.5",
|
||||||
"@tailwindcss/vite": "^4.0.15",
|
"@tailwindcss/vite": "^4.0.15",
|
||||||
"@tanstack/react-query": "^5.69.0",
|
"@tanstack/react-query": "^5.69.0",
|
||||||
"@tanstack/react-query-devtools": "^5.69.0",
|
|
||||||
"@tanstack/react-router": "^1.114.25",
|
"@tanstack/react-router": "^1.114.25",
|
||||||
"@tanstack/router-devtools": "^1.114.25",
|
|
||||||
"@trpc/client": "^11.0.0",
|
"@trpc/client": "^11.0.0",
|
||||||
"@trpc/react-query": "^11.0.0",
|
"@trpc/react-query": "^11.0.0",
|
||||||
"@trpc/server": "^11.0.0",
|
"@trpc/server": "^11.0.0",
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "better-t-stack",
|
"name": "better-t-stack",
|
||||||
"private": true,
|
"private": true,
|
||||||
"workspaces": ["packages/*"],
|
"workspaces": ["apps/*"],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "turbo dev",
|
"dev": "turbo dev",
|
||||||
"build": "turbo build",
|
"build": "turbo build",
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
packages:
|
packages:
|
||||||
- "packages/*"
|
- "apps/*"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Reference in New Issue
Block a user