2021-03-13 更新使用说明 2019-12-04 初稿 create-self-cli.html 2019-03-26 写一个npm包来规范专题写法
制作一个基于Commander的cli脚手架工具
为啥要写一个脚手架:开发提效、约定配置、统一开发流程。
在中大时候一直觉得写页面不够规范,看了一些经验,可以通过npm cli来实现一键创建目标项目,经过调研发现以下技术:
- inquirer, enquirer or prompts for 处理用户输入
- email-prompt for convenient email input prompts
- chalk or kleur for 颜色输出
- ora for beautiful spinners
- boxen for drawing boxes around your output
- stmux for a tmux like UI
- listr for progress lists
- ink to build CLIs with React
- meow or arg for basic argument parsing
- commander and yargs for complex argument parsing and subcommand support
- oclif a framework for building extensible CLIs by Heroku (gluegun as an alternative)
理想状态,我们可以通过脚手架来创建日常专题:
yarn global add @zdwx/clizdwx add —p —pc womensday // 新建pc专题,默认pczdwx add -w --wap womensday // 新建wap专题
也可以和 vue 的脚手架一样,让用户自己选,最后拼接选项。开发完成一键发布,用到了 ftp 功能。
这样想达成下面的成果:
- 创建项目、通用代码,封装axios工具、组件库
- git操作,自动提交推送、打tag
- 自动构建、部署cdn、打点埋点
技术储备
什么是脚手架CLI
vue create xxx -r xx -p 10000
有命令、参数、选项
options 一个- 表示短标,如果是 -a -b -c 可以写成 -abc。
两个--表示长标,--dev-version
vue 为何能全局系统级别生效?
vue这个本质上是 node的js脚本,通过注入node全局脚本到系统环境变量,实现了node全局命令的映射,映射用到的是软连接概念。
whice vue查找环境命令,得到 vue注册的位置 等同于xxx/bin/vue- 查找软连接找到具体脚本位置
vue —> node [nodePath]/lib/node_modules/@vue/cli/bin/vue —> path/vue.js
安装的是 @vue/cli 但注册的是 vue?
通过 package.bin 注册了 vue 命令
如何通过执行js脚本?
开头声明使用node来执行 #!/usr/bin/env node
Commander
介绍第一个npm库:commander ,这是TJ大神的作品,用来解析cli输入的工具。
node.js 命令行接口的完整解决方案,灵感来自 Ruby 的 commander。
有几个核心概念:
- options 选项,提供某种选项,比如告诉我版本号、进入安静模式、输出结果不要颜色等。
- commands 命令,
#!/usr/bin/env nodeconst program = require('commander')program.version(require('../package').version, '-v', '--version').command('init <name>', 'init project').command('refresh','refresh routers...')program.parse(process.argv)//commander.option(‘-c —color <color>’,”指定颜色”).parse(process.argv)//if(commander.color) console.log(‘颜色是 %s’, commander.color)
Chalk
介绍 chalk 这个最简单,就是彩色输出的。https://www.npmjs.com/package/chalk
log(chalk.blue('Hello') + ' World' + chalk.red('!'));log(chalk.blue.bgRed.bold('Hello world!'));
ora
const ora = require('ora');const process = ora(`正在下载....${repo}`);process.start();process.fail()process.succeed()
inquirer
交互式选项
基本流程
1. 列出要使用到的依赖库
- download-git-repo 下载仓库。可以指定一个文件夹,下载到本地。
- ora 等待进度条
- commander
- handlebars
- figlet
- clear
- chalk console变色
- open
2. 创建 .bin/mycli.js
指明运行脚本要执行的命令
#! /usr/bin/env node// 上一行固定写死console.log('cli')
package.json 添加
"bin": {"axe": "bin/index.js"}
3. 链接全局
通过 npm i -g xxx 安装的包会全局生效,如何做到的?通过软连接 ln -s
比如:
/usr/local/bin/http-server# 链接到/usr/local/lib/node_modules/http-server/bin/http-server
在当前目录执行 npm link ,在项目中就可以 npm link xxx package了
如果要取消
- npm unlink 从全局包中移除,这时候软链接已经失效了
- npm unlink [package] 这时候目标软连接已经失效了
- 删除 node_module 重新安装
4. 命令参数解析
const argv = require('process').argv;console.log(argv)
比如 axe create . -p 123
解析到的结果
['/Users/xinbao/.nvm/versions/node/v14.15.5/bin/node','/Users/xinbao/myCode/cli-demo/node_modules/.bin/axe','create','.','-p','123']
因此,commander 存在的意义就是帮我们把参数解析做好
发包
#!/usr/bin/env bashnpm config get registry # 检查仓库镜像库npm config set registry=http://registry.npmjs.orgecho '请进行登录相关操作:'npm login # 登陆echo "-------publishing-------"npm publish # 发布npm config set registry=https://registry.npm.taobao.org # 设置为淘宝镜像echo "发布完成"exit
简单的参考案例 github.com/su37josephxia/vue-template
带 @scope 发包,比如 @axe.dev/create-web 会提示 You must sign up for private packages
npm publish --access public
小技巧
放最后,但是很有用
yarn create
如果一个包 create- 开头,就可以说过它
yarn create <create-xxx-package> [<args>]# 比如yarn create react-app my-app# 等同于yarn global add create-react-appcreate-react-app myapp
全局安装,如果有group必须还是要 @scope
npx
npx package name
先把package下载到临时目录,使用后删除,下次执行会重新下载
可以添加 —no-install 不远程下载走本地
npm init
npm init @scope/name# 等同于npx @scope/create-<name>
如果包本身叫 @scope/create 直接 npm init @scope
