⚡node打怪升级系列 - 通俗易懂聊下脚手架交互式命令界面怎么做

1,401 阅读5分钟

前言

NodeJS这东西是不是学过了,之后感觉又像没学到什么东西???

我最近翻到了之前学习node的笔记,又结合了一些大佬的经验,这里把node系列相关的东西串联一下,分享给小伙伴们,顺便我自己也加深一下印象。

总共分为六篇

node打怪升级系列 - 基础篇

node打怪升级系列 - Koa篇

node打怪升级系列 - 浅谈require函数

node打怪升级系列 - 手写中间件篇

node打怪升级系列 - 手写发布订阅和观察者篇

node打怪升级系列 - 手写compose(洋葱模型)

node打怪升级系列 - 手写脚手架交互式命令界面

本文重点记录下脚手架篇里的交互式命令界面怎么做

image.png

正文开始

一,开发脚手架的交互式命令行界面

1,项目结构

image.png

2,安装依赖

package.json代码贴到文章最后了

3,创建核心文件

bin/index.js

#!/usr/bin/env node

console.log('hellow world')

#!:这两个字符是 shebang 的标识,它告诉操作系统这个文件是一个脚本

#!/usr/bin/env node通常在linux程序中的开头,指明这个文件的解释程序。此处是说明用node来执行这个文件

4,注册全局指令

cliTest目录下执行 npm link

npm link

cluo-cli指令注册到全局变量,在任何地方都可以使用此命令来执行cluo-cli对应的js文件(下图红框处)

image.png

npm link 为了本地调试,不需发布

它等于 npm publish vue包 => npm install vue包 -g => 全局可用vue create '项目'

如下图,任意其它目录输入cluo-cli会打印出hello world就算成功了

image.png

5,选择工具

  • inquirer:用于创建交互式命令行界面的库,比如创建vue脚手架时,让你选择Vuex还是 Router那个节界面

  • commander:命令行参数解析库,比如cluo-cli -h解析这个-h

  • chalk:用于在控制台输出彩色文本的库,让你的终端好看一点

此处我们选择inquirercommander库(所有该装的,文章底部package.json的都有了)

6,开发配置项

如下图可以看到,当前我们已经给cluo-cli命令开发了配置项(Options),并且可以通过cluo-cli -V查看版本号

image.png

7,开发命令项

如下图可以看到,输入cluo-cli -h 不仅有Options,还有Commands

image.png

7.1,子命令

...

program
  .version('0.1.0')
  .description('this is a test')
  // 添加了一个子命令
  .command('pack [entry]')
  .description('this is a tool for pack')
  .option('-d, --dev', '开发模式')
  .option('-p, --prod', '生产模式')
  
program.parse(process.argv)

-d -ppack命令的Options,如下图

image.png

.command('pack [entry]')中,[]表示可选 <>表示必选

action对执行的pack命令进行响应
...

program
  .version('0.1.0')
  .description('this is a test')
  // 添加了一个子命令
  .command('pack [entry]')
  .description('this is a tool for pack')
  .option('-d, --dev', '开发模式')
  .option('-p, --prod', '生产模式')
  .action((entry, type) => {
    console.log(`entry :${entry}, type: ${JSON.stringify(type)}`)
  })
  
program.parse(process.argv)

用户命令行输入cluo-cli pack index.js -dpack命令被执行

action里的回调函数被触发,函数携带两个参数cb(entry, type),函数里可以做自定义逻辑

  • entry: 用户输入的文件名

  • type: 上文配置项的内容(-d,-p),值是dev prod

如下图

image.png

添加交互式命令行界面

action里使用inquirer做出用户输入命令=>展示交互式界面=>让用户选择的效果

