1 新建项目目录
1 | mkdir my-cli |
2 | cd my-cli |
3 | npm init —y |
2 新建 bin 目录 创建脚本 test.js
1 | #!/usr/bin/env node //指定一个解释器 告诉shell 用node解释器去执行脚本 |
2 | console.log('test') |
3 在package.json 配置bin 字段
bin字段用来指定各个内部命令对应的可执行文件的位置。
test 有毒不生效 所以这里新建了一个test2.js 脚本(命令)
1 | "bin": { |
2 | "test": "./bin/test.js", // 好像test 命令有毒 不打印 其他可以 |
3 | "test2": "./bin/test2.js" |
4 | }, |
4 运行 npm link (参考博客 npm link 详解)
将包中的任何bin链接到{prefix}/bin/{name} npm config get prefix 查看前缀
test2 命令已被添加到环境变量中
5 执行test2
6 引入commander 添加子命令
test2.js 初始化项目
1 | #!/usr/bin/env node |
2 | const program = require('commander') |
3 |
|
4 | program.version(require('../package.json').version) |
5 | program |
6 | .command('init <name>') |
7 | .description('init project ') |
8 | .action(require('../lib/init')) |
9 |
|
10 |
|
11 | program.parse(process.argv) |
7 使用 figlet chalk 输出欢迎界面
1 |
|
2 | const { promisify } = require('util') |
3 | const figlet = promisify(require('figlet')) |
4 | const chalk = require('chalk') |
5 | const log = content => console.log(chalk.green(content)) |
6 | module.exports = async name => { |
7 | const data = await figlet('Welcome') |
8 | log(data) |
9 | log(`下载项目: ${name}`) |
10 | } |
8 download-git-repo 从远程仓库拉取项目
1 | const {clone} = require('./download') |
2 |
|
3 | log(`下载项目: ${name}`) |
4 |
|
5 | await clone('github:cxyxiaoyuyu/xinyi-ui#main',name) |
使用 ora 在下载时显示loading
1 |
|
2 | const { promisify } = require('util') |
3 | const ora = require('ora') |
4 |
|
5 | module.exports.clone = async function(repo,desc){ |
6 | const download = promisify(require('download-git-repo')) |
7 | const process = ora(`下载..... ${repo}`) |
8 | process.start() |
9 | await download(repo,desc) |
10 | console.log(repo,desc) |
11 | process.succeed() |
12 | } |
执行完成后项目会多了一个执行命令时输入的目录
9 执行命令 自动安装依赖
使用 spawn 执行 命令
1 |
|
2 | const {spawn} = require('child_process') |
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | const _spawn = async (...args) => { |
9 | return new Promise((resolve)=>{ |
10 | const proc = spawn(...args) |
11 | proc.stdout.pipe(process.stdout) |
12 | proc.stderr.pipe(process.stderr) |
13 | proc.on('close',()=>{ |
14 | resolve() |
15 | }) |
16 | }) |
17 | } |
18 | log('安装依赖') |
19 | await _spawn('npm',['install'],{cwd: `./${name}`}) |
20 | log(`安装完成`) |
10 自动启动项目
使用open 打开浏览器
1 |
|
2 | log('启动') |
3 |
|
4 |
|
5 |
|
6 |
|
7 | open(`http://localhost:3001`) |
8 | _spawn('npm',['run','dev'],{cwd: `./${name}`}) |
11 实现约定路由功能
根据views下的文件 自动生成路由
使用handlebars 模板引擎
1 | const fs = require('fs') |
2 | const handlebars = require('handlebars') |
3 |
|
4 | const program = require('commander') |
5 | program |
6 | .command('create component <name>') |
7 | .description('init project ') |
8 | .action(refresh) |
9 | program.parse(process.argv) |
10 |
|
11 |
|
12 | async function refresh (name){ |
13 | console.log(name) |
14 | |
15 | const list = fs.readdirSync('./src/views') |
16 | .filter(v => v !== 'Home.vue') |
17 | .map(v => ({ |
18 | name: v.replace('.vue','').toLowerCase(), |
19 | file: v |
20 | })) |
21 | console.log(list) |
22 |
|
23 | |
24 | compile({list},'./src/router/index.js','./template/router.js.hbs') |
25 |
|
26 | |
27 | compile({list},'./src/App.vue','./template/App.vue.hbs') |
28 |
|
29 | |
30 |
|
31 |
|
32 |
|
33 |
|
34 | |
35 | function compile(meta,filePath,templatePath){ |
36 | if(fs.existsSync(templatePath)){ |
37 | const content = fs.readFileSync(templatePath).toString() |
38 | const result = handlebars.compile(content)(meta) |
39 | fs.writeFileSync(filePath,content) |
40 | console.log(`${filePath}创建成功`) |
41 | } |
42 | } |
43 | } |