当前位置: 首页 > news >正文

Node.js命令行工具开发

文章目录

  • Node.js命令行工具开发
    • 实例效果展示
    • 初始化项目
    • 基本结构
    • 配置package.json
    • 创建启动文件
    • 创建入口文件及其它配置文件
      • 1.lib/index.js 入口文件
      • 2.lib/theme.js 封装打印带样式的文本到终端的函数
      • 3.lib/utlis.js 复用模块封装
      • 4.lib/create-cli.js cli创建逻辑
      • 5.lib/create-uni.js uni项目模板创建
    • 命令行工具测试
    • 版本管理
    • 发布npm
      • 发布完成测试
    • 各包的用途
      • commander
        • 核心功能
          • 1. 定义命令和选项
          • 1.自动生成的帮助信息
        • 核心概念
          • 1. 选项(Options)
          • 2. 命令(Commands)
          • 3. 子命令(Subcommands)
        • 实际应用场景
          • 1. 创建脚手架工具(如`create-react-app`)
          • 2. 构建开发服务器
      • chalk
        • 核心功能
          • 1. 改变文字颜色
          • 2. 改变背景色
          • 3. 添加文本样式
          • 4. 链式调用
          • 5.**256色和RGB支持**
        • 实际应用场景
        • 高级用法
          • 1.自定义主题函数
          • 2. 组合使用模板字符串
      • ora
        • 核心功能
          • 1. 基本用法
          • 2. 状态变化效果
          • 3.**丰富的预设动画**:包含超过30种动画效果
          • 4.**颜色支持**:与chalk完美配合
          • 5.**速度控制**:调整动画刷新率
          • 6.**多行文本支持**
        • 实际应用场景
          • 1. 文件下载进度
          • 2. 安装依赖
        • 高级用法
          • 1. 自定义动画
          • 2. 组合进度条
          • 3. 动态更新文本
      • inquirer

Node.js命令行工具开发

  • 开发一个类似npm create vite@latestnpx xxx这样的Node.js命令行工具

实例效果展示

  • 模板提供了两个简单的列子
    • 1.创建一个命令行工具模板项目,也就是当前这个项目的源代码
    • 2.从远程拉取创建一个uniapp的模板项目
  • 先全局安装
npm i -g rxm-node-cli
# 安装完成后
# 安装完成后 执行命令行工具,先不指定模板,会通过命令行交互选择模板
rxm-node-cli create project-name
# 或者 
npx rxm-node-cli create project-name
# 指定模板
npx rxm-node-cli create project-name -t cli-template
npx rxm-node-cli create project-name -t uni-template
  • npm地址:https://www.npmjs.com/package/rxm-node-cli
  • 源码地址:https://gitee.com/public_12/node-cli-template
  • 博文地址:https://blog.csdn.net/weixin_43376417/article/details/152220237?spm=1011.2415.3001.5331

初始化项目

mkdir rxm-node-cli-tool
cd rxm-node-cli-tool
npm init -y

基本结构

rxm-node-cli-tool/
├── bin/
│   └── cli.js        # 命令行入口文件
├── lib/
│   └── index.js      # 主要逻辑代码
├── package.json
└── README.md

配置package.json

  • bin下的rxm-node-cli就是命令行工具名称
{"name": "rxm-node-cli","version": "1.0.3","bin": {"rxm-node-cli": "./bin/cli.js"},"scripts": {"dev": "node bin/cli.js create","upgrade": "standard-version"},"standard-version": {"message": "docs: %s [skip ci]"},"dependencies": {"chalk": "^4.1.0","commander": "^9.0.0","download-git-repo": "^3.0.2","fs-extra": "^11.3.2","inquirer": "^8.0.0"},"devDependencies": {"standard-version": "^9.5.0"}
}

创建启动文件

  • 根目录下创建 bin/cli.js
#!/usr/bin/env nodeconst { program } = require('commander');
const pkg = require('../package.json');
program.name('rxm-node-cli').description('cli命令行开发模板');
program.version(pkg.version).command('create <project-name>').description('创建一个新项目').option('-t, --template <name>', '指定模板') // 子命令可以配置多个,多次调用option方法即可。得到的option对象会合并.action((name,options) => {require('../lib/index')({name,template:options.template});});program.parse(process.argv); // process.argv是启动命令行时传入的参数数组

创建入口文件及其它配置文件

1.lib/index.js 入口文件

