create-butterfly-app-v2 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # create-butterfly-app
2
+
3
+ Scaffold a full-stack **Node.js + React + Tailwind + MySQL** project in seconds.
4
+
5
+ ```bash
6
+ npx create-butterfly-app my-project
7
+ cd my-project
8
+ npm run dev
9
+ ```
10
+
11
+ ---
12
+
13
+ ## Why this exists
14
+
15
+ If you have an **exam or assignment** that requires a working full-stack web app — with a backend API, a database, and a modern frontend — but you **don't know how to set it all up from scratch**, this boilerplate is for you.
16
+
17
+ Instead of spending hours wiring up Express, configuring Vite, installing Tailwind, connecting MySQL — writing boilerplate config files you don't understand — you get a **ready-to-run project** with one command.
18
+
19
+ You only need to know:
20
+ 1. **That XAMPP must be running** (start Apache & MySQL from the XAMPP Control Panel)
21
+ 2. **How to create a database** (open phpMyAdmin, click "New", type your project name, click "Create")
22
+ 3. **How to run `npm run dev`** in the terminal
23
+
24
+ That's it.
25
+
26
+ ---
27
+
28
+ ## What you get
29
+
30
+ ```
31
+ my-project/
32
+ ├── backend/
33
+ │ ├── server.js # Express server, starts on port 5000
34
+ │ ├── config/db.js # MySQL connection via XAMPP
35
+ │ └── routes/api.js # /api/users GET + POST
36
+ ├── frontend/
37
+ │ ├── src/App.jsx # React UI with Tailwind styling
38
+ │ ├── src/main.jsx # React entry point
39
+ │ ├── vite.config.js # Dev server + proxy to backend
40
+ │ ├── tailwind.config.js
41
+ │ └── postcss.config.js
42
+ ├── .env # DB credentials (user=root, password=blank)
43
+ └── package.json # Runs both backend & frontend together
44
+ ```
45
+
46
+ ---
47
+
48
+ ## How to use it in an exam / project
49
+
50
+ ### Step 1 — Start XAMPP
51
+
52
+ Open **XAMPP Control Panel** → click **Start** next to **Apache** and **MySQL**.
53
+
54
+ ### Step 2 — Create the database
55
+
56
+ Open your browser, go to `http://localhost/phpmyadmin`:
57
+ - Click **New** (left sidebar)
58
+ - Type your project name as the database name
59
+ - Click **Create** (no tables needed — the API will create them if you want, or you can add a table manually)
60
+
61
+ ### Step 3 — Create the project
62
+
63
+ ```bash
64
+ npx create-butterfly-app my-exam-project
65
+ cd my-exam-project
66
+ ```
67
+
68
+ ### Step 4 — Start the app
69
+
70
+ ```bash
71
+ npm run dev
72
+ ```
73
+
74
+ This starts:
75
+ - **Backend** on `http://localhost:5000`
76
+ - **Frontend** on `http://localhost:5173` (opens in browser automatically)
77
+
78
+ ### Step 5 — Add a users table (required for the demo)
79
+
80
+ Go to `http://localhost/phpmyadmin`, select your database, and run this SQL:
81
+
82
+ ```sql
83
+ CREATE TABLE users (
84
+ id INT AUTO_INCREMENT PRIMARY KEY,
85
+ name VARCHAR(100) NOT NULL,
86
+ email VARCHAR(100) NOT NULL,
87
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
88
+ );
89
+ ```
90
+
91
+ Now the app works — add users from the browser UI, see them stored in MySQL.
92
+
93
+ ---
94
+
95
+ ## Why this is effective when you don't know code
96
+
97
+ | Problem | Solution |
98
+ |--------|----------|
99
+ | "I don't know how to set up a Node.js server" | `server.js` is pre-written with Express |
100
+ | "I don't know how to connect to MySQL" | `config/db.js` connects automatically using `.env` |
101
+ | "I don't know React or Tailwind" | `App.jsx` gives you a styled working UI |
102
+ | "I can't configure Vite" | `vite.config.js` is ready with API proxy |
103
+ | "I don't understand npm" | One command installs everything |
104
+ | "I don't know how to run two servers at once" | `concurrently` runs both with `npm run dev` |
105
+
106
+ The boilerplate handles **every configuration detail**. You focus only on:
107
+ - **Modifying the HTML/JSX** if you want to change the page layout
108
+ - **Adding SQL queries** in `routes/api.js` if you need more features
109
+ - **Changing the CSS** with Tailwind utility classes if you want different colors
110
+
111
+ Everything else works out of the box.
112
+
113
+ ---
114
+
115
+ ## Testing locally without publishing
116
+
117
+ ```bash
118
+ # From the create-butterfly-app folder
119
+ npm link
120
+ create-butterfly-app my-test
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Publishing your own version
126
+
127
+ ```bash
128
+ cd create-butterfly-app
129
+ npm login
130
+ npm publish
131
+ ```
132
+
133
+ Then anyone can run:
134
+
135
+ ```bash
136
+ npx create-butterfly-app any-project-name
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Important notes for exams
142
+
143
+ - **XAMPP must be running** before you start the app
144
+ - The `.env` file assumes default XAMPP credentials (`root` / blank password / port 3306) — change if yours is different
145
+ - The app runs on **port 5000** (backend) and **port 5173** (frontend) — make sure these are free
146
+ - If the frontend can't reach the backend, check that the proxy in `vite.config.js` matches the backend port
147
+
148
+ ---
149
+
150
+ ## License
151
+
152
+ MIT — use it for anything, including exams.
package/cli.js ADDED
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+ const { execSync } = require("child_process");
5
+
6
+ const projectName = process.argv[2] || "my-fullstack-app";
7
+ const targetDir = path.resolve(process.cwd(), projectName);
8
+ const templateDir = path.join(__dirname, "templates", "fullstack");
9
+
10
+ if (fs.existsSync(targetDir)) {
11
+ console.error(`Error: Directory "${projectName}" already exists.`);
12
+ process.exit(1);
13
+ }
14
+
15
+ console.log(`\n Creating ${projectName}...\n`);
16
+
17
+ function copyRecursive(src, dest) {
18
+ fs.mkdirSync(dest, { recursive: true });
19
+ const entries = fs.readdirSync(src, { withFileTypes: true });
20
+ for (const entry of entries) {
21
+ const srcPath = path.join(src, entry.name);
22
+ const destPath = path.join(dest, entry.name);
23
+ if (entry.isDirectory()) {
24
+ copyRecursive(srcPath, destPath);
25
+ } else {
26
+ let content = fs.readFileSync(srcPath, "utf-8");
27
+ content = content.replace(/__PROJECT_NAME__/g, projectName);
28
+ fs.writeFileSync(destPath, content);
29
+ }
30
+ }
31
+ }
32
+
33
+ copyRecursive(templateDir, targetDir);
34
+ console.log(` Created project at: ${targetDir}\n`);
35
+
36
+ try {
37
+ console.log(" Installing backend dependencies...");
38
+ execSync("npm install", { cwd: path.join(targetDir, "backend"), stdio: "inherit" });
39
+ console.log(" Installing frontend dependencies...");
40
+ execSync("npm install", { cwd: path.join(targetDir, "frontend"), stdio: "inherit" });
41
+ console.log(" Installing root dependencies...");
42
+ execSync("npm install", { cwd: targetDir, stdio: "inherit" });
43
+ } catch {
44
+ console.log("\n Run 'npm install' in each folder manually if install failed.");
45
+ }
46
+
47
+ console.log(`\n Done! Run these commands:\n`);
48
+ console.log(` cd ${projectName}`);
49
+ console.log(` npm run dev # starts both backend & frontend\n`);
package/package.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "create-butterfly-app-v2",
3
+ "version": "1.0.0",
4
+ "description": "Scaffold a full-stack Node.js + React + Tailwind + MySQL project",
5
+ "bin": {
6
+ "create-butterfly-app": "cli.js"
7
+ },
8
+ "files": [
9
+ "cli.js",
10
+ "templates/"
11
+ ],
12
+ "license": "MIT"
13
+ }
@@ -0,0 +1,13 @@
1
+ const mysql = require("mysql2/promise");
2
+
3
+ const pool = mysql.createPool({
4
+ host: process.env.DB_HOST || "localhost",
5
+ user: process.env.DB_USER || "root",
6
+ password: process.env.DB_PASSWORD || "",
7
+ database: process.env.DB_NAME || "__PROJECT_NAME__",
8
+ port: process.env.DB_PORT || 3306,
9
+ waitForConnections: true,
10
+ connectionLimit: 10,
11
+ });
12
+
13
+ module.exports = pool;
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "__PROJECT_NAME__-backend",
3
+ "private": true,
4
+ "scripts": {
5
+ "dev": "nodemon server.js"
6
+ },
7
+ "dependencies": {
8
+ "cors": "^2.8.5",
9
+ "dotenv": "^16.4.7",
10
+ "express": "^4.21.1",
11
+ "mysql2": "^3.11.5"
12
+ },
13
+ "devDependencies": {
14
+ "nodemon": "^3.1.9"
15
+ }
16
+ }
@@ -0,0 +1,26 @@
1
+ const router = require("express").Router();
2
+ const db = require("../config/db");
3
+
4
+ router.get("/users", async (req, res) => {
5
+ try {
6
+ const [rows] = await db.query("SELECT * FROM users");
7
+ res.json(rows);
8
+ } catch (err) {
9
+ res.status(500).json({ error: err.message });
10
+ }
11
+ });
12
+
13
+ router.post("/users", async (req, res) => {
14
+ const { name, email } = req.body;
15
+ try {
16
+ const [result] = await db.query(
17
+ "INSERT INTO users (name, email) VALUES (?, ?)",
18
+ [name, email]
19
+ );
20
+ res.status(201).json({ id: result.insertId, name, email });
21
+ } catch (err) {
22
+ res.status(500).json({ error: err.message });
23
+ }
24
+ });
25
+
26
+ module.exports = router;
@@ -0,0 +1,26 @@
1
+ require("dotenv").config({ path: "../.env" });
2
+ const express = require("express");
3
+ const cors = require("cors");
4
+ const db = require("./config/db");
5
+
6
+ const app = express();
7
+ const PORT = process.env.PORT || 5000;
8
+
9
+ app.use(cors());
10
+ app.use(express.json());
11
+
12
+ app.get("/api/health", (req, res) => {
13
+ res.json({ status: "ok", project: "__PROJECT_NAME__" });
14
+ });
15
+
16
+ app.use("/api", require("./routes/api"));
17
+
18
+ db.query("SELECT 1")
19
+ .then(() => {
20
+ console.log("MySQL connected");
21
+ app.listen(PORT, () => console.log(`Backend on http://localhost:${PORT}`));
22
+ })
23
+ .catch((err) => {
24
+ console.error("MySQL connection failed:", err.message);
25
+ process.exit(1);
26
+ });
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>__PROJECT_NAME__</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.jsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "__PROJECT_NAME__-frontend",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "build": "vite build",
8
+ "preview": "vite preview"
9
+ },
10
+ "dependencies": {
11
+ "react": "^19.0.0",
12
+ "react-dom": "^19.0.0"
13
+ },
14
+ "devDependencies": {
15
+ "@vitejs/plugin-react": "^4.3.4",
16
+ "autoprefixer": "^10.4.20",
17
+ "postcss": "^8.4.49",
18
+ "tailwindcss": "^3.4.17",
19
+ "vite": "^6.0.6"
20
+ }
21
+ }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
@@ -0,0 +1,86 @@
1
+ import { useState, useEffect } from "react";
2
+
3
+ function App() {
4
+ const [users, setUsers] = useState([]);
5
+ const [name, setName] = useState("");
6
+ const [email, setEmail] = useState("");
7
+ const [status, setStatus] = useState("");
8
+
9
+ useEffect(() => {
10
+ fetch("/api/health")
11
+ .then((r) => r.json())
12
+ .then((d) => setStatus(d.status))
13
+ .catch(() => setStatus("no connection"));
14
+ }, []);
15
+
16
+ useEffect(() => {
17
+ fetch("/api/users")
18
+ .then((r) => r.json())
19
+ .then(setUsers)
20
+ .catch(console.error);
21
+ }, []);
22
+
23
+ const addUser = async (e) => {
24
+ e.preventDefault();
25
+ const res = await fetch("/api/users", {
26
+ method: "POST",
27
+ headers: { "Content-Type": "application/json" },
28
+ body: JSON.stringify({ name, email }),
29
+ });
30
+ if (res.ok) {
31
+ const user = await res.json();
32
+ setUsers((prev) => [...prev, user]);
33
+ setName("");
34
+ setEmail("");
35
+ }
36
+ };
37
+
38
+ return (
39
+ <div className="min-h-screen bg-gray-100 flex flex-col items-center p-6">
40
+ <h1 className="text-4xl font-bold text-blue-600 mb-2">__PROJECT_NAME__</h1>
41
+ <p className="text-gray-500 mb-6">Backend: {status}</p>
42
+
43
+ <form onSubmit={addUser} className="flex gap-2 mb-6">
44
+ <input
45
+ className="border rounded px-3 py-2"
46
+ placeholder="Name"
47
+ value={name}
48
+ onChange={(e) => setName(e.target.value)}
49
+ required
50
+ />
51
+ <input
52
+ className="border rounded px-3 py-2"
53
+ type="email"
54
+ placeholder="Email"
55
+ value={email}
56
+ onChange={(e) => setEmail(e.target.value)}
57
+ required
58
+ />
59
+ <button className="bg-blue-600 text-white rounded px-4 py-2 hover:bg-blue-700">
60
+ Add User
61
+ </button>
62
+ </form>
63
+
64
+ <table className="w-full max-w-lg bg-white rounded shadow">
65
+ <thead>
66
+ <tr className="border-b bg-gray-50">
67
+ <th className="p-2 text-left">ID</th>
68
+ <th className="p-2 text-left">Name</th>
69
+ <th className="p-2 text-left">Email</th>
70
+ </tr>
71
+ </thead>
72
+ <tbody>
73
+ {users.map((u) => (
74
+ <tr key={u.id} className="border-b">
75
+ <td className="p-2">{u.id}</td>
76
+ <td className="p-2">{u.name}</td>
77
+ <td className="p-2">{u.email}</td>
78
+ </tr>
79
+ ))}
80
+ </tbody>
81
+ </table>
82
+ </div>
83
+ );
84
+ }
85
+
86
+ export default App;
@@ -0,0 +1,3 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
@@ -0,0 +1,10 @@
1
+ import { StrictMode } from "react";
2
+ import { createRoot } from "react-dom/client";
3
+ import App from "./App";
4
+ import "./index.css";
5
+
6
+ createRoot(document.getElementById("root")).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>
10
+ );
@@ -0,0 +1,8 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: ["./index.html", "./src/**/*.{js,jsx}"],
4
+ theme: {
5
+ extend: {},
6
+ },
7
+ plugins: [],
8
+ };
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+
4
+ export default defineConfig({
5
+ plugins: [react()],
6
+ server: {
7
+ port: 5173,
8
+ proxy: {
9
+ "/api": "http://localhost:5000",
10
+ },
11
+ },
12
+ });
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "__PROJECT_NAME__",
3
+ "private": true,
4
+ "scripts": {
5
+ "dev": "concurrently \"npm run dev --prefix backend\" \"npm run dev --prefix frontend\"",
6
+ "backend": "npm run dev --prefix backend",
7
+ "frontend": "npm run dev --prefix frontend"
8
+ },
9
+ "devDependencies": {
10
+ "concurrently": "^9.1.0"
11
+ }
12
+ }