Commit 93d38f96 authored by lipengcheng 's avatar lipengcheng

build: footer logo

parent 866766c2
[toc]
#### TODO
### TODO
- [ ] commander配置多条命令的方式(命令直接对应文件)
- [ ] 显示环境配置信息:nuxt
- [x] 未知的命令给出相关的建议命令
......@@ -17,204 +17,3 @@
- [ ] 通过删除模板文件中带插值的文件定位ejs报错信息
- [ ] 脚手架版本提示:"New version available 4.5.11 → 4.5.12";提示信息以方框的形式展示
- [ ] 删除生成的项目的git目录
#### Q
metalsmith是什么?
handlerbar?
#### program.on()必须在program.parse()之前,因为node的emit()是即时的
#### 未知的命令给出相关的建议命令
通过`program.on('command:*',cb)``leven` 包来实现。-- vuecli
#### 依赖包专门管理 -- vuelci
```javascript
// @vue/cli-shared-utils
[
'env',
'exit',
'ipc',
'logger',
'module',
'object',
'openBrowser',
'pkg',
'pluginResolution',
'launch',
'request',
'spinner',
'validate'
].forEach(m => {
Object.assign(exports, require(`./lib/${m}`))
})
exports.chalk = require('chalk')
exports.execa = require('execa')
exports.semver = require('semver')
Object.defineProperty(exports, 'installedBrowsers', {
enumerable: true,
get () {
return exports.getInstalledBrowsers()
}
})
```
#### 只包含一个命令的程序
在只包含一个命令的程序中,无需定义处理函数。
```javascript
#!/usr/bin/env node
const { program } = require('commander');
program
.description('An application for pizza ordering')
.option('-p, --peppers', 'Add peppers')
.option('-c, --cheese <type>', 'Add the specified type of cheese', 'marble')
.option('-C, --no-cheese', 'You do not want any cheese');
program.parse();
const options = program.opts();
console.log('you ordered a pizza with:');
if (options.peppers) console.log(' - peppers');
const cheese = !options.cheese ? 'no' : options.cheese;
console.log(' - %s cheese', cheese);
```
#### 工具集
cac: nuxt中使用的命令行工具,类似commander。 -- nuxt
leven: 计算测量两字符串之间的差异,用于对未知的命令给出相关的建议命令 -- vuecli
semver:版本号控制 -- vuelci
slash: 将window反斜杠路径转换为斜杠路径 foo\\bar ➔ foo/bar -- vuecli
minimist:解析参数选项 -- vuecli
validate-npm-package-name:判断作为pkgname的某个字符串是否已经存在
ncp:异步文件目录递归复制
模板引擎:consolidatejs、handlebars、ejs、jade、swig
#### 创建项目逻辑
`create .`的话,直接初始化当前目录(以当前目录的文件名为项目名称)
`create xx`,在当前工作目录新建名为`xx`的项目。
xx如果与当前工作目录同名的话,提示用户如何处理?
如果当前目录已经存在同名xx目录的话,提示用户强制覆盖?
#### `path.resolve()`和`path.join()`的区别
一句话,path.join()从左往右,将传入的path片段拼接成一个完成的地址。path.resolve() 从右往左将path片段拼成绝对路径。
#### 可以通过`program.arguments()`方法给顶层命令指定参数
通过.arguments可以为最顶层命令指定命令参数,对子命令而言,参数都包括在.command调用之中了。尖括号(例如<required>)意味着必选,而方括号(例如[optional])则代表可选。可以向.description()方法传递第二个参数,从而在帮助中展示命令参数的信息。该参数是一个包含了 “命令参数名称:命令参数描述” 键值对的对象。
```javascript
program
.arguments('<username> [password]')
.description('test command', {
username: 'user to login',
password: 'password for user, if required'
})
.action((username, password) => {
console.log('username:', username);
console.log('environment:', password || 'no password given');
});
```
#### program.command()的参数
program.command()的第一个参数可以配置**命令名称及命令参数**,参数支持**必选(尖括号表示)****可选(方括号表示)**及变长参数(点号表示,如果使用,只能是最后一个参数)。
```javascript
// 通过绑定处理函数实现命令(这里的指令描述为放在`.command`中)
// 返回新生成的命令(即该子命令)以供继续配置
program
.command('clone <source> [destination]')
.description('clone a repository into a newly created directory')
.action((source, destination) => {
console.log('clone command called');
});
// 通过独立的的可执行文件实现命令 (注意这里指令描述是作为`.command`的第二个参数)
// 返回最顶层的命令以供继续添加子命令
program
.command('start <service>', 'start named service')
.command('stop [service]', 'stop named service, or all if no name supplied');
```
#### 独立的可执行文件规则
**当.command()带有描述参数时,就意味着使用独立的可执行文件作为子命令**。 Commander 将会尝试在入口脚本(例如 ./examples/pm)的目录中搜索program-command形式的可执行文件,例如pm-install, pm-search。通过配置选项executableFile可以自定义名字。
```javascript
program
.version('0.1.0')
.command('install [name]', 'install one or more packages')
.command('search [query]', 'search with optional query')
.command('update', 'update installed packages', { executableFile: 'myUpdateSubCommand' })
.command('list', 'list packages installed', { isDefault: true });
program.parse(process.argv);
```
独立的可执行文件,要么明确`.js`后缀,要么`chmod +x file`赋予执行权限。
#### program.action()处理函数的参数
命令处理函数的参数,为该命令声明的所有参数,除此之外还会附加两个额外参数:一个是解析出的选项,另一个则是该命令对象自身
```javascript
program
.arguments('<name>')
.option('-t, --title <honorific>', 'title to use before name')
.option('-d, --debug', 'display some debugging')
.action((name, options, command) => {
if (options.debug) {
console.error('Called %s with options %o', command.name(), options);
}
const title = options.title ? `${options.title} ` : '';
console.log(`Thank-you ${title}${name}`);
});
```
#### 脚手架执行顺序
- 创建可执行脚本`/bin/cli`
- 配置package.json中的 bin字段
- npm link链接到本地全局环境。npm link --force可以覆盖之前已链接过得同名命令
- 执行的node命令默认取package.json的name字段(bin字段值为字符串),也可以把bin字段配置为对象,那么执行的命令就是对象的键名
#### prefix
`npm config get prefix`可以获取到全局命令链接到的本地目录前缀
```bash
{13:54}~/Desktop/zf-cli:master ✗ ➭ npm config get prefix
/usr/local
```
#### 脚手架大概流程
1. 配置可执行命令及对应文件
2. 命令行交互 commander inquirer
3. 下载模板 downlaod-git-repo
4. 根据用户输入信息生成项目 metalsmith
#### commander输出版本号
```javascript
program.version(`lhfe ${require('../package.json').version}`)
```
#### 异步的fs模块封装包
fs-extra
####
download-git-repo不支持promise
通过util.promisify转换
#### nodejs中操作shell脚本
原生的childProcess
execa
shelljs
cli
#### download-git-repo
download-git-repo内部是通过`download``git-clone``rimraf`几个包实现的
#### npm包download-git-repo 报 'git clone' failed with status 128
[npm包download-git-repo 报 'git clone' failed with status 128 · Issue #17 · wuqiong7/Note](https://github.com/wuqiong7/Note/issues/17)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment