diff --git a/packages/atxp/src/help.ts b/packages/atxp/src/help.ts index 4e3a27c..134a621 100644 --- a/packages/atxp/src/help.ts +++ b/packages/atxp/src/help.ts @@ -16,18 +16,21 @@ export function showHelp(): void { console.log(); console.log(chalk.bold('Demo Options:')); - console.log(' ' + chalk.yellow('--verbose, -v') + ' ' + 'Show detailed logs'); - console.log(' ' + chalk.yellow('--refresh') + ' ' + 'Force refresh the demo from GitHub'); - console.log(' ' + chalk.yellow('--port, -p') + ' ' + 'Specify port number (default: 8016)'); - console.log(' ' + chalk.yellow('--dir, -d') + ' ' + 'Specify demo directory (default: ~/.cache/atxp/demo)'); + console.log(' ' + chalk.yellow('--verbose, -v') + ' ' + 'Show detailed logs'); + console.log(' ' + chalk.yellow('--refresh') + ' ' + 'Force refresh the demo from GitHub'); + console.log(' ' + chalk.yellow('--frontend-port, --fp') + ' ' + 'Specify frontend port (default: 8016)'); + console.log(' ' + chalk.yellow('--backend-port, --bp') + ' ' + 'Specify backend port (default: 8017)'); + console.log(' ' + chalk.yellow('--dir, -d') + ' ' + 'Specify demo directory (default: ~/.cache/atxp/demo)'); console.log(); console.log(chalk.bold('Examples:')); - console.log(' npx atxp demo # Run the demo with defaults'); + console.log(' npx atxp demo # Run the demo with defaults (frontend: 8016, backend: 8017)'); console.log(' npx atxp demo --verbose # Run demo with detailed logs'); - console.log(' npx atxp demo --port 3000 # Run demo on port 3000'); + console.log(' npx atxp demo --frontend-port 4000 # Run demo with frontend on port 4000'); + console.log(' npx atxp demo --backend-port 4001 # Run demo with backend on port 4001'); console.log(' npx atxp demo --dir ./my-demo # Use custom demo directory'); - console.log(' npx atxp demo --port 3000 --dir ./demo # Custom port and directory'); + console.log(' npx atxp demo --frontend-port 4000 --backend-port 4001 # Custom ports'); + console.log(' npx atxp demo --dir ./my-demo --frontend-port 4000 # Custom directory and port'); console.log(' npx atxp create # Create a new project'); console.log(); diff --git a/packages/atxp/src/index.ts b/packages/atxp/src/index.ts index 8a3e455..adefa6e 100644 --- a/packages/atxp/src/index.ts +++ b/packages/atxp/src/index.ts @@ -8,7 +8,8 @@ import { showHelp } from './help.js'; import { checkAllDependencies, showDependencyError } from './check-dependencies.js'; interface DemoOptions { - port: number; + frontendPort: number; + backendPort: number; dir: string; verbose: boolean; refresh: boolean; @@ -24,13 +25,22 @@ function parseArgs(): { command: string; demoOptions: DemoOptions } { return index !== -1 ? process.argv[index + 1] : undefined; }; - const port = (() => { - const portValue = getArgValue('--port', '-p'); + const frontendPort = (() => { + const portValue = getArgValue('--frontend-port', '--fp'); if (portValue) { const parsed = parseInt(portValue, 10); if (parsed > 0 && parsed < 65536) return parsed; } - return 8016; // default port + return 8016; // default frontend port + })(); + + const backendPort = (() => { + const portValue = getArgValue('--backend-port', '--bp'); + if (portValue) { + const parsed = parseInt(portValue, 10); + if (parsed > 0 && parsed < 65536) return parsed; + } + return 8017; // default backend port })(); const dir = (() => { @@ -43,7 +53,7 @@ function parseArgs(): { command: string; demoOptions: DemoOptions } { return { command, - demoOptions: { port, dir, verbose, refresh } + demoOptions: { frontendPort, backendPort, dir, verbose, refresh } }; } diff --git a/packages/atxp/src/run-demo.ts b/packages/atxp/src/run-demo.ts index 6fa0ea2..91fbfe7 100644 --- a/packages/atxp/src/run-demo.ts +++ b/packages/atxp/src/run-demo.ts @@ -2,9 +2,11 @@ import chalk from 'chalk'; import { spawn } from 'child_process'; import fs from 'fs-extra'; import open from 'open'; +import path from 'path'; interface DemoOptions { - port: number; + frontendPort: number; + backendPort: number; dir: string; verbose: boolean; refresh: boolean; @@ -32,8 +34,11 @@ export async function runDemo(options: DemoOptions): Promise { // Install dependencies if needed await installDependencies(options.dir, options.verbose); + // Create .env files for configuration + await createEnvFiles(options.dir, options.frontendPort, options.backendPort, options.verbose); + // Start the demo and open browser - await startDemo(options.port, options.dir, options.verbose); + await startDemo(options.frontendPort, options.backendPort, options.dir, options.verbose); } catch (error) { console.error(chalk.red('Error starting demo:'), (error as Error).message); @@ -124,9 +129,9 @@ async function installDependencies(demoDir: string, isVerbose: boolean): Promise }); } -async function startDemo(port: number, demoDir: string, isVerbose: boolean): Promise { +async function startDemo(frontendPort: number, backendPort: number, demoDir: string, isVerbose: boolean): Promise { console.log(chalk.blue('Starting demo application...')); - console.log(chalk.green(`Demo will be available at: http://localhost:${port}`)); + console.log(chalk.green(`Demo will be available at: http://localhost:${frontendPort}`)); console.log(chalk.gray(`Demo directory: ${demoDir}`)); console.log(chalk.yellow('Press Ctrl+C to stop the demo')); if (!isVerbose) { @@ -137,7 +142,11 @@ async function startDemo(port: number, demoDir: string, isVerbose: boolean): Pro // Set the port environment variable for the demo const env = { ...process.env, - PORT: port.toString(), + // Backend will use PORT from its .env file, frontend will use PORT from its .env file + // We don't set PORT globally to avoid conflicts - let each service read its own .env + FRONTEND_PORT: frontendPort.toString(), + BACKEND_PORT: backendPort.toString(), + REACT_APP_BACKEND_PORT: backendPort.toString(), // Suppress deprecation warnings NODE_NO_WARNINGS: '1', // Suppress React warnings in development @@ -190,10 +199,10 @@ async function startDemo(port: number, demoDir: string, isVerbose: boolean): Pro if (!demoOpenedBrowser) { try { console.log(chalk.blue('Opening browser...')); - await open(`http://localhost:${port}`); + await open(`http://localhost:${frontendPort}`); } catch { console.log(chalk.yellow('Could not open browser automatically')); - console.log(chalk.white(`Please open http://localhost:${port} in your browser`)); + console.log(chalk.white(`Please open http://localhost:${frontendPort} in your browser`)); } } }, 2000); @@ -224,6 +233,36 @@ async function startDemo(port: number, demoDir: string, isVerbose: boolean): Pro }); } +async function createEnvFiles(demoDir: string, frontendPort: number, backendPort: number, isVerbose: boolean): Promise { + if (isVerbose) { + console.log(chalk.blue('Creating .env files...')); + } + + try { + // Create backend .env file + const backendEnvPath = path.join(demoDir, 'backend', '.env'); + const backendEnvContent = `PORT=${backendPort}\nFRONTEND_PORT=${frontendPort}\n`; + await fs.writeFile(backendEnvPath, backendEnvContent); + + if (isVerbose) { + console.log(chalk.gray(`Created backend .env: ${backendEnvPath}`)); + } + + // Create frontend .env file + const frontendEnvPath = path.join(demoDir, 'frontend', '.env'); + const frontendEnvContent = `PORT=${frontendPort}\nREACT_APP_BACKEND_PORT=${backendPort}\n`; + await fs.writeFile(frontendEnvPath, frontendEnvContent); + + if (isVerbose) { + console.log(chalk.gray(`Created frontend .env: ${frontendEnvPath}`)); + } + + } catch (error) { + console.log(chalk.yellow(`Warning: Could not create .env files: ${(error as Error).message}`)); + console.log(chalk.gray('Demo will use environment variables passed directly')); + } +} + async function cleanup(): Promise { try { // Optionally clean up the demo directory