交互式的 NPM Scripts

Author Avatar
l19861225q 6月 29, 2017
  • 在其它设备中阅读本文章

尽管 Webpack 2 默认支持从终端传参数到配置文件中来实现定制:

–env.x=xxx

但每次开发都需要在命令行输入冗长且难记的各种参数:

npm run dev – –env.p=xxx –env.s –env.r …

希望可以屏蔽这些细节,提供一个交互式的终端用户界面。
先看一下最终效果:

支持会话的终端界面 - Inquirer.js

Inquirer.js 可以预设一组问题来收集用户答案,支持过滤、验证等特性。

定义问题

这里我需要两个提问:

  • 将要开发哪个项目(必填)
  • 可选配置(是否生成雪碧图、是否使用 CSS Module 等)
const questions = [
  {
    name: 'project',
    message: 'Please input the project name:',
    // 验证:这个答案必填才继续后面的问题
    validate: (str) => Boolean(str.length)
  },
  {
    name: 'conf',
    type: 'checkbox',
    message: 'Please make your choice:',
    choices: [
      { name: 'Sprite (是否生成雪碧图)', value: 's' },
      { name: 'Retina (是否支持 Retina 雪碧图)', value: 'r' },
      { name: 'CSS Module (是否使用 CSS Module)', value: 'm' },
      { name: 'Use React (是否使用 React, 默认 Preact)', value: 'R' }
    ]
  }
]

收集答案

--color 来让终端始终高亮显示强调的内容。Inquirer 支持 Promise 特性,代码看起来也十分的简介、优雅。

const args = ['--color']
inquirer.prompt(questions).then(function ({ project, conf }) {
  // 拼接成 Webpack 2 规定的参数格式
  args.push(`--env.p=${project}`)

  conf.map((command) => args.push(`--env.${command}`))
})

终端 Loading 动画 - ora

ora 优雅的终端 Loading 动画

因为 webpack 的配置文件使用了 ES6,在启动前需要先经过 Babel 转码,需要一定的时间,这时如果能给终端 Loading 的反馈,用户体验将是美好的。

console.log('\n') // 和上面 Inquirer 的问题保留一个空行更美观

const oraInstance = ora({
  color: 'cyan',
  text: 'Please waiting for the webpack start'
}).start()

这里返回了 ora 的实例,后面需要显示的调用 ora 的 API stop & clear 来停止并移除 ora .

用于 Node.js 的 shell 命令 - shellJS

ShellJS 是 Node.js API 之上的 shell 命令的便携式(Windows / Linux / OS X)实现。

我需要在 js 文件里执行原先定义在 package.json 中的 scripts 命令。

const child = shell.exec(`
  NODE_ENV=development webpack --hide-modules ${args}
`, { async: true }) // 异步执行速度更快哦

这里返回了子线程的实例 child,后面会用到他的 stdoutstderr 实现监听终端输出的功能。

// npm run dev
// Stop and clear the ora when webpack started
child.stdout.on('data', function (data) {
  if (data.toLowerCase().includes('webpack')) {
    oraInstance.stop() // 停止 ora 动画
    oraInstance.clear() // 移除 ora
  }
})

因为 ora 的实现原理是不断刷新终端输出来达到动画的效果,如果不移除会造成 webpack stdout 的闪现,体验很差。

NODE_ENV=production 模式下,Webpack 只会产生标准错误输出 stderr,所以监听有些许改变:

// npm run build
child.stderr.on('data', function (data) {
  if (data.toLowerCase().includes('compiling')) {
    oraInstance.stop()
    oraInstance.clear()
  }
})

OK~ 愉快地 coding 吧 ^_^