// lib/index.js 
const tool = require('./create-cli.js');
const uni = require('./create-uni')
const theme = require('./theme');
const inquirer = require('inquirer');module.exports = async function ({ name: projectName, template }) {if (!projectName) return theme.error('请输入项目名称')if (!template) {const { action } = await inquirer.prompt([{name: 'action',type: 'list',message: '请选择模板类型:',choices: [{ name: 'cli-template', value: 'cli-template' },{ name: 'uni-template', value: 'uni-template' }]}]);template = action}if (template === 'cli-template') return tool(projectName)if (template === 'uni-template') return uni(projectName)theme.error('模板不存在')
};

2.lib/theme.js 封装打印带样式的文本到终端的函数

// lib/theme.js
const chalk = require('chalk');module.exports = {error: text=>{console.log(chalk.red.bold(text))},success: text=>{console.log(chalk.green(text))},successBold: text=>{console.log(chalk.bold.green(text))},warning: text=>{console.log(chalk.yellow.underline(text))}
};

3.lib/utlis.js 复用模块封装

const inquirer = require('inquirer');
const fs = require('fs');
const pfs = require('fs-extra');
const theme = require('./theme');module.exports = {/*** 创建前*/async beforCreate(projectName) {const { action } = await inquirer.prompt([{name: 'action',type: 'list',message: '是否开始创建:',choices: [{ name: '是', value: 'yes' },{ name: '否', value: false }]}]);if (!action) returntheme.success(`创建项目: ${projectName}`)// 检查目录是否已存在if (fs.existsSync(projectName)) {// 交互式询问用户是否覆盖const { action } = await inquirer.prompt([{name: 'action',type: 'list',message: '目录已存在,请选择:',choices: [{ name: '覆盖', value: 'overwrite' },{ name: '取消', value: false }]}]);// action等于 choices选择的valueif (!action) return;if (action === 'overwrite') {console.log(`\n删除 ${projectName}...`);// 删除目录fs.rmSync(projectName, { recursive: true, force: true });}}// 创建项目目录fs.mkdirSync(projectName);return true},/*** initJson*/initJson(projectName) {const json = require('../package.json')json.name = projectNamejson.version = '1.0.0'console.log('创建package.json...')return pfs.outputFile(`${projectName}/package.json`,JSON.stringify(json, null, 2));}
}

4.lib/create-cli.js cli创建逻辑

const path = require('path');
const fs = require('fs');
const pfs = require('fs-extra');
const theme = require('./theme');
const utlis = require('./utlis');
const basePath = path.join(__dirname, '../')
// 拷贝目录
async function copyDirectorySync (src, projectName) {await pfs.ensureDir(projectName+'/'+src);const url = path.join(basePath, src)// 读取源目录内容const items = fs.readdirSync(url);for (const item of items) {pfs.outputFile(`${projectName}/${src}/${item}`,fs.readFileSync(path.join(url, item), 'utf-8'))}
}
module.exports = async function (projectName) {await utlis.beforCreate(projectName)await pfs.ensureDir(projectName);await utlis.initJson(projectName)await copyDirectorySync('lib', projectName)await copyDirectorySync('bin', projectName)// 拷贝 README.mdpfs.outputFile(`${projectName}/README.md`,fs.readFileSync(path.join(basePath, 'README.md'), 'utf-8'))theme.success('\n项目创建成功')theme.successBold(`cd ${projectName}`)theme.successBold(`npm install`)
}

5.lib/create-uni.js uni项目模板创建

// lib/create-uni.js 
const path = require('path');
const fs = require('fs');
const theme = require('./theme');
const utlis = require('./utlis');
const { promisify } = require('util');
const download = promisify(require('download-git-repo'));
const ora = require('ora');
const chalk = require('chalk');module.exports = async function (projectName) {await utlis.beforCreate(projectName);const spinner = ora('正在创建项目...').start();try {spinner.text = '正在下载模板...';// 确保使用绝对路径const projectPath = path.resolve(process.cwd(), projectName);await download('direct:https://gitee.com/ren_jinming/uniapp-vue3-ts-uview-plus.git', projectPath, { clone: true });console.log('下载完成');// 修改package.jsonspinner.text = '正在修改package.json...';const packageJsonPath = path.join(projectPath, 'package.json');// 检查文件是否存在if (!fs.existsSync(packageJsonPath)) {throw new Error(`package.json not found at ${packageJsonPath}`);}// 读取并修改package.jsonconst packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));packageJson.name = projectName;// 写入修改后的内容fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');console.log('修改完成');spinner.succeed(chalk.green('项目创建成功!'));theme.successBold(`cd ${projectName}`);theme.successBold(`npm install`);console.log('使用Hbuild X打开项目')} catch (error) {console.error(error);spinner.warn('项目创建失败');}
}

命令行工具测试

  • 本地测试
# cli-test作为创建项目的名称
npm run dev cli-test
  • 将命令行工具链接到全局测试
# 安装
npm link
# 如果上面的命令报错可以换一个
npm link --force
# 查看支持哪些命令
rxm-node-cli
# 运行命令行 查询版本
rxm-node-cli -V
# 创建指定的模板
rxm-node-cli create text-project -t cli-template
rxm-node-cli create text-project -t uni-template
# 不指定模板,通过命令行选择
rxm-node-cli create text-project
# 或者用npx 的形式执行
npx rxm-node-cli create text-project

版本管理

  • 安装 standard-version 用于版本管理:
npm install -D standard-version
  • 更新 package.json 配置升级命令及提交msg
{"scripts": {"upgrade": "standard-version"},"standard-version":{"message": "docs: %s [skip ci]"},
}
  • 推荐自动升级方案 会根据 Git 提交记录自动升级版本号,也可以手动设置版本
pnpm upgrade
# 或者
npx standard-version
# 它会读取git的提交信息 并将相关的记录写入到 CHANGELOG.md

发布npm

  • 如果还没有npm账号可以先去注册一个 :https://www.npmjs.com/signup
  • 登录npm
# 执行
npm login
# 在终端输入账号
Username: xxxx (回车)
# 输入密码
Password: xxxx (这里输入密码终端是没有交互反馈的,所以只要确认输入完直接回车)
# 输入邮箱会发送验证码
Email: (this IS public): xxx 回车
# 输入邮箱验证码
Enter one-time password: xxxx 回车
# 登录成功后显示 Logged in as renjinming on https://registry.npmjs.org/.# 模拟发布
npm pack --dry-run
# 执行后会打印出要上传的信息 如下:
Debugger attached.
npm notice 
npm notice 📦  rxm-node-cli@1.0.4
npm notice === Tarball Contents === 
npm notice 503B  CHANGELOG.md     
npm notice 596B  README.md        
npm notice 622B  bin/cli.js       
npm notice 1.1kB lib/create-cli.js
npm notice 1.6kB lib/create-uni.js
npm notice 788B  lib/index.js     
npm notice 312B  lib/theme.js     
npm notice 1.6kB lib/utlis.js     
npm notice 481B  package.json     
npm notice === Tarball Details === 
npm notice name:          rxm-node-cli
npm notice version:       1.0.4
npm notice filename:      rxm-node-cli-1.0.4.tgz
npm notice package size:  3.0 kB
npm notice unpacked size: 7.6 kB
npm notice shasum:        2efbb29c6d3731a2abb6333b386f39526b8d1e69
npm notice integrity:     sha512-BrixVR69X/dJd[...]Brt8xuFQWYwnQ==
npm notice total files:   9
npm notice 
rxm-node-cli-1.0.4.tgz
Waiting for the debugger to disconnect...
# 实际发布
npm publish
#如果版本号以存在,须要修改版本信息,不然提交会403 执行上面的升级命令在进行发布
➔ 若包名冲突或无权限,会报错。
  • 发布403错误

如果发布403可能是包名已经存在。可以用下面的命令试试看有没有,如果存在可以修改package.json的name重新定义包名

npm view rxm-node-cli   # 检查包名占用

发布完成测试

  • 发布成功验证
# 查询包在npm上的所有版本
npm view rxm-node-cli versions
  • 安装使用
npm i -g rxm-node-cli
# 安装完成后 执行命令行工具
rxm-node-cli create project-name
# 或者 
npx rxm-node-cli create project-name
# 指定模板
npx rxm-node-cli create project-name -t cli-template
npx rxm-node-cli create project-name -t uni-template

各包的用途

commander

  • commander 是 Node.js 最流行的命令行工具开发框架,用于快速构建 CLI(Command Line Interface)应用程序。它可以实现如下功能:
  1. 解析命令行参数(选项、子命令等)
  2. 自动生成帮助信息--help
  3. 提供用户友好的命令行交互体验
核心功能
1. 定义命令和选项
// app.js
const { program } = require('commander');program.name('rxm-node-cli')                     // 工具名称.description('一个示例CLI工具')       // 描述.version('1.0.0');                   // 版本号program.command('create <project-name>')    // 定义子命令.description('创建新项目')           // 命令描述.option('-t, --template <name>', '指定模板') // 命令选项 // 子命令可以配置多个,多次调用option方法即可。得到的option对象会合并.action((name, options) => {         // 执行逻辑console.log(`创建项目 ${name},使用模板: ${options.template || '默认'}`);});program.parse(); // 必须调用// 运行 node app.js create my-project -t vue
// 输出 创建项目 my-project,使用模板: vue
1.自动生成的帮助信息
  • 运行时会自动添加 -h, --help 选项:
node app.js --help
  • 输出示例:
Usage: rxm-node-cli [options] [command]一个示例CLI工具Options:-V, --version           输出版本号-h, --help              显示帮助信息Commands:create <project-name>   创建新项目help [command]          显示命令帮助
核心概念
1. 选项(Options)
program.option('-d, --debug', '开启调试模式')       // 布尔选项.option('-p, --port <number>', '端口号', 80) // 带默认值的选项.option('-c, --config <path>', '配置文件');  // 必填选项
2. 命令(Commands)
program.command('add <file>')            // 必需参数.description('添加文件').action((file) => {console.log(`添加文件: ${file}`);});
3. 子命令(Subcommands)
program.command('server').description('服务器操作').command('start')                // 子命令.action(() => {console.log('启动服务器');});
实际应用场景
1. 创建脚手架工具(如create-react-app
program.command('create <app-name>').description('创建新应用').action((name) => {// 下载模板、初始化项目等操作});
2. 构建开发服务器
program.command('start').option('-p, --port <number>', '端口号', 3000).action((options) => {startDevServer(options.port);});

chalk

  • chalk 是 Node.js 中最流行的终端字符串样式库,专门用于在命令行工具中输出彩色文本和丰富的格式(如加粗、下划线等)。它能让你的 CLI 工具拥有更美观、更专业的输出效果。
核心功能
1. 改变文字颜色
const chalk = require('chalk');console.log(chalk.red('错误信息'));      // 红色文字
console.log(chalk.blue('提示信息'));     // 蓝色文字
console.log(chalk.green('成功信息'));    // 绿色文字
2. 改变背景色
console.log(chalk.bgRed.white('白字红底')); 
console.log(chalk.bgGreen.black('黑字绿底'));
3. 添加文本样式
console.log(chalk.bold('加粗文本'));
console.log(chalk.underline('下划线文本'));
console.log(chalk.dim('暗淡文本'));
4. 链式调用
console.log(chalk.blue.bgRed.bold('蓝字红底加粗'));
5.256色和RGB支持
console.log(chalk.rgb(255, 136, 0).bold('橙色加粗'))
console.log(chalk.hex('#FF8800')('十六进制颜色'))
实际应用场景
  • 可自定义进行封装,方便调用 ,如下
function showError(message) {console.log(chalk.red.bold('✖ 错误:'), chalk.red(message));
}
// 输出:✖ 错误: 文件不存在
function showSuccess(message) {console.log(chalk.green.bold('✓ 成功:'), message);
}
function showWarning(message) {console.log(chalk.yellow.bold('⚠ 警告:'), message);
}
  • 创建彩色表格,虽然这种方式不太完美但是也勉强能看出是表格了
// 空格
const  space = '    ';console.log(chalk.blue('名称') + space + chalk.green('状态') + space + chalk.yellow('进度')
);
console.log(chalk.blue('张三') + space +chalk.green('已支付') + space +chalk.yellow('100%')
)
console.log(chalk.blue('李四') + space +chalk.green('未支付') + space +chalk.yellow('0%')
)
高级用法
1.自定义主题函数
const theme = {error: text=>{console.log(chalk.red.bold(text))},success: text=>{console.log(chalk.green(text))},warning: text=>{console.log(chalk.yellow.underline(text))}
};
theme.error('错误信息');
theme.success('成功信息');
theme.warning('警告信息');
2. 组合使用模板字符串
const name = 'Alice';
console.log(chalk`{red 警告:} 用户 {blue.bold ${name}} 不存在`);

ora

  • ora 是 Node.js 中一个专门用于**命令行加载动画(Spinner)**的库,它可以在执行异步操作时显示旋转的加载指示器,为用户提供清晰的执行状态反馈。这个模块特别适合需要等待的操作(如文件下载、安装依赖等)。
核心功能
1. 基本用法
const ora = require('ora');const spinner = ora('正在加载...').start();// 模拟异步操作
setTimeout(() => {spinner.succeed('加载完成');
}, 2000);
2. 状态变化效果
方法效果示例使用场景
.start()⠋ 正在加载…开始加载
.succeed(text)✓ 成功操作成功
.fail(text)✖ 失败操作失败
.warn(text)⚠ 警告出现警告
.info(text)ℹ 信息显示信息
.stop()清除动画手动停止
3.丰富的预设动画:包含超过30种动画效果
spinner.spinner = 'dots'; // 可选:dots, line, pulse等
4.颜色支持:与chalk完美配合
spinner.color = 'yellow'; // 改变颜色
5.速度控制:调整动画刷新率
spinner.interval = 100; // 毫秒(默认80)
6.多行文本支持
spinner.text = '第一行\n第二行';
实际应用场景
1. 文件下载进度
async function downloadFile() {const spinner = ora('下载文件中...').start();try {await download('https://example.com/file.zip');spinner.succeed('下载完成');} catch (err) {spinner.fail('下载失败');console.error(err);}
}
2. 安装依赖
async function installDependencies() {const spinner = ora('正在安装依赖...').start();try {await execa('npm', ['install']);spinner.succeed('依赖安装完成');} catch {spinner.fail('依赖安装失败');}
}
高级用法
1. 自定义动画
const ora = require('ora');const spinner = ora('正在加载...').start();
spinner.spinner = {interval: 80,frames: ['-', '+', '-']
};
// 模拟异步操作
setTimeout(() => {spinner.succeed('加载完成');// spinner.fail('加载完成');
}, 3000);
2. 组合进度条
const ora = require('ora');const spinner = ora({text: '处理中...',spinner: {frames: ['🕛', '🕒', '🕕', '🕘'],interval: 300}
}).start();
// 模拟异步操作
setTimeout(() => {spinner.succeed('加载完成');// spinner.fail('加载完成');
}, 3000);
3. 动态更新文本
const ora = require('ora');
const spinner = ora({text: '处理中...',spinner: {frames: ['🕛', '🕒', '🕕', '🕘'],interval: 300}
}).start();
let i = 1
const time = setInterval(() => {spinner.text = `已处理 ${i}/${100} 文件`;i++
}, 1000);
// 模拟异步操作
setTimeout(() => {spinner.succeed('加载完成');clearInterval(time);// spinner.fail('加载完成');
}, 5000);

inquirer

  • 这是一个nodejs命令行交互工具,关于使用可查看我写的另外一篇文章

https://blog.csdn.net/weixin_43376417/article/details/135908186?spm=1011.2415.3001.5331

直接点击目录的 使用inquirer包来实现 查看

  • 整理不易,大家方便的话可帮忙点点赞点点收藏啥的,拜托啦,
http://www.dtcms.com/a/423766.html

相关文章:

  • 《面向物理交互任务的触觉传感阵列仿真》2020AIM论文解读
  • 未来最紧缺的十大专业seo优化师
  • OCP证书考试难度怎么样?
  • Vue3 defineModel === 实现原理
  • 唐山营销型网站建设2023新闻头条最新消息今天
  • 计算机网络---传输层
  • 如何在阿里云上做网站制作软件的手机软件
  • 深入理解 Java 虚拟机:从原理到实践的全方位剖析
  • 网站谷歌seo做哪些凌点视频素材网
  • 手机app应用网站C语言做网站需要创建窗口吗
  • uniapp 安卓FTP上传下载操作原生插件
  • 国外知名平面设计网站黄骅打牌吧
  • C++ I/O流与文件操作速查
  • 网站制作哪家好又便宜做电商网站的流程
  • 网络边界突围:运营商QoS限速策略
  • 【笔记】在WPF中Decorator是什么以及何时优先考虑 Decorator 派生类
  • [算法练习]Day 4:定长滑动窗口
  • 外汇交易网站开发做网站前端后台
  • 小红书网站建设目的优化师简历
  • 集群的概述和分类和负载均衡集群
  • 专业的商城网站开发搜索引擎优化不包括
  • 哈尔滨市延寿建设局网站wordpress 主题添加
  • 技术实践指南:多模态RAG从数据预处理到生成响应的完整流程
  • 新中地三维GIS开发智慧城市效果和应用场景
  • 做产品封面的网站赵公口网站建设公司
  • Redis开发07:使用stackexchange.redis库实现简单消息队列
  • RabbitMQ的安装集群、镜像队列配置
  • php 网站后台模板zencart外贸网站建设
  • IS-IS 与 OSPF 路由汇总机制:边界、应用与核心差异深度分析报告
  • 福彩双色球第2025113期篮球号码分析