【nodejs脚手架开发】交互处理-Inquirer.js篇

2021-08-30 21:49:42 浏览数 (2)

【nodejs脚手架开发】交互处理-Inquirer.js篇

上一篇 文章讲解了nodejs开发的第一步,命令处理,命令处理的短板是无法处理复杂的选项,而inquier.js解决了这一问题。这篇文章继续介绍脚手架中的交互处理。

什么是交互?

说交互可能会引发一些歧义,我个人习惯将交互理解为客服,我们在购物的时候,客服会向你问一系列的问题,比如:

  • 你的性别是?
  • 你的身高是?
  • 请您选一个衣服颜色(红,黄,白,绿, 黑)
  • 体恤还是夹克?
  • 。。。。

等等问题,然后会根据你的需求,向你推荐合适的衣服。而Inquirer.js在命令行开发中则承担了这一角色,让我们根据使用者的需要,来做相应的处理。比如vue-cli中的vue create命令,在创建项目时会问以下问题:

  • 选择预设:Please pick a preset
  • 选择特性:Check the features needed for your project
  • 选择vue版本:Choose a version of Vue.js that you want to start the project with
  • 选择css预处理器:Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default)
  • 选择eslint校验时机:Pick additional lint features
  • 。。。。

什么是Inquirer.js?

如图,inquirer.js主要包括问题的类型和问题的处理两个部分,问题的类型包含:

  • input:可以理解为填空题,需要用户输入
  • confirm: 由用户通过快捷键y/n选择是/否,判断题
  • list: 无序列表单选题
  • rawlist: 有序列表单选题
  • expand: 可以通过key定义快捷选择,如A, B, C, D 选择题
  • checkbox: 多选题
  • pasword: 密码输入,输入时掩码代替显示
  • editor: 通过vim编辑器输入

问题的处理比较简单也比较丰富,主要包括以下属性:

  • message: 问题的描述
  • name: 问题答案值的属性名,可以理解为form表单prop
  • choices: 选项列表
  • pagesize: choices过多时每页显示的个数
  • surfix和prefix:问题描述的前后缀
  • default: 默认值
  • when: 问题回答后的回调函数,可以处理问题的依赖关系
  • filter: 对回答进行过滤
  • validate: 对回答进行验证
  • transformer: 对回答进行格式化显示,但不会改变回答的值

讲了这么多概念,如果我们要做一个选择题,写法如下:

代码语言:txt复制
const inquirer = require('inquirer')

const propmtList = [{
  type: 'list',
  message: 'Please pick a preset',
  name: 'preset',
  choices: [
    "Default ([Vue 2] babel, eslint)",
    "Default (Vue 3 Preview) ([Vue 3] babel, eslint)",
    "Manually select features"
  ],
}]

inquirer.prompt(propmtList);

运行效果如下:

实现vue create效果

代码语言:txt复制
const program = require('commander');
const inquirer = require('inquirer')

const propmtList = [{
  type: 'list',
  message: 'Please pick a preset',
  name: 'preset',
  choices: [
    "Default ([Vue 2] babel, eslint)",
    "Default (Vue 3 Preview) ([Vue 3] babel, eslint)",
    "Manually select features"
  ],
}, {
  type: 'checkbox',
  message: 'Check the features needed for your project',
  name: 'features',
  choices: [{
    name: 'Choose Vue version',
    checked: true,
  }, {
    name: 'Babel',
    checked: true,
  }, {
    name: 'TypeScript',
  }, {
    name: 'Progressive Web App (PWA) Support',
  }, {
    name: 'Router',
  }, {
    name: 'Vuex',
  }, {
    name: 'CSS Pre-processors',
  }, {
    name: 'Linter / Formatter',
    checked: true,
  }, {
    name: 'Unit Testing',
    checked: true,
  }, {
    name: 'E2E Testing',
    checked: true,
  }],
  pageSize: 10,
}, {
  type: 'list',
  message: 'Choose a version of Vue.js that you want to start the project with',
  name: 'version',
  choices: [
    "2.x",
    "3.x (Preview)"
  ],
}, {
  type: 'confirm',
  message: 'Use history mode for router? (Requires proper server setup for index fallback in production)',
  name: 'routerMode',
  default: ''
}, {
  type: 'list',
  name: 'cssProcessor',
  message: 'Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default)',
  choices: [
    "Sass/SCSS (with dart-sass)",
    "Sass/SCSS (with node-sass)",
    "Less",
    "Stylus",
  ]
}, {
  type: 'checkbox',
  name: 'lint',
  message: 'Pick additional lint features',
  choices: [
    "Lint on save",
    "Lint and fix on commit",
  ]
}, {
  type: 'list',
  name: 'where',
  message: 'Where do you prefer placing config for Babel, ESLint, etc.?',
  choices: [
    "In dedicated config files",
    "In package.json",
  ]
}, {
  type: 'confirm',
  name: 'save',
  message: 'Save this as a preset for future projects? ',
}];

program.usage('Usage: create [options] <app-name>')
  .argument('[app-name]')
  .showHelpAfterError()
  .description('create a new project powered by vue-cli-service')
  .option('-p, --preset <presetName>', 'Skip prompts and use saved or remote preset')
  .option('-d, --default', 'Skip prompts and use default preset')
  .option('-i, --inlinePreset <json>', 'Skip prompts and use inline JSON string as preset')
  .option('-m, --packageManager <command>', 'Use specified npm client when installing dependencies')
  .option('-r, --registry <url>', 'Use specified npm registry when installing dependencies (only for npm)')
  .option('-g, --git [message]', 'Force git initialization with initial commit message')
  .option('-n, --no-git', 'Skip git initialization')
  .option('--merge', 'Merge target directory if it exists')
  .option('-c, --clone', 'Use git clone when fetching remote preset')
  .option('-x, --proxy <proxyUrl>', 'Use specified proxy when creating project')
  .option('-b, --bare', 'Scaffold project without beginner instructions')
  .option('--skipGetStarted', 'Merge target directory if it exists')
  .action((name, options, command) => {
    if (!name) {
      program.help();
      return;
    } 
    inquirer.prompt(propmtList).then(answer => {
      console.log(answer);
    });
  })
  .parse();

运行效果

代码语言:txt复制
node ./bin/my-cli.js create

没有输入工程名称时自动答应帮助信息:

代码语言:txt复制
node ./bin/my-cli.js create hello

选择预设

选择特性

选择vue版本

是否使用history模式

选择css预处理器

选择eslint执行时机

选择babel config的存储位置

是否存为预设

打印用户的所有选择

总结

inquirer.js的实现简洁而优雅,文档清晰明了,对于脚手架开发的交互处理简单方便,定义了丰富的问题类型,和问题处理方法,简单易学,结合模拟实现vue-cli实现,有利于了解vue-cli是如何工作的。

0 人点赞