commander.js,可以自动的解析命令和参数,用于处理用户输入的命令。
download-git-repo,下载并提取 git 仓库,用于下载项目模板。
Inquirer.js,通用的命令行用户界面集合,用于和用户进行交互。
handlebars.js,模板引擎,将用户提交的信息动态填充到文件中。(一版本暂时未用到)
ora,下载过程久的话,可以用于显示下载中的动画效果。(暂时未用到)
chalk,可以给终端的字体加上颜色。
注意点
关于npm install -g的解释:
我们在写命令行工具的时候,需要指定一个可执行文件。在package.json中,
bin字段用来映射命令名和可执行文件。在通过npm install -g全局安装的时候,npm会symlink可执行文件到prefix/bin文件夹。
如果通过npm install本地安装的时候, npm会symlink可执行文件到./node_modules/.bin/文件夹。
npm install chalk commander download-git-repo inquirer ora --save
完成安装补充关于npm各种安装的差异详见:
npm安装的差异
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
注意事项 :
#! /usr/bin/env node
(对应的项目运行环境)#! /usr/bin/env node
process.env.NODE_PATH = __dirname + "/../node_modules";
const { resolve } = require("path");
const res = command => resolve(__dirname, '../commands/', command);
const program = require("commander");
const pkg = require("../package.json");
program
.version(pkg.version)
program
.usage("")
program
.command("init")
.description("Generate a new node project")
.alias("i")
.action(() => {
require(res("init"))
})
program.parse(process.argv)
// 判断终端上输入出来bin中的命令是否还有其他值,如果没有终端会直接输出help
if(!program.args || !program.args.length){
program.help()
}
init.js
编写具体命令代码const inquirer = require("inquirer");
const program = require("commander");
const chalk = require("chalk");
const download = require("download-git-repo");
const ora = require("ora");
const spinner = ora("Downloading please wait......");
const fs = require("fs");
const path = require("path");
const option = program.parse(process.argv).args[0];
// 生产项目默认名
const defaultName = typeof option === "string" ? option : "node-project";
// 交互使用的问题
const questionList = [
{
type: 'input',
name: 'Project name',
message: 'Project name',
default: defaultName,
filter(val) {
return val.trim()
},
// 验证数据
validate(val) {
const validate = (val.trim().split(" ")).length === 1
return validate || 'Project name is not allowed to have spaces ';
},
transformer(val) {
return val;
}
},{
type: 'input',
name: 'description',
message: 'Project description',
default: 'Node project',
validate (val) {
return true;
},
transformer(val) {
return val;
}
}, {
type: 'input',
name: 'author',
message: 'Author',
default: 'project author',
validate (val) {
return true;
},
transformer(val) {
return val;
}
},{
type: "list",
name: "program type",
message: "program type",
choices: [
"Nodejs",
"Typescript",
"Python"
],
default:"nodejs",
// 使用filter将回答变成小写
filter: function(val){
return val.toLowerCase();
}
}
]
// 生成项目目录
fs.mkdir(defaultName, err => {
if(err){
console.log("项目目录生成失败")
}
})
// 根据用户选择的语言去配置对应的配置文件
inquirer.prompt(questionList).then(answers => {
if (answers["program type"] === "nodejs"){
spinner.start();
download("direct:https://gitlab.com/zjiahuizjh/auto-cli#node-conf", answers["Project name"] + "/config", { clone: true }, (err) => {
if(err){
spinner.stop();
console.log(err)
}else{
spinner.stop();
console.log(chalk.red("项目初始化成功"));
}
});
}else if(answers["program type"] === "typescript"){
spinner.start();
download("direct:https://gitlab.com/zjiahuizjh/auto-cli#ts-conf", answers["Project name"] + "/config", { clone: true }, (err) => {
if(err){
spinner.stop();
console.log(err)
}else{
spinner.stop();
console.log(chalk.red("项目初始化成功"));
}
});
}else{
spinner.start();
download("direct:https://gitlab.com/zjiahuizjh/auto-cli#py-config", answers["Project name"] + "/config", { clone: true }, (err) => {
if(err){
spinner.stop();
console.log(err)
}else{
spinner.stop();
console.log(chalk.red("项目初始化成功"));
}
});
}
})
.gitignore
(不需要上传的文件)
node_modules
.npmrc
(锁定npm版本)
save-exact=true
参考:发布一个npm包