diff --git a/package.json b/package.json index 38e2df495..4c657876e 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "type": "module", "scripts": { "dev": "node scripts/start-dev.js", - "dev:simple": "concurrently \"cd server && bun dev\" \"cd server && bun workers:dev\" \"cd vite && bun dev\" \"cd shared && bun dev\"", + "dev:simple": "concurrently \"cd shared && bun dev:watch\" \"cd server && bun dev\" \"cd server && bun workers:dev\" \"cd vite && bun dev\"", "vite:build": "bun -F @autumn/shared build && bun -F @autumn/vite build:bun", "vite:start": "bun -F @autumn/vite start:bun", "shared": "bun -F @autumn/shared build", @@ -29,9 +29,7 @@ "docker:up:ci": "docker compose -f docker-compose.ci.yml up --build", "build:all": "pnpm -F shared build && pnpm -F server prod:build && pnpm -F vite build", "vite:build:bun": "bun -F @autumn/shared build && bun -F @autumn/vite build:bun", - "vite:start:bun": "bun -F @autumn/shared build && bun -F @autumn/vite start:bun", - "dev:bun": "concurrently \"cd server && bun run dev\" \"cd vite && bun run dev\" \"bun -F @autumn/shared dev:bun\"", - "build:all:bun": "bun run -F @autumn/shared build:bun && bun run -F @autumn/server prod:build:bun && bun run -F @autumn/vite build:bun" + "vite:start:bun": "bun -F @autumn/shared build && bun -F @autumn/vite start:bun" }, "dependencies": { "@wooorm/starry-night": "^3.8.0", diff --git a/scripts/start-dev.js b/scripts/start-dev.js index 46a1bccc5..7ed2ff58f 100644 --- a/scripts/start-dev.js +++ b/scripts/start-dev.js @@ -6,17 +6,41 @@ async function startDev() { // Detect and set ports const { vitePort, serverPort } = await detectAndSetPorts(); - console.log("\nšŸš€ Starting development servers...\n"); + // Step 1: Build shared package first (initial build) + console.log("\nšŸ“¦ Building shared package...\n"); + const buildShared = spawn("bun", ["run", "build"], { + cwd: "shared", + stdio: "inherit", + shell: true, + }); - // Start concurrently with the detected ports + await new Promise((resolve, reject) => { + buildShared.on("close", (code) => { + if (code !== 0) { + reject(new Error(`Shared package build failed with code ${code}`)); + } else { + resolve(); + } + }); + buildShared.on("error", reject); + }); + + console.log("\nāœ… Shared package built successfully!\n"); + console.log("šŸš€ Starting development servers in watch mode...\n"); + + // Step 2: Start server, workers, and vite first (they'll use the built shared package) const concurrentlyCmd = spawn( "bunx", [ "concurrently", - `"cd shared && bun run build && bun tsc"`, + "-n", + "server,workers,vite,shared", + "-c", + "green,yellow,blue,cyan", `"cd server && SERVER_PORT=${serverPort} bun dev"`, `"cd server && bun workers:dev"`, `"cd vite && VITE_PORT=${vitePort} bun dev"`, + `"cd shared && bun run dev:watch"`, ], { stdio: "inherit", diff --git a/server/package.json b/server/package.json index 019484528..da87af2de 100644 --- a/server/package.json +++ b/server/package.json @@ -7,8 +7,8 @@ "scripts": { "email": "email dev -p 3001", "start": "bun src/index.ts", - "dev": "cross-env NODE_ENV=development bunx nodemon -w ../shared/dist -w src --ext js,ts --exec bun src/index.ts --ignore scripts --ignore tests", - "workers:dev": "cross-env NODE_ENV=development bunx nodemon -w ../shared/dist -w src/workers.ts -w src/queue --ext js,ts --exec bun src/workers.ts --ignore scripts --ignore tests", + "dev": "cross-env NODE_ENV=development bunx nodemon -w ../shared/dist -w src --ext js,ts --ignore '../shared/dist/**/*.d.ts' --ignore scripts --ignore tests --exec bun src/index.ts", + "workers:dev": "cross-env NODE_ENV=development bunx nodemon -w ../shared/dist -w src/workers.ts -w src/queue --ext js,ts --ignore '../shared/dist/**/*.d.ts' --ignore scripts --ignore tests --exec bun src/workers.ts", "workers": "bun src/workers.ts", "cron": "bun src/cron.ts", "check": "bun src/check.ts", diff --git a/shared/package.json b/shared/package.json index 4ef1b6d02..fb78f7306 100644 --- a/shared/package.json +++ b/shared/package.json @@ -16,6 +16,7 @@ "api": "bun api/openapi.ts", "build": "tsc --emitDeclarationOnly --outDir dist && bun build ./index.ts --outdir dist --format esm --target bun --external zod", "dev": "bunx nodemon --ext ts --ignore dist --exec \"tsc --emitDeclarationOnly --outDir dist && bun build ./index.ts --outdir dist --format esm --target bun --external zod\"", + "dev:watch": "bun scripts/watch.js", "db:push": "bun db:generate && bun db:migrate", "db:generate": "cross-env NODE_OPTIONS=\"--import tsx\" bunx drizzle-kit generate --config drizzle.config.ts", "db:migrate": "cross-env NODE_OPTIONS=\"--import tsx\" bunx drizzle-kit migrate --config drizzle.config.ts", diff --git a/shared/scripts/watch.js b/shared/scripts/watch.js new file mode 100644 index 000000000..a80c4b629 --- /dev/null +++ b/shared/scripts/watch.js @@ -0,0 +1,88 @@ +import { spawn } from "node:child_process"; +import { watch } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = resolve(dirname(fileURLToPath(import.meta.url)), ".."); + +let isBuilding = false; +let rebuildQueued = false; + +function runBuild() { + if (isBuilding) { + rebuildQueued = true; + return; + } + + isBuilding = true; + console.log("\nšŸ“¦ [shared] Rebuilding..."); + + const build = spawn( + "bun", + [ + "build", + "./index.ts", + "--outdir", + "dist", + "--format", + "esm", + "--target", + "bun", + "--external", + "zod", + ], + { + cwd: __dirname, + stdio: "inherit", + shell: true, + }, + ); + + // Run tsc in parallel + const tsc = spawn("tsc", ["--emitDeclarationOnly", "--outDir", "dist"], { + cwd: __dirname, + stdio: "inherit", + shell: true, + }); + + Promise.all([ + new Promise((resolve) => build.on("close", resolve)), + new Promise((resolve) => tsc.on("close", resolve)), + ]).then(() => { + console.log("āœ… [shared] Rebuild complete"); + isBuilding = false; + + if (rebuildQueued) { + rebuildQueued = false; + setTimeout(() => runBuild(), 100); + } + }); +} + +// Watch for changes (excluding dist directory) +const watcher = watch(__dirname, { recursive: true }, (eventType, filename) => { + if ( + !filename || + filename.includes("dist/") || + filename.includes("node_modules/") || + filename.includes("scripts/") || + !filename.endsWith(".ts") + ) { + return; + } + + console.log(`\nšŸ“ [shared] Changed: ${filename}`); + runBuild(); +}); + +console.log("šŸ‘€ [shared] Watching for changes..."); + +process.on("SIGINT", () => { + watcher.close(); + process.exit(0); +}); + +process.on("SIGTERM", () => { + watcher.close(); + process.exit(0); +});