Commit ef2ea79e authored by lipengcheng 's avatar lipengcheng

init

parents
.history
node_modules
\ No newline at end of file
[toc]
#### 顺序
- 创建可执行脚本`/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转换
#### Q
metalsmith是什么?
#! /usr/bin/env node
const { program } = require('commander')
const chalk = require('chalk')
// 配置命令
// 万一重名?添加--force选项强制覆盖
program
.command(`create <app-name>`)
.description(`create a new project`)
.option(`-f, --force`, `overwrite target direcrtory if it exists`)
.action((name, cmd) => {
require('../lib/create.js')(name, cmd)
})
program
.command(`config [value]`)
.description(`inspect and modify the config file`)
.option(`-g, --get <path>`, 'get value from option')
.option(`-s, --set <path> <value`)
.option(`-d, --delete <path>`, `delete option from config`)
.action((value, cmd) => {
console.log(`value:`,value);
console.log(`cmd:`,cmd);
})
program
.version(`lhfe ${require('../package.json').version}`)
.usage(`<command> [option]`)
program
.on(`--help`, () => console.log(`Run ${chalk.cyan(`lhfe <commadn> -h`)} show details`))
// 解析参数
program.parse(process.argv)
\ No newline at end of file
const inquirer = require('inquirer')
const { fetchRepoList, fetchTagList } = require('./request')
const { wrapLoading } = require('./utils')
const downlodRepo = require('download-git-repo') //不支持promise
const util = require('util')
const path = require('path')
module.exports = class Creator {
constructor(projectname, targetDir){
this.name = projectname
this.target = targetDir
this.downlodRepo = util.promisify(downlodRepo)
}
async fetchRepo(){
let repos = await wrapLoading(fetchRepoList, 'waitgin fetch tempales...')
if(!repos) return;
repos = repos.map(i => i.name)
const { repo } = await inquirer.prompt([
{
name: 'repo',
type: 'list',
choices: repos,
message: 'Choose a template'
}
])
console.log(`repo1:`,repo);
return repo
}
async fetchTag(repo) {
let tags = await wrapLoading(fetchTagList, 'waiting fetch tags....', repo)
if(!tags) return ;
tags = tags.map(i => i.name)
const { tag } = await inquirer.prompt([
{
name: 'tag',
type: 'list',
choices: tags,
message: 'Choose a tag',
}
])
return tag
}
async download(repo, tag) {
console.log(`repo:`,repo);
console.log(`tag:`,tag);
let requestUrl = `zhu-cli/${repo}${tag ? '#'+tag : ''}`
// 优化:先下载到系统目录中(用作缓存),再使用ejs handlerbar渲染模板,然后再写入到目标目录
await this.downlodRepo(requestUrl, path.resolve(process.cwd(), `${repo}@${tag}`))
return this.target
}
async create(){
const repo = await this.fetchRepo()
const tag = await this.fetchTag(repo)
await this.download(repo, tag)
}
}
\ No newline at end of file
const path = require('path')
const fs = require('fs-extra');
const inquirer = require('inquirer');
const Creator = require('./Creator')
module.exports = async function(projectname, options){
console.log(`projectname:`,projectname);
console.log(`options:`,options);
// 获取命令执行的目录
const cwd = process.cwd()
console.log(`cwd:`, cwd);
// 目标目录
const targetDir = path.join(cwd, projectname)
console.log(`targetDir:`,targetDir);
if(fs.existsSync(targetDir)){
// 有force参数,直接强制删除
if(options.force){
await fs.remove(targetDir)
} else {
// 提示是否要覆盖
console.log('222:',);
const answers = await inquirer.prompt([
{
name: 'action',
type: 'list',
message: `Target dir has exists`,
choices: [
{ name: 'Overwrite', value: 'overwrite' },
{ name: 'Cncel', value: false},
]
}
])
console.log(`answers:`,answers);
const {action} = answers
if(!action){
return
} else if(action === 'overwrite'){
console.log('\r\nRemoving:',);
fs.remove(targetDir)
}
}
}
console.log('不存在 开始创建:',);
const creator = new Creator(projectname, targetDir)
console.log(`creator:`,creator);
creator.create()
}
\ No newline at end of file
const axios = require('axios')
axios.interceptors.response.use(res => res.data)
module.exports = {
async fetchRepoList (){
return await axios.get(`https://api.github.com/orgs/zhu-cli/repos`,{
params:{
username: 'slevin57'
}
})
},
async fetchTagList(repo) {
const tagApi = `https://api.github.com/repos/zhu-cli/${repo}/tags`
console.log(`tagApi:`, tagApi);
return await axios.get(tagApi)
},
}
\ No newline at end of file
const ora = require('ora')
// 睡觉方法
async function sleep(ms) {
return new Promise((resolve, rejecrt) => setTimeout(resolve(), ms))
}
async function wrapLoading(fn, message, ...args) {
const spinner = ora(message)
spinner.start()
try {
const result = await fn(...args)
spinner.succeed()
return result
} catch (error) {
spinner.fail(`${error}, request failed, refetch...`)
await sleep(5000)
return wrapLoading(fn, message, ...args)
}
}
module.exports = {
sleep,
wrapLoading
}
\ No newline at end of file
{
"name": "lhfe",
"version": "1.0.0",
"description": "",
"main": "index.js",
"bin": "./bin/cli",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.21.1",
"chalk": "^4.1.0",
"commander": "^7.1.0",
"download-git-repo": "^3.0.2",
"fs-extra": "^9.1.0",
"inquirer": "^8.0.0",
"ora": "^5.4.0"
}
}
This diff is collapsed.
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