UNPKG

mern-project-cli

Version:

A developer-friendly CLI tool that streamlines MERN stack development by automating project setup, database configuration, and boilerplate generation by implementing MVC Architecture. Create production-ready MongoDB, Express, React, and Node.js applicatio

344 lines (303 loc) • 10.4 kB
import fs from 'fs-extra'; import path from 'path'; import chalk from 'chalk'; import { execSync } from 'child_process'; import createNextJsProject from './createNextJs.js'; import { checkNodeVersion } from '../utils/checkNodeVersion.js'; export default function createMERNProjectCommand(program) { program .command('create <projectName>') .description('Create a new MERN project') .option('--next') .option('--backend') .action((projectName, opts) => { // Check Node.js version before proceeding if (opts.next) return createNextJsProject(projectName); checkNodeVersion(); const rootDir = path.join(process.cwd(), projectName); if (opts.backend) { console.log('šŸ“¦ Creating backend app...'); const backendDir = path.join(rootDir, 'backend'); const dirsToCreate = [ 'controllers', 'db', 'middlewares', 'models', 'routes', 'utils', ]; try { fs.mkdirSync(backendDir, { recursive: true }); dirsToCreate.forEach((dir) => fs.mkdirSync(path.join(backendDir, dir), { recursive: true }) ); console.log('āœ… Backend directory structure created.'); // Backend files creation fs.writeFileSync( path.join(backendDir, 'constants.js'), '// TODO: Add application-wide constants' ); fs.writeFileSync( path.join(backendDir, 'server.js'), `// Entry point of the backend server require('dotenv').config(); const express = require('express'); const app = express(); const PORT = process.env.PORT || 5000; app.use(express.json()); // Route to display the initial message on browser app.get('/', (req, res) => { res.send('${projectName.toUpperCase()} BACKEND API'); }); // TODO: Add routes and middleware app.listen(PORT, () => { console.log(\`Server is up and running at http://localhost:\${PORT} šŸš€\`); });` ); fs.writeFileSync( path.join(backendDir, '.env.example'), `# Sample .env file for backend PORT=5000 DB_URI=your_database_uri_here` ); fs.writeFileSync( path.join(backendDir, '.gitignore'), `node_modules .env` ); fs.writeFileSync( path.join(backendDir, 'README.md'), `# ${projectName} Backend This is the backend of the ${projectName} MERN project. ## Setup - Install dependencies: \`npm install\` - Start the development server: \`npm run dev\` ## Environment Variables Create a \`.env\` file based on \`.env.example\`.` ); fs.writeFileSync( path.join(backendDir, 'package.json'), JSON.stringify( { name: `${projectName}-backend`, version: '1.0.0', main: 'server.js', scripts: { start: 'node server.js', dev: 'nodemon server.js', }, dependencies: { express: '^4.21.1', mongoose: '^8.7.1', cors: '^2.8.5', dotenv: '^16.4.5', }, devDependencies: { nodemon: '^3.1.7', }, }, null, 2 ) ); console.log('āœ… Backend files created successfully.'); // Initialize Git in backend console.log('šŸ”§ Initializing Git repository in backend...'); try { execSync(`git init "${backendDir}"`, { stdio: 'inherit' }); console.log('āœ… Git repository initialized in backend.'); } catch { console.warn( 'āš ļø Git is not installed or an error occurred. Skipping Git initialization.' ); } // Install backend dependencies console.log('šŸ“¦ Installing backend dependencies...'); try { execSync('npm install', { cwd: backendDir, stdio: 'inherit' }); console.log('āœ… Backend dependencies installed.'); } catch (error) { console.error( `āŒ Failed to install backend dependencies: ${error.message}` ); process.exit(1); } console.log( `\nšŸŽ‰ Backend directory for "${projectName}" created successfully!` ); } catch (error) { console.error(`āŒ Failed to create backend: ${error.message}`); process.exit(1); } return; } // Create root project directory try { fs.mkdirSync(rootDir, { recursive: true }); console.log('āœ… Root directory created successfully.'); } catch (error) { console.error(`āŒ Failed to create root directory: ${error.message}`); process.exit(1); } console.log('šŸ“¦ Creating backend app...'); const backendDir = path.join(rootDir, 'backend'); const dirsToCreate = [ 'controllers', 'db', 'middlewares', 'models', 'routes', 'utils', ]; try { fs.mkdirSync(backendDir, { recursive: true }); dirsToCreate.forEach((dir) => fs.mkdirSync(path.join(backendDir, dir), { recursive: true }) ); console.log('āœ… Backend directory structure created.'); } catch (error) { console.error( `āŒ Failed to create backend directory structure: ${error.message}` ); process.exit(1); } // Backend files creation try { fs.writeFileSync( path.join(backendDir, 'constants.js'), '// TODO: Add application-wide constants' ); fs.writeFileSync( path.join(backendDir, 'server.js'), `// Entry point of the backend server require('dotenv').config(); const express = require('express'); const app = express(); const PORT = process.env.PORT || 5000; app.use(express.json()); // Route to display the initial message on browser app.get('/', (req, res) => { res.send('${projectName.toUpperCase()} BACKEND API'); }); // TODO: Add routes and middleware app.listen(PORT, () => { console.log(\`Server is up and running at http://localhost:\${PORT} šŸš€\`); });` ); fs.writeFileSync( path.join(backendDir, '.env.example'), `# Sample .env file for backend PORT=5000 DB_URI=your_database_uri_here` ); fs.writeFileSync( path.join(backendDir, '.gitignore'), `node_modules .env` ); fs.writeFileSync( path.join(backendDir, 'README.md'), `# ${projectName} Backend This is the backend of the ${projectName} MERN project. ## Setup - Install dependencies: \`npm install\` - Start the development server: \`npm run dev\` ## Environment Variables Create a \`.env\` file based on \`.env.example\`.` ); fs.writeFileSync( path.join(backendDir, 'package.json'), JSON.stringify( { name: `${projectName}-backend`, version: '1.0.0', main: 'server.js', scripts: { start: 'node server.js', dev: 'nodemon server.js', }, dependencies: { express: '^4.21.1', mongoose: '^8.7.1', cors: '^2.8.5', dotenv: '^16.4.5', }, devDependencies: { nodemon: '^3.1.7', }, }, null, 2 ) ); console.log('āœ… Backend files created successfully.'); } catch (error) { console.error(`āŒ Failed to create backend files: ${error.message}`); process.exit(1); } // Initialize Git in backend console.log('šŸ”§ Initializing Git repository in backend...'); try { execSync(`git init "${backendDir}"`, { stdio: 'inherit' }); console.log('āœ… Git repository initialized in backend.'); } catch { console.warn( 'āš ļø Git is not installed or an error occurred. Skipping Git initialization.' ); } const frontendDir = path.join(rootDir, 'frontend'); // Install backend dependencies console.log('šŸ“¦ Installing backend dependencies...'); try { execSync('npm install', { cwd: backendDir, stdio: 'inherit' }); console.log('āœ… Backend dependencies installed.'); } catch (error) { console.error( `āŒ Failed to install backend dependencies: ${error.message}` ); process.exit(1); } // Create frontend using Vite console.log('šŸ“¦ Creating React frontend app with Vite...'); try { // Ensure frontend directory exists and is empty fs.emptyDirSync(frontendDir); // Use npm create vite to generate the project execSync(`npm create vite@latest frontend -- --template react`, { cwd: rootDir, stdio: 'inherit', }); // Install dependencies console.log('šŸ“¦ Installing frontend dependencies...'); execSync('npm install', { cwd: frontendDir, stdio: 'inherit', }); console.log('āœ… Frontend dependencies installed.'); // Create .env.example fs.writeFileSync( path.join(frontendDir, '.env.example'), `# Sample .env file for frontend REACT_APP_API_URL=http://localhost:5000/api` ); console.log('āœ… Frontend .env.example file created.'); // Final success message console.log(`\nšŸŽ‰ MERN project "${projectName}" created successfully!`); console.log( `${chalk.green.bold('To get started:')} ${chalk.blue(`cd "${projectName}"`)} ${chalk.magenta.bold('Backend:')} ${chalk.blue('cd backend')} ${chalk.yellow('npm start')} ${chalk.cyan('or')} ${chalk.yellow( 'npm run dev [nodemon]' )} ${chalk.magenta.bold('Frontend:')} ${chalk.blue('cd frontend')} ${chalk.yellow('npm run dev')}` ); } catch (error) { console.error(`āŒ Failed to create frontend: ${error.message}`); process.exit(1); } }); }