UNPKG

boiler-code-create

Version:

A blazing-fast CLI tool to scaffold a full-featured MERN Stack project with React + Vite + TailwindCSS v4 and JWT Auth backend

344 lines (274 loc) • 10.5 kB
#!/usr/bin/env node const { execSync } = require("child_process"); const fs = require("fs"); const path = require("path"); const folderName = process.argv[2] || "my-mern-app"; const folderPath = path.join(process.cwd(),folderName); const mainfolder= fs.mkdirSync(folderPath); console.log(`\nšŸš€ Creating React project: ${folderName}...`); // Step 1: Create Vite + React app execSync(`npm create vite@latest frontend -- --template react`, { stdio: "inherit", cwd:folderPath }); const appPath=path.join(folderPath,"frontend") // Step 2: Install frontend dependencies execSync(`npm install`, { cwd: appPath, stdio: "inherit" }); // Step 3: Install TailwindCSS v4 console.log(`\nšŸŽØ Installing TailwindCSS v4...`); execSync(`npm install tailwindcss @tailwindcss/vite`, { cwd: appPath, stdio: "inherit", shell: true, }); // Step 4: Write vite.config.js manually const viteConfig = ` import react from '@vitejs/plugin-react' import { defineConfig } from 'vite'; import tailwindcss from '@tailwindcss/vite'; export default defineConfig({ plugins: [ react(), tailwindcss() ], }); `; fs.writeFileSync(`${appPath}/vite.config.js`,viteConfig); // Step 5: Create index.css and app.jsx const indexCss = ` @import "tailwindcss" `; fs.writeFileSync(`${appPath}/src/index.css`, indexCss); const appdata=`import { useState } from "react"; import reactLogo from "./assets/react.svg"; import viteLogo from "/vite.svg"; import "./index.css"; const features = [ { title: "āš™ļø Instant Fullstack Setup", description: "Spin up a complete MERN project in seconds with one CLI command.", }, { title: "šŸ” JWT Auth + Bcrypt", description: "Authentication is preconfigured with JWT and bcrypt hashing.", }, { title: "šŸ“ Clean Project Structure", description: "Organized folder structure for models, routes, controllers, and more.", }, { title: "šŸŽØ TailwindCSS v4 Integrated", description: "Beautiful styling powered by the latest Tailwind v4 setup.", }, ]; export default function App() { const [count, setCount] = useState(0); return ( <div className="min-h-screen bg-gradient-to-tr from-white via-indigo-50 to-purple-100 text-gray-800 flex flex-col"> {/* Header */} <header className="text-center py-10"> <div className="flex justify-center items-center space-x-8 mb-6"> <a href="https://vitejs.dev" target="_blank" rel="noreferrer"> <img src={viteLogo} className="h-16 hover:scale-110 transition-transform" alt="Vite logo" /> </a> <a href="https://react.dev" target="_blank" rel="noreferrer"> <img src={reactLogo} className="h-16 hover:scale-110 transition-transform" alt="React logo" /> </a> </div> <h1 className="text-4xl sm:text-5xl font-extrabold text-indigo-600 drop-shadow-lg">boiler-code-create</h1> <p className="mt-4 text-lg sm:text-xl max-w-2xl mx-auto text-gray-600"> Launch your fullstack MERN app in seconds. Backend + Frontend ready to build. </p> </header> {/* Feature Section */} <section className="py-12 px-6 sm:px-12 grid grid-cols-1 sm:grid-cols-2 gap-6 max-w-5xl mx-auto"> {features.map((feature, idx) => ( <div key={idx} className="bg-white p-6 rounded-xl shadow hover:shadow-xl transition-all border border-gray-100"> <h3 className="text-xl font-semibold text-indigo-700 mb-2">{feature.title}</h3> <p className="text-gray-600 text-sm">{feature.description}</p> </div> ))} </section> {/* Interactive Counter */} <section className="text-center my-16"> <h2 className="text-2xl font-semibold mb-4 text-indigo-700">⚔ Try Hot Reloading</h2> <button onClick={() => setCount(count + 1)} className="px-6 py-2 text-white bg-indigo-600 rounded-lg hover:bg-indigo-700 shadow transition-all" > Count is {count} </button> <p className="text-sm mt-3 text-gray-500">Edit <code>App.jsx</code> and save to test live updates!</p> </section> {/* Footer */} <footer className="mt-auto bg-white border-t py-4 text-center text-sm text-gray-500"> Ā© {new Date().getFullYear()} boiler-code-create. Crafted with ā¤ļø for developers. </footer> </div> ); } ` fs.writeFileSync(`${appPath}/src/App.jsx`,appdata); // Step 6: Install React Router console.log(`\n🌐 Installing React Router...`); execSync(`npm install react-router-dom`, { cwd: appPath, stdio: "inherit", }); console.log(`\nāœ… Your React + Tailwind v4 MERN app is ready!`); // Step 7: Create backend folder console.log(`\nšŸ“ Creating backend folder...`); const backendFolderName = "backend"; const backendPath=path.join(folderPath,backendFolderName); fs.mkdirSync(backendPath); execSync(`npm init -y `,{ cwd:backendPath, stdio:"inherit" }) console.log(`\n Installing express mongoose dotenv cors jsonwebtoken bcrypt ...`); execSync(`npm i express mongoose dotenv cors jsonwebtoken nodemon`,{ cwd:backendPath, stdio:"inherit" }) const indexdata=` const express = require("express"); const cors = require("cors"); require("dotenv").config(); const connectDB = require("./config/db"); const userRoutes = require("./routes/userRoutes"); const { notFound, errorHandler } = require("./middleware/errorMiddleware"); const app = express(); connectDB(); app.use(cors()); app.use(express.json()); app.use("/api/users", userRoutes); app.get("/", (req, res) => { res.send("API is running"); }); app.use(notFound); app.use(errorHandler); const PORT = process.env.PORT || 5000; app.listen(PORT, () => { console.log(\`Server is running on port \${PORT}\`); }); ` console.log("creating index.js...") fs.writeFileSync(path.join(backendPath,"index.js"),indexdata) const envData=` PORT=5000 MONGO_URI=mongodb://localhost:27017/mydatabase JWT_SECRET=yourStrongJWTSecret ` console.log("creating .env..."); fs.writeFileSync(path.join(backendPath,".env"),envData) const mongodata=`const mongoose = require('mongoose'); const connectDB = async () => { try { await mongoose.connect(process.env.MONGO_URI); console.log('āœ… MongoDB connected successfully'); } catch (err) { console.error('āŒ MongoDB connection error:', err); process.exit(1); // Stop the server on failure } }; module.exports = connectDB; ` fs.mkdirSync(path.join(backendPath,"config")); console.log("creating db.js..."); fs.writeFileSync(path.join(backendPath,"config","db.js"),mongodata) const middlewarePath=path.join(backendPath,"middleware") const routesPath=path.join(backendPath,"routes") const modelsPath=path.join(backendPath,"models") const controllerspath=path.join(backendPath,"controllers"); const userModelData = ` const mongoose = require("mongoose"); const userSchema = new mongoose.Schema( { name: { type: String, required: true }, email: { type: String, required: true, unique: true }, password: { type: String, required: true }, }, { timestamps: true } ); module.exports = mongoose.model("User", userSchema); `; fs.mkdirSync(modelsPath); fs.writeFileSync(path.join(modelsPath, "userModel.js"), userModelData); const controllerData = ` const User = require("../models/userModel"); const bcrypt = require("bcryptjs"); const jwt = require("jsonwebtoken"); const generateToken = (id) => { return jwt.sign({ id }, process.env.JWT_SECRET, { expiresIn: "30d" }); }; exports.registerUser = async (req, res) => { try { const { name, email, password } = req.body; const userExists = await User.findOne({ email }); if (userExists) return res.status(400).json({ message: "User already exists" }); const salt = await bcrypt.genSalt(10); const hashed = await bcrypt.hash(password, salt); const user = await User.create({ name, email, password: hashed }); res.status(201).json({ _id: user._id, name: user.name, email: user.email, token: generateToken(user._id), }); } catch (err) { res.status(500).json({ message: err.message }); } }; exports.loginUser = async (req, res) => { try { const { email, password } = req.body; const user = await User.findOne({ email }); const isMatch = user && await bcrypt.compare(password, user.password); if (!isMatch) return res.status(401).json({ message: "Invalid credentials" }); res.json({ _id: user._id, name: user.name, email: user.email, token: generateToken(user._id), }); } catch (err) { res.status(500).json({ message: err.message }); } }; `; fs.mkdirSync(controllerspath); fs.writeFileSync(path.join(controllerspath, "userController.js"), controllerData); const routesData = ` const express = require("express"); const router = express.Router(); const { registerUser, loginUser } = require("../controllers/userController"); router.post("/register", registerUser); router.post("/login", loginUser); module.exports = router; `; fs.mkdirSync(routesPath); fs.writeFileSync(path.join(routesPath, "userRoutes.js"), routesData); const middlewareData = ` const notFound = (req, res, next) => { const error = new Error(\`Not Found - \${req.originalUrl}\`); res.status(404); next(error); }; const errorHandler = (err, req, res, next) => { const statusCode = res.statusCode === 200 ? 500 : res.statusCode; res.status(statusCode).json({ message: err.message, stack: process.env.NODE_ENV === "production" ? null : err.stack, }); }; module.exports = { notFound, errorHandler }; `; fs.mkdirSync(middlewarePath); fs.writeFileSync(path.join(middlewarePath, "errorMiddleware.js"), middlewareData); console.log("\nāœ… All backend files created successfully!"); console.log("\nšŸš€ To run backend:"); console.log(`šŸ‘‰ cd ${folderName}/backend`); console.log(`šŸ‘‰ node index.js`); console.log("\n\n for running frontend") console.log(`šŸ‘‰ cd ${folderName}`); console.log(`šŸ‘‰ cd frontend && npm run dev `);