如何在自己的项目中实现脚手架的命令行交互

922 阅读4分钟

背景

所在的公司大多数项目都是用Taro脚手架搭建的,因为业务上要实现多端开发 答应我,如果可以千万不要选择跨端开发🙏。所以不同环境下运行、打包会有多个命令。如下图所示: image.png 某天,我来到公司后,公司刚入职不久的老大哥(大佬)跟我说来看一个好玩的!

iShot_2022-09-26_20.31.23.gif

嗯??好熟悉感觉在哪见过?

这不是我当时初学框架时候用脚手架搭建项目的时候选择配置的交互效果吗!本着学会了就是自己的的原则,立马打开package.json看看这个start命令到底干了什么!

初探

当我充满好奇打开package.json。 image.png 嗯?怎么多了一个node start.js,再看左侧文件多出一个start.js,一定是它搞得鬼。

为了方便理解,这里先把所有的多余的方法隐藏起来。

image.png

当我把杂七杂八的都隐藏起来之后,发现最底部有一个index(),这个我懂!先执行了index方法嘛。 然后我顺着代码看去,引出了start.js文件中第一个依赖inquirer

inquirer

打开npm搜索这个依赖,大致了解一下后,原来命令行的交互都是它来实现的。 image.png

这里简单介绍一下inquirer,具体的可以去GitHub看下文档

语法

const inquirer = require('inquirer');

const test = async ()=>{
    const promptList = [{
        type: 'input',
        message: '输入框',
        name: 'xxx',
    }]
    const { xxx } = await inquirer.prompt(promptList);
    console.log(`返回值为${xxx}`); //返回值
}

PS:因为inquirer.prompt()返回的是一个Promise,这里是为了使用await 所以const一个test函数。另外,结构赋值出来的变量xxx要与配置项中的name相同。

PPS:ES6语法参考阮一峰老师的ES6 入门教程

类型

input (输入 可用于填写用户信息 支持参数校验)
const promptList = [{
        type: 'input',
        message: '请输入年龄:',
        name: 'xxx',
        validate: (val)=> {
            if(val == 18){
                return '还18呢?!'
            }else{
                return true
            }
        }
    }]

效果如下: iShot_2022-09-26_22.00.12.gif

password (密码 隐藏输入)
const promptList = [{
        type: "password",
        message: "请输入您的密码:",
        name: "xxx",
    }];

效果如下:

iShot_2022-09-26_22.17.45.gif

confirm (确认 返回true/false)
const promptList = [{
        type: "confirm",
        message: "是否加班?",
        name: "xxx",
    }];

效果如下: iShot_2022-09-26_22.13.29.gif

checkbox (复选 空格选中)
 const promptList = [{
        type: "checkbox",
        message: "请选择您的武器(可多选):",
        name: "xxx",
        choices: [
            {name: "JS",checked: true // 默认选中},
            {name: "React"},
            {name: "Vue"},
            {name: "Angular"},
        ]
    }]

效果如下:

iShot_2022-09-26_22.31.28.gif

rawlist (有序列表)
const promptList = [{
        type: "rawlist",
        message: "请选择您的职业:",
        name: "xxx",
        choices:["法师","战士","盗贼"]
    }];

效果如下:

iShot_2022-09-26_22.28.11.gif

list (无序列表)
const promptList = [{
        type: "list",
        message: "请选择您的位置:",
        name: "xxx",
        choices:["上","野","中","AD","辅助"]
    }];

效果如下:

iShot_2022-09-26_22.37.39.gif

分析

搞懂这个依赖后,发现文件中的indexmode(模式)env(环境) 这三个函数都是在让用户选取模式,并将此次操作选择的返回值带到下一个函数内,最后将所有参数代入到 exec(执行)

无标题-2022-09-26-2251.png

绘图用的是 excalidraw (在 快跑啊小卢_ 评论找到的):D

接下来就是揭开exec的神秘面纱的时候!

image.png

嗯嗯?前两行代码我倒是看懂了,将之前所有的返回值在commandObj这个配置项中拿到具体的执行命令。那这个chalkshell是什么东西??

接下来引出我们文件中第二个依赖chalk

chalk

继续在npm平台上搜索这个依赖 image.png 大致意思是实现终端的文字样式,依旧是简单介绍一下,具体可参考GitHub

颜色

console.log(chalk.red('我是红色'));
console.log(chalk.yellow('我是黄色'));
console.log(chalk.blue('我是蓝色'));

效果如下

image.png

背景色

console.log(chalk.bgRed('我是红色'));
console.log(chalk.bgYellow('我是黄色'));
console.log(chalk.bgBlue('我是蓝色'));

效果如下

image.png

粗细

console.log(chalk.bold('我是粗的'));
console.log(chalk('我是细的'));

效果如下 image.png

同时设置

console.log(chalk.bgBlue.red.bold('蓝底红字粗'));

效果如下

image.png

shelljs

老规矩先查依赖,同时贴上GitHub, 官网翻译如下

image.png 因为不是计算机专业出身,所以该依赖在本章中的作用就是用js在终端运行脚本 (有懂哥可以在评论区科普一下🙏)

例如:

shell.exec('git help')

效果如下

iShot_2022-09-26_23.36.03.gif

总结

到这里整个交互以及执行就显而易见了

无标题-2022-09-26-12251.png

占为己有

就这?简单!接下来就是自己写个小Demo,然后占为己有

  • 新建文件
  • 初始化 yarn init
  • 安装依赖 yarn add inquirer chalk shelljs -D
  • 在package.json中增加 "script":{ "start":"node start.js" }
  • 引入start.js
  • 最后在命令行中输入 yarn start,按下回车

image.png

嗯嗯??怎么报错了

查了一下资料,发现最新版本的chalkinquirer 不支持CommonJS语法

  "devDependencies": {
    "chalk": "^5.0.1",
    "inquirer": "^9.1.2",
    "shelljs": "^0.8.5"
  },

解决办法:将CommonJS改为ES Module,并在package.json中加入

//start.js
import inquirer from  'inquirer'
import chalk from  'chalk'
import shell from  'shelljs'

//package.json
"type":"module"

大功告成!

注意: 这里在Taro项目中没有使用ES Module,是因为我在package.json加入type后,Taro会报错,所以还是采用CommonJS语法,降低了依赖的版本

image.png 依赖版本参考

 "devDependencies": {
    "chalk": "^4.1.2",
    "inquirer": "^8.2.4",
    "shelljs": "^0.8.5",
  }

写在最后


后续更新

之前因为Taro中没有使用ES Module,退而求其次降低了依赖版本。今日复习阮一峰老师ES6 入门教程,发现模块化加载部分有对应的处理手段

image.png