一、目的
甚至有马大哈,没有更新项目仓库地址,导致提交代码到旧仓库,这就很尴尬了。。。
基于这些情况,编写命令行工具(CLI)的目的就很明确:
- 用于新项目工程的初始化
- 利用工具进行初始化,可以节省项目初期的准备时间
- 避免出现改漏的情况
- 杜绝未更新项目版本仓库地址的问题
二、自动化流程分析
- 配置信息
- 模板文件
三、工具准备3.1 配置信息工具
- commander
借鉴Ruby commander理念实现的命令行执行补全解决方案
npg-cli --
♫ ♫♬♪♫ npm-package-cli ♫ ♫♬♪♫Usage: npg-cli [options]Options: -V, --version output the version number -h, --
output usage information run testcli and edit the setting.
- inquirer
常用交互式命令行用户界面的集合。
npg-cli♫ ♫♬♪♫ npm-package-cli ♫ ♫♬♪♫Follow the prompts to complete the project configuration.? project name
? version 1.0.0? description3.2 模板信息工具
如果把所有项目文件,不管文件后缀名,都看成是ejs模板,则可以在文件内容中使用ejs语法。
再根据配置信息进行替换,最终生成新文件。
- mem-fs
- mem-fs-editor
3.3 提示信息工具
这样,可以输出更直观、友好的提示。
3.4 文件操作
利用shelljs,可以在项目中简化以下步骤:
- 一些项目文件,不需要修改,只用直接copy。可以使用shelljs.copySync同步方式生成。
- 一些文件夹,需要提前构建,可以使用shelljs.mkdir进行创建
四、实现
4.1 初始化
项目结构如下:
npm-package-cli |-- package.json4.2 生成全局指令
4.2.1 新建执行文件
clishell脚本文件内容如下:
!/usr/bin/env nodeconsole.log('hello world');
"bin": { "npg-cli": "bin/cli"}
npm-package-cli |-- bin |-- cli |-- package.json4.2.2 链接指令到全局
- npm link
- npm install -g
作用是把npg-cli指令,指向全局的bin文件下,实现软链。
4.2.3 运行
npg-cli
输出hello world
4.3 初始化操作类Creation
Creation的结构如下:
class Creation{
(){
}
(){
}
}
npm-package-cli |-- bin |-- cli |-- src |-- index.js |-- package.json4.4 修改cli文件
!/usr/bin/env nodeconst Creator = require('../src/index.js');const project = new Creator();project.do();
4.5 实现命令行参数读取
新建src/command.js文件,文件内容如下:
commander =
(
);
chalk =
(
);
packageJson =
(
);
log =
.log;function initCommand(){ commander.version(packageJson.version) .on(
, ()=>{ log(chalk.green(
)); }) .parse(process.argv);}
.exports = initCommand;
npm-package-cli |-- bin |-- cli |-- src |-- command.js |-- index.js |-- package.json
initCommand =
(
);class Creation{
(){ initCommand(); }}
Usage: npg-cli [options]Options: -V, --version output the version number -h, --help output usage information run testcli and edit the setting.4.6 获取用户输入配置信息
新建src/setting.js文件,文件内容如下:
inquirer =
(
);
fse =
(
);function initSetting(){
prompt = [ {
:
,
:
,
:
, validate(input){
(!input){
}
(fse.existsSync(input)){
}
; } },
];
inquirer.prompt(prompt);}
.exports = initSetting;
npm-package-cli |-- bin |-- cli |-- src |-- command.js |-- index.js |-- setting.js |-- package.json
initCommand =
(
);
initSetting =
(
);class Creation{
(){ initCommand(); initSetting().then(setting => {
}); }}
4.7 模板文件替换输出
文件操作,要用到工具shelljs。
chalk =
(
);
fse =
(
);
path =
(
);
log =
.log;function output(creation){
((resolve, reject)=>{
setting = creation._setting;
{ projectName } = setting;
cwd = process.cwd();
projectPath = path.join(cwd, projectName);
projectResolve = getProjectResolve(projectPath);
fse.mkdirSync(projectPath);
creation.copy(
, projectResolve(
));
creation.copyTpl(
, projectResolve(
), setting);
creation._mfs.commit(() => { resolve(); }); });}
.exports = output;
- 新建项目文件夹
- 把模板文件读取出来,根据配置信息,进行替换(调用的是mem-fs-editor的copyTpl方法)
- 拷贝其他文件
- 输出最终文件到硬盘上
initCommand =
(
);
initSetting =
(
);
output =
(
);class Creation{
(){ initCommand(); initSetting().then(setting => {
._setting =
.assign({},
._setting, setting);
output(
).then(res => {
}); }); }}4.8 阶段小结
- 读取用户配置
- 读取模板文件
- 根据配置,编译模板文件,输出最终文件
五、发布npm包的注意点5.1 安装依赖包的方式
体现在package.json的表现是dependencies字段:
: {
:
,
:
,
:
,
:
,
:
,
:
,
:
},
5.2 .gitignore文件
解决方式是:将.gitignore改名称,比如改为gitignore。当使用CLI工具时,再将文件名改回来。
例子:
creation.copy(
, projectResolve(
));六、项目开源
生成的项目,囊括以下功能点:
- 支持TypeScrpt
- mocha+chai自动化测试,支持使用TypeScript编写测试用例
- 支持测试覆盖率coverage
- 支持eslint,包括对TypeScript的lint检查
- Git commit规范提交
- Git版本自动打标签(standard-version),更新CHANGELOG.md
- 输出的npm包支持各种模块规范(AMD、CMD、CommonJS、ESModule)
npm install -g npm-package-cli