@cvyadnik/quicknode
Version:
A CLI tool to quickly generate Node.js + Express projects with database setup
297 lines (259 loc) ⢠8.02 kB
JavaScript
#!/usr/bin/env node
import fs from "fs-extra";
import path from "path";
import inquirer from "inquirer";
import chalk from "chalk";
import { execSync } from "child_process";
import figlet from "figlet";
import shell from "shelljs";
// Display QuickNode CLI title
console.log(
chalk.blue(figlet.textSync("QuickNode", { horizontalLayout: "full" }))
);
console.log(chalk.green("\nš Welcome to QuickNode - by Chetan Yadnik\n"));
// Database options
const databases = {
mongoose: {
name: "MongoDB (Mongoose)",
package: "mongoose",
dbFile: `
const mongoose = require("mongoose");
require("dotenv").config();
const connectDB = async () => {
try {
await mongoose.connect(process.env.DB_URI, { useNewUrlParser: true, useUnifiedTopology: true });
console.log("ā
MongoDB Connected!");
} catch (error) {
console.error("ā MongoDB Connection Error:", error);
process.exit(1);
}
};
module.exports = connectDB;
`,
},
"mysql2 sequelize": {
name: "MySQL (Sequelize)",
package: "mysql2 sequelize",
dbFile: `
const { Sequelize } = require("sequelize");
require("dotenv").config();
const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASS, {
host: process.env.DB_HOST,
dialect: "mysql",
logging: false
});
module.exports = sequelize;
`,
},
"pg pg-hstore sequelize": {
name: "PostgreSQL (Sequelize)",
package: "pg pg-hstore sequelize",
dbFile: `
const { Sequelize } = require("sequelize");
require("dotenv").config();
const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASS, {
host: process.env.DB_HOST,
dialect: "postgres",
logging: false
});
module.exports = sequelize;
`,
},
"sqlite3 sequelize": {
name: "SQLite (Sequelize)",
package: "sqlite3 sequelize",
dbFile: `
const { Sequelize } = require("sequelize");
require("dotenv").config();
const sequelize = new Sequelize({
dialect: "sqlite",
storage: "./database.sqlite",
logging: false
});
module.exports = sequelize;
`,
},
};
// Prompt user for project details
inquirer
.prompt([
{
type: "input",
name: "projectName",
message: "š Enter your project name:",
validate: (input) => (input ? true : "Project name cannot be empty!"),
},
{
type: "list",
name: "database",
message: "š¢ Select a database:",
choices: Object.values(databases).map((db) => ({
name: db.name,
value: db.package,
})),
},
])
.then(({ projectName, database }) => {
const projectPath = path.join(process.cwd(), projectName);
if (fs.existsSync(projectPath)) {
console.log(chalk.red("ā Project already exists! Choose another name."));
process.exit(1);
}
console.log(chalk.yellow("\nš§ Setting up project structure...\n"));
// Folder Structure
const folders = [
"src",
"src/config",
"src/controllers",
"src/models",
"src/routes",
"src/services",
"src/middlewares",
"src/utils",
"src/validations",
"src/logs",
"tests",
];
shell.mkdir(
"-p",
folders.map((folder) => path.join(projectPath, folder))
);
// Create package.json
const packageJson = {
name: projectName,
version: "1.0.0",
main: "src/server.js",
scripts: {
start: "node src/server.js",
dev: "nodemon src/server.js",
},
dependencies: {
express: "^4.18.2",
dotenv: "^16.3.1",
cors: "^2.8.5",
helmet: "^7.1.1",
jsonwebtoken: "^9.0.0",
bcryptjs: "^2.4.3",
joi: "^17.8.4",
nodemon: "^2.0.15",
},
};
const dbPackages = database.split(" "); // Split the database string into an array
dbPackages.forEach((pkg) => (packageJson.dependencies[pkg] = "*"));
fs.writeFileSync(
path.join(projectPath, "package.json"),
JSON.stringify(packageJson, null, 2)
);
// Create .env file
const envFile = `
# Environment Variables - Created by QuickNode by Chetan Yadnik
PORT=5000
DB_URI=mongodb://localhost:27017/${projectName}
DB_HOST=localhost
DB_USER=root
DB_PASS=
DB_NAME=${projectName}_db
`;
fs.writeFileSync(path.join(projectPath, ".env"), envFile.trim());
// ā
Create db.js based on selected database
fs.writeFileSync(
path.join(projectPath, "src/config/db.js"),
databases[database].dbFile.trim()
);
// ā
Create app.js inside src/
fs.writeFileSync(
path.join(projectPath, "src/app.js"),
`
/**
* Express App Setup - by Chetan Yadnik
*/
const express = require("express");
const cors = require("cors");
const helmet = require("helmet");
const userRoutes = require("./routes/userRoutes");
const errorHandler = require("./middlewares/errorHandler");
const app = express();
app.use(express.json());
app.use(cors());
app.use(helmet());
app.use("/api", userRoutes);
app.use(errorHandler);
module.exports = app;
`.trim()
);
// ā
Ensure `userRoutes.js` is created inside `src/routes/`
fs.mkdirSync(path.join(projectPath, "src/routes"), { recursive: true });
fs.writeFileSync(
path.join(projectPath, "src/routes/userRoutes.js"),
`
const express = require("express");
const { getUsers } = require("../controllers/userController");
const router = express.Router();
router.get("/", getUsers);
module.exports = router;
`.trim()
);
// ā
Ensure correct path in server.js
fs.writeFileSync(
path.join(projectPath, "src/server.js"),
`
/**
* Express Server - by Chetan Yadnik
*/
const express = require("express");
require("dotenv").config();
const path = require("path");
const app = require(path.join(__dirname, "./app")); // ā
Fixed path
const sequelize = require("./config/db");
const PORT = process.env.PORT || 5000;
sequelize.sync().then(() => {
console.log("ā
Database synced successfully.");
app.listen(PORT, () => console.log(\`š Server running on http://localhost:\${PORT}\`));
}).catch(error => {
console.error("ā Database connection failed:", error);
});
`.trim()
);
// ā
Create errorHandler.js
fs.writeFileSync(
path.join(projectPath, "src/middlewares/errorHandler.js"),
`
/**
* Global Error Handler - by Chetan Yadnik
*/
const errorHandler = (err, req, res, next) => {
console.error("ā Error:", err.stack);
res.status(err.status || 500).json({
success: false,
message: err.message || "Internal Server Error",
});
};
module.exports = errorHandler;
`.trim()
);
// ā
Ensure `userController.js` is created inside `src/controllers/`
fs.mkdirSync(path.join(projectPath, "src/controllers"), {
recursive: true,
});
fs.writeFileSync(
path.join(projectPath, "src/controllers/userController.js"),
`
exports.getUsers = (req, res) => {
res.json({ message: "Welcome to QuickNode API!", author: "Chetan Yadnik" });
};
`.trim()
);
console.log(chalk.blue("\nš¦ Installing dependencies...\n"));
try {
execSync(`npm install`, { cwd: projectPath, stdio: "inherit" });
console.log(chalk.green("\nā
Dependencies installed successfully!"));
} catch (error) {
console.error(chalk.red("ā Error installing dependencies:"), error);
}
console.log(chalk.green("\nš Setup Complete!"));
console.log(chalk.yellow(`š cd ${projectName} && npm run dev`));
console.log(
chalk.yellow("š Start building your API with QuickNode - by Chetan Yadnik!")
);
})
.catch((error) => console.error(chalk.red("ā Error:", error)));