...
program
  .version('0.1.0')
  .description('this is a test')
  .command('pack [entry]') // 构建一个打包工具
  .description('this is a tool for pack')
  .option('-d, --dev', '开发模式')
  .option('-p, --prod', '生产模式')
  .action((entry, type) => {
    console.log(`entry :${entry}, type: ${JSON.stringify(type)}`)
    let { dev, prod } = type;
    if (!(dev || prod)) {
      const promptList = [
        {
          type: 'list', // list, input, confirm, checkbox, editor...
          message: '运行(dev)还是打包(prod)', // 问题的描述
          name: 'packEnv',
          choices: ['dev', 'prod'], // 选项
          // validata, filter, prefix, suffix, default..
        }
      ]

      inquirer.prompt(promptList).then((res) => {
        if (res.packEnv === 'dev') {
          console.log('我要运行')
        } else {
          console.log("我要打包")
        }
      })
    } else {
      dev && console.log('我要运行')
      prod && console.log('我要打包')
    }
  })
...

用户输入cluo-cli pack展示交互式命令界面 => 用户选择prod => 打印出我要打包

用户输入cluo-cli pack -d => 直接打印出我要运行

image.png

接入打包(下文有,这一part重点是交互式命令界面)

bin/rollup.js

// const rollup = require('rollup');
// const { devConfig } = require('./rollup.config');

async function devRollup(entry) {
  // 打包逻辑的配置
  // doSth...
}

module.exports = { devRollup };

bin/index.js

...
const { devRollup } = require('./rollup');

...

  .action((entry, type) => {
      const promptList = []
      inquirer.prompt(promptList).then((res) => {
        if (res.packEnv === 'dev') {
          console.log('我要运行')
          devRollup(entry);
        } else {
          console.log("我要打包")
        }
      })
  })
...

7.2,多个子命令

...

program
  .version('0.1.0')
  .description('this is a test')
  // 添加了一个子命令
  .command('pack [entry]')
  .description('this is a tool for pack')
  .option('-d, --dev', '开发模式')
  .option('-p, --prod', '生产模式')
  .action((entry, type) => {
    console.log(`entry :${entry}, type: ${JSON.stringify(type)}`)
  })
  
program
  .version('0.1.0')
  .description('this is a test')
  .command('create [project]') // 构建一个打包工具
  .description('这个命令可以创建模板')
  .action((project, type) => {
    console.log(`entry :${project}, type: ${JSON.stringify(type)}`)
  })
  
program.parse(process.argv)

如下图,可以看见多了一个create的命令

输入cluo-cli create projectDemo可以也可以打印action里的自定义内容

上面的交互式命令界面和这个cluo-cli create projectDemo是不是联想起了vue创建脚手架时候的流程😎~~~

image.png

二、项目和构建分离

到此,结束啦~~~ 哈哈

这篇文章越写感觉知识点越多,为了降低小伙伴们的心智负担,避免出现小伙伴一看滚动条根本拉不到尽头

顿时,就不想学了这种想法,这篇只聊下脚手架交互式命令界面的相关内容

项目和构建分离 通过命令在项目中生成脚手架提供的模板这两块内容请点击下方传送门噢

传送门:⚡node打怪升级系列 - 脚手架和项目那千丝万缕的关系

package.json文件

{
  "name": "cluo-cli",
  "version": "1.0.0",
  "bin": {
    "cluo-cli": "bin/index.js"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@babel/core": "^7.17.10",
    "@babel/preset-env": "^7.17.10",
    "@babel/preset-react": "^7.16.7",
    "commander": "^9.2.0",
    "fs-extra": "^10.1.0",
    "inquirer": "^8.2.4",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "rollup": "^2.71.1",
    "rollup-plugin-babel": "^4.4.0",
    "rollup-plugin-commonjs": "^10.1.0",
    "rollup-plugin-livereload": "^2.0.5",
    "rollup-plugin-node-resolve": "^5.2.0",
    "rollup-plugin-peer-deps-external": "^2.2.4",
    "rollup-plugin-serve": "^1.1.0"
  },
  "main": "babel.config.js",
  "devDependencies": {},
  "description": ""
}


完结

这篇文章我尽力把我的笔记和想法放到这了,希望对小伙伴有帮助。

欢迎转载,但请注明来源。

最后,希望小伙伴们给我个免费的点赞,祝大家心想事成,平安喜乐。

image.png