最佳实践初始化项目公用cli

package.json入口实现

js 复制代码
{
  "name": "xxx-cli",
  "version": "1.0.0",
  "description": "Command line interface for rapid project development",
  "bin": {
    "xxx-cli": "bin/cli.mjs"
  },
  "repository": {
    "type": "git",
    "url": "git+https://git地址"
  },
  "keywords": [
    "cli"
  ],
  "author": "",
  "license": "MIT",
  "bugs": {
    "url": "https://git地址/issues"
  },
  "engines": {
    "node": ">= 14.18.0"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "chalk": "^5.0.1",
    "child_process": "^1.0.2",
    "commander": "^9.4.0",
    "compressing": "^1.7.0",
    "figlet": "^1.5.2",
    "fs-extra": "^10.1.0",
    "inquirer": "^9.1.0",
    "ora": "^6.1.2",
    "semver": "^7.3.7",
    "shelljs": "^0.8.5"
  }
}

bin/cli.mjs内部实现

js 复制代码
#!/usr/bin/env node
// `#!/usr/bin/env node`:指定使用 Node.js 执行此脚本。

// 导入需要的模块
import { readFile } from 'fs/promises'; // 异步文件读取
import chalk from 'chalk'; // 控制台文本样式
import semverSatisfies from 'semver/functions/satisfies.js'; // 版本比较
import { program } from 'commander'; // 命令行参数解析
import create from '../lib/create.mjs'; // 创建项目命令

const CLI_NAME = 'xxx-cli';

// 读取 package.json 获取 Node 版本要求和 CLI 版本
const { engines: { node: requiredVersion }, version } = JSON.parse(
    await readFile(
        new URL('../package.json', import.meta.url)
    )
);

// 检查 Node 版本是否满足要求
function checkNodeVersion(wanted, id) {
    if (!semverSatisfies(process.version, wanted, { includePrerelease: true })) {
        console.log(chalk.red(
            'You are using Node ' + process.version + ', but this version of ' + id +
            ' requires Node ' + wanted + '.\nPlease upgrade your Node version.'
        ));
        process.exit(1); // 退出程序
    }
}

// 执行 Node 版本检查
checkNodeVersion(requiredVersion, CLI_NAME);

// 初始化 commander 程序
program
    .name(CLI_NAME) // CLI 工具名称
    .version(version); // CLI 工具版本

// 定义 create 命令
program
    .command('create <app-name>') // 命令名称和参数
    .description('create a new project powered by xxx-cli') // 命令描述
    .option("-f, --force", "overwrite target directory if it exists") // 命令选项
    .action((name, options) => { // 命令执行函数
        console.log(chalk.cyan(`Creating project: ${name}`));
        create(name, options); // 调用 create 函数
    });

// 解析命令行参数
program.parse(process.argv);

lib/create.mjs内部实现

js 复制代码
import ora from 'ora';
import chalk from 'chalk'
import fse from 'fs-extra'
import shelljs from 'shelljs'
import path from 'path'
import inquirer from 'inquirer'

const PROJECT_TYPES = [ 
  { name: 'pc', value: 'pc' }, 
  { name: 'h5', value: 'h5' }, 
]; 
const PROJECT_MAP = { 
  pc: 'pc最佳实践git地址', 
  h5: 'h5最佳实践git地址', 
};

async function create(projectName, options) {
  const progress = ora('创建中...')
  const targetDirectory = path.join(process.cwd(), projectName)
  try {
    // 判断是否存在git,不存在则提示并退出
    if (!shelljs.which('git')) {
      console(chalk.red('Sorry, xxx-cli requires git'));
      return
    }
    const isExist = await fse.pathExists(targetDirectory)
    // 判断目录下是否存在同名文件夹
    if (isExist) {
      // 如果有 --force 选项,则删除已存在的目录
      if (options.force) {
        await fse.remove(targetDirectory);
      } else {
        const { isOverwrite } = await new inquirer.prompt([
          {
            name: "isOverwrite", // 与返回值对应
            type: "list",
            message: "目标目录已存在,请选择操作:",
            choices: [
              { name: "Overwrite", value: true },
              { name: "Cancel", value: false },
            ],
          },
        ]);
        // 移除同名文件夹
        if (isOverwrite) {
          console.log('remove existing directory...')
          await fse.remove(targetDirectory);
        } else {
          return;
        }
      }
    }
    // 项目类型
    const { projectType } = await new inquirer.prompt([
      {
        name: "projectType", // 与返回值对应
        type: "list",
        message: "Please select project type:",
        choices: PROJECT_TYPES,
      },
    ]);

    // 安装依赖项目
    shelljs.exec(`git clone ${PROJECT_MAP[projectType]} ${projectName}`, async (code, stdout, stderr) => {
      if (code === 0) {
        progress.start()
        try {
          // 删除原有.git
          await fse.remove(path.join(process.cwd(), projectName, '.git'))
        } catch (error) {
          console.log(error)
        }
        progress.succeed()
        console.log(`\r\nSuccessfully created project ${chalk.cyan(projectName)}`);
        console.log(`\r\n  cd ${chalk.cyan(projectName)}`);
        console.log("  git init");
        console.log("  pnpm install");
          console.log("  pnpm dev");
      }
    })
  } catch (error) {
    progress.fail(chalk.red('创建项目失败:', error));
    console.log(error);
  }
}

export default create
相关推荐
山河故人1635 分钟前
uniapp使用npm下载
前端·npm·uni-app
-曾牛30 分钟前
基于微信小程序的在线聊天功能实现:WebSocket通信实战
前端·后端·websocket·网络协议·微信小程序·小程序·notepad++
一口一个橘子1 小时前
[ctfshow web入门] web72
前端·web安全·网络安全
Web极客码1 小时前
如何使用WordPress SEO检查器进行实时内容分析
前端·seo·wordpress
Stella25211 小时前
【Vue】CSS3实现关键帧动画
前端·vue.js·css3
junjun.chen06061 小时前
【在qiankun模式下el-dropdown点击,浏览器报Failed to execute ‘getComputedStyle‘ on ‘Window‘: parameter 1 is not o
前端·javascript·前端框架
Yvonne爱编码1 小时前
HTML-3.3 表格布局(学校官网简易布局实例)
前端·html·github·html5·hbuilder
jllllyuz2 小时前
matlab实现蚁群算法解决公交车路径规划问题
服务器·前端·数据库
小屁孩大帅-杨一凡3 小时前
一个简单点的js的h5页面实现地铁快跑的小游戏
开发语言·前端·javascript·css·html
读心悦3 小时前
CSS 布局系统深度解析:从传统到现代的布局方案
前端·css