UNPKG

initia-devaxis

Version:

CLI to create full-stack React projects with Next.js (REST) or RedwoodJS (GraphQL)

381 lines (366 loc) 14.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createNextProject = createNextProject; const chalk_1 = __importDefault(require("chalk")); const child_process_1 = require("child_process"); const fs_1 = require("fs"); const promises_1 = require("fs/promises"); const os_1 = require("os"); const path_1 = require("path"); /** * Crée un nouveau projet Next.js avec la configuration spécifiée */ /** * Vérifie que le gestionnaire de paquets est disponible */ async function checkPackageManagerAvailability(packageManager) { try { // Exécuter la vérification dans le répertoire home pour éviter les conflits await executeCommandSilent(packageManager, ["--version"], { cwd: (0, os_1.homedir)(), }); } catch (error) { throw new Error(` ${packageManager} is not installed or not available in PATH. Please install ${packageManager} before creating a project: - npm: comes with Node.js - yarn: npm install -g yarn - pnpm: npm install -g pnpm `); } } async function createNextProject(config) { const packageManager = config.packageManager || "npm"; // Vérifier que le gestionnaire de paquets est disponible await checkPackageManagerAvailability(packageManager); const args = [ "create-next-app@latest", config.name, "--src-dir", "--app", "--import-alias", "@/*", ]; if (config.typescript) { args.push("--typescript"); } else { args.push("--javascript"); } if (config.eslint) { args.push("--eslint"); } else { args.push("--no-eslint"); } if (config.tailwind) { args.push("--tailwind"); } else { args.push("--no-tailwind"); } if (packageManager === "yarn") { args.push("--use-yarn"); } else if (packageManager === "pnpm") { args.push("--use-pnpm"); } else { args.push("--use-npm"); } args.push("--skip-install"); try { // Utiliser le bon exécuteur selon le gestionnaire de paquets const executor = packageManager === "pnpm" ? "pnpm" : packageManager === "yarn" ? "yarn" : "npx"; const execArgs = packageManager === "pnpm" ? ["dlx", ...args] : packageManager === "yarn" ? ["create", ...args.slice(1)] // remove "create-next-app@latest", keep the rest : args; await executeCommandSilent(executor, execArgs); // Si pnpm est choisi, supprimer les fichiers yarn qui pourraient causer des conflits if (packageManager === "pnpm") { try { const projectPath = (0, path_1.join)(process.cwd(), config.name); // Supprimer les fichiers yarn qui pourraient interférer const yarnFiles = [".yarnrc.yml", ".yarnrc", "yarn.lock"]; for (const file of yarnFiles) { const filePath = (0, path_1.join)(projectPath, file); if ((0, fs_1.existsSync)(filePath)) { await (0, promises_1.unlink)(filePath); } } } catch (cleanupError) { // Ignorer les erreurs de nettoyage } } const installCommand = packageManager === "npm" ? "install" : packageManager === "yarn" ? "install" : "install"; await executeCommandSilent(packageManager, [installCommand], { cwd: config.name, }); // Configuration post-création if (config.prettier) { await setupPrettier(config.name, config.typescript, packageManager); } if (config.eslint) { await enhanceESLintConfig(config.name, config.typescript, config.prettier); } await createReadme(config, packageManager); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); // Afficher l'erreur dans un joli cadre rouge const maxLength = 65; const lines = errorMessage.match(/.{1,60}/g) || [errorMessage]; const errorBox = ` ╭─── ❌ NEXT.JS PROJECT CREATION FAILED ───────────────────────────╮ │ │ ${lines.map((line) => `│ ${line.padEnd(maxLength - 2)} │`).join("\n")} │ │ ╰───────────────────────────────────────────────────────────────────╯ `; console.error(chalk_1.default.red(errorBox)); throw new Error(`Failed to create Next.js project: ${errorMessage}`); } } /** * Exécute une commande silencieusement mais capture les erreurs pour debugging */ function executeCommandSilent(command, args, options) { return new Promise((resolve, reject) => { const fullCommand = `${command} ${args.join(" ")}`; const child = (0, child_process_1.spawn)(command, args, { stdio: ["inherit", "pipe", "pipe"], // Capture stdout et stderr pour debugging shell: true, cwd: options?.cwd, env: { ...process.env, NPM_CONFIG_LOGLEVEL: "silent", NPM_CONFIG_PROGRESS: "false", NPM_CONFIG_AUDIT: "false", NPM_CONFIG_FUND: "false", NPM_CONFIG_UPDATE_NOTIFIER: "false", // Variables pour forcer pnpm malgré la configuration yarn PNPM_IGNORE_PNPMFILE: "true", PNPM_SHAMEFULLY_HOIST: "true", // Supprimer les variables yarn qui pourraient interférer YARN_IGNORE_PATH: "1", YARN_IGNORE_CWD: "1", CI: "true", DISABLE_OPENCOLLECTIVE: "true", ADBLOCK: "true", }, }); let stdout = ""; let stderr = ""; // Capturer stdout et stderr sans les afficher child.stdout?.on("data", (data) => { stdout += data.toString(); }); child.stderr?.on("data", (data) => { stderr += data.toString(); }); const timeout = setTimeout(() => { child.kill("SIGTERM"); reject(new Error("Command timed out")); }, 300000); // 5 minutes child.on("close", (code) => { clearTimeout(timeout); if (code === 0) { resolve(); } else { // Créer un message d'erreur détaillé et bien visible const errorBox = ` ╭─── ❌ COMMAND FAILED ─────────────────────────────────────────────╮ │ │ │ Command: ${fullCommand} │ Exit Code: ${code} │ │ ${stderr ? `│ Error Output: │ │ ${stderr .split("\n") .slice(0, 5) .map((line) => ` ${line}`.padEnd(65)) .join("\n│")}\n│ │` : ""} ${stdout && stdout.trim() ? `│ Standard Output: │ │ ${stdout .split("\n") .slice(0, 3) .map((line) => ` ${line}`.padEnd(65)) .join("\n│")}\n│ │` : ""} ╰───────────────────────────────────────────────────────────────────╯ `; console.error(chalk_1.default.red(errorBox)); // Inclure l'erreur réelle dans le message d'exception const realError = stderr || stdout || `Exit code ${code}`; reject(new Error(realError.split("\n")[0])); // Première ligne de l'erreur réelle } }); child.on("error", (error) => { clearTimeout(timeout); console.error(`Spawn error for command: ${fullCommand}`, error); reject(new Error(`Execution error: ${error.message}`)); }); }); } /** * Configure Prettier pour le projet Next.js */ async function setupPrettier(projectName, typescript, packageManager = "npm") { const projectPath = (0, path_1.join)(process.cwd(), projectName); // Configuration Prettier const prettierConfig = { semi: false, singleQuote: true, trailingComma: "es5", tabWidth: 2, printWidth: 80, endOfLine: "lf", }; // Fichier .prettierrc.json await (0, promises_1.writeFile)((0, path_1.join)(projectPath, ".prettierrc.json"), JSON.stringify(prettierConfig, null, 2)); // Fichier .prettierignore const prettierIgnore = ` node_modules .next out dist *.log .DS_Store .env* public *.lock package-lock.json yarn.lock pnpm-lock.yaml `.trim(); await (0, promises_1.writeFile)((0, path_1.join)(projectPath, ".prettierignore"), prettierIgnore); // Installation des dépendances Prettier en mode silencieux const devDeps = [ "prettier", "eslint-config-prettier", "eslint-plugin-prettier", ]; const devInstallArgs = packageManager === "npm" ? ["install", "--save-dev", ...devDeps] : packageManager === "yarn" ? ["add", "--dev", ...devDeps] : ["add", "--save-dev", ...devDeps]; await executeCommandSilent(packageManager, devInstallArgs, { cwd: projectPath, }); // Mise à jour du package.json avec les scripts const packageJsonPath = (0, path_1.join)(projectPath, "package.json"); const packageJson = JSON.parse(await (0, promises_1.readFile)(packageJsonPath, "utf-8")); packageJson.scripts = { ...packageJson.scripts, format: "prettier --write .", "format:check": "prettier --check .", "lint:fix": "next lint --fix", }; await (0, promises_1.writeFile)(packageJsonPath, JSON.stringify(packageJson, null, 2)); } /** * Améliore la configuration ESLint */ async function enhanceESLintConfig(projectName, typescript, prettier) { const projectPath = (0, path_1.join)(process.cwd(), projectName); const eslintConfigPath = (0, path_1.join)(projectPath, ".eslintrc.json"); let eslintConfig = { extends: ["next/core-web-vitals", "eslint:recommended"], rules: { "react/no-unescaped-entities": "off", "@next/next/no-page-custom-font": "off", }, }; if (typescript) { eslintConfig.extends.push("@typescript-eslint/recommended"); } if (prettier) { eslintConfig.extends.push("prettier"); eslintConfig.rules = { ...eslintConfig.rules, "prettier/prettier": "error", }; } await (0, promises_1.writeFile)(eslintConfigPath, JSON.stringify(eslintConfig, null, 2)); } /** * Crée un README personnalisé pour le projet */ async function createReadme(config, packageManager = "npm") { const projectPath = (0, path_1.join)(process.cwd(), config.name); const readme = `# ${config.name} This project was created with [INITIA CLI](https://github.com/your-username/initia) using **${config.framework}**. ## 🚀 Quick Start Install dependencies: \`\`\`bash ${packageManager} ${packageManager === "npm" ? "install" : packageManager === "yarn" ? "install" : "install"} \`\`\` Run the development server: \`\`\`bash ${packageManager} run dev \`\`\` Open [http://localhost:3000](http://localhost:3000) in your browser. ## 📁 Project Structure \`\`\` ${config.name}/ ├── src/ │ ├── app/ # App Router (Next.js 13+) │ ├── components/ # Reusable components │ └── styles/ # CSS files ├── public/ # Static assets └── ... \`\`\` ## 🛠️ Available Scripts - \`${packageManager} run dev\` - Start development server - \`${packageManager} run build\` - Build for production - \`${packageManager} run start\` - Start production server - \`${packageManager} run lint\` - Run ESLint${config.prettier ? `\n- \`${packageManager} run format\` - Format code with Prettier\n- \`${packageManager} run format:check\` - Check formatting` : ""} ## 🔧 Configuration ### Technologies used: - ⚡ **Next.js** - React framework ${config.typescript ? "- 🔷 **TypeScript** - Static typing" : "- 📜 **JavaScript** - Base language"} ${config.eslint ? "- 🔍 **ESLint** - Code linting" : ""} ${config.prettier ? "- 💅 **Prettier** - Code formatting" : ""} ${config.tailwind ? "- 🎨 **Tailwind CSS** - Utility-first CSS framework" : ""} ## 📚 Documentation - [Next.js Documentation](https://nextjs.org/docs) ${config.typescript ? "- [TypeScript Documentation](https://www.typescriptlang.org/docs/)" : ""} ${config.tailwind ? "- [Tailwind CSS Documentation](https://tailwindcss.com/docs)" : ""} --- ✨ **Generated by INITIA CLI** - For an optimal development experience `; await (0, promises_1.writeFile)((0, path_1.join)(projectPath, "README.md"), readme); } //# sourceMappingURL=nextjs.js.map