# 常见npm包

本文是vue-cli的学习blog

首先说一下常用的npm包,这样更方便之后的学习。

# commander

commander (opens new window)是一款重量轻,表现力和强大的命令行框架,提供了用户命令行输入和参数解析强大功能。

推荐使用minimist替代,源代码更小。

# Inquirer

Inquirer (opens new window) 为交互式命令行工具,比如执行 vue create 命令会有以下的命令行交互: 前度脚手架搭建_2020-05-04-19-44-12

# execa

execa (opens new window) 是可以调用 shell 和本地外部程序的 javascript 封装。会启动子进程执行,支持多操作系统,包括 windows,如果父进程退出,则生成的全部子进程都被杀死。它是在 Node.js 内置的 child_process.exec 基础上进行了提升,比如更好地支持 windows 平台,以及提供 Promise 的接口等等。

# handlebars

handlebars (opens new window) 是一个 javascript 语义模版库,而且与 Mustache 模板 是兼容的,通过一个 demo 来感受下:

var source = "<p>Hello, my name is {{name}}. I am from {{hometown}}. I have " +
             "{{kids.length}} kids:</p>" +
             "<ul>{{#kids}}<li>{{name}} is {{age}}</li>{{/kids}}</ul>";
var template = Handlebars.compile(source);
var data = { "name": "Alan", "hometown": "Somewhere, TX",
             "kids": [{"name": "Jimmy", "age": "12"}, {"name": "Sally", "age": "4"}]};
var result = template(data);
// Would render:
// <p>Hello, my name is Alan. I am from Somewhere, TX. I have 2 kids:</p>
// <ul>
//   <li>Jimmy is 12</li>
//   <li>Sally is 4</li>
// </ul>

# metalsmith

metalsmith (opens new window) 一个静态网站生成器,可以用在批量处理模板的场景,和 hexo 类似。它最大的特点就是所有的逻辑都是由插件处理,你只需要将这些插件用 metalsmith 连接起来使用即可

# chalk

chalk (opens new window) 是用于修改控制台字符串的样式,包括字体样式(加粗),颜色以及背景颜色等。 前度脚手架搭建_2020-05-04-19-58-51 使用比较简单:

const chalk = require('chalk');
console.log(chalk.blue('Hello world!'));

# download-git-repo

download-git-repo (opens new window) 是用于 从 GitHub, GitLab, Bitbucket 下载一个 git 仓库,API 如下:

download(repository, destination, options, callback)
  • repository:仓库地址。
  • destination:存放下载 git 仓库的路径。
  • options:选项,clone。是以 http download 的形式还是 git clone 的形式下载。其中 git clone 的形式支持下载 private 仓库。
  • callback:下载完成地回调。

# consolidate

consolidate (opens new window) 是一个模版引擎整合库,它的作用是把一些著名的模板引擎适配成 Express 兼容的接口

# SAO

# 介绍

通过配置文件快速生成脚手架工具,基于cac、chalk、enquirer、cross-spawn、ejs、fs-extra、ora等包。文档不完整,社区使用少,太长时间不维护。

#

# cac

# 介绍

类似commander,完整的命令行解决方案

# command

接收命令,参数(name,description,config?), name中[]表示可选参数。<>表示必填参数。

const cli = require('cac')()
cli.command('deploy <folder>', 'Deploy a folder to AWS')
cli
  .command('build [...otherFiles]', 'Build your app') // command支持多个参数

command执行完毕后实例带有option、action、alias、allowUnknownOptions、example、usage方法可执行。

# 默认command

只需要省略name,就可以创建一个默认command,这会在没有匹配到command时执行该命令。

cli
  .command('[...files]', 'Build files')
  .action((files, options) => {
    console.log(files)
  })

# command.option

设置命令的参数,参数:(name,description,config?),name中使用时[]表示该值可以为true,<>表示值为字符串或数字。括号内的内容可以随便写,不会影响接参和解析参数。

const cli = require('cac')()
cli
  .command('build [project]', 'Build a project')
  .option('--out <dir>', 'Output directory')

# 对象格式option

也叫做点嵌套option

yy create --env.a 123  // 会被解析成:{ '--': [], env: { a: 123 } }

# 数组格式option

输入多个相同的option时,解析到的参数就是数组形式

node cli.js --include project-a --include project-b  // { include: ['project-a', 'project-b'] }

# command.example

在输入commad时,输入-h,会提示相关示例。不会在命令行的顶级-h中显示。

const cli = require('cac')()
cli.command('create [file]').example("yy create -f")

在命令行输入yy create -h,会展示如下信息:

index.js/0.0.0
Usage:
  $ index.js create [file]
Examples:
yy create -f

# command.acition

接收用户命令的回调函数,参数:(...args,options)args如果是可变参数则为数组,

# help

在输入-h或者--help的时候,显示帮助信息。需要注册:cli.help()

# version

输入-v或者--version的时候显示版本信息,需要自定义:cli.version("0.0.1")

# Events

监听命令

// Listen to the `foo` command
cli.on('command:foo', () => {
  // Do something
})
// Listen to the default command
cli.on('command:!', () => {
  // Do something
})
// Listen to unknown commands
cli.on('command:*', () => {
  console.error('Invalid command: %s', cli.args.join(' '))
  process.exit(1)
})

# parse

只有在该方法调用时,cli.rawArgs cli.args cli.options cli.matchedCommand才会生效

# prompts

# 介绍

命令行中进行询问

const prompts = require('prompts');
(async () => {
  const response = await prompts({
    type: 'text',
    name: 'meaning',
    message: 'What is the meaning of life?'
  });
  console.log(response.meaning);
})();

还支持多个询问

const prompts = require('prompts');
const questions = [
  {
    type: 'text',
    name: 'username',
    message: 'What is your GitHub username?'
  },
  {
    type: 'number',
    name: 'age',
    message: 'How old are you?'
  },
  {
    type: 'text',
    name: 'about',
    message: 'Tell something about yourself',
    initial: 'Why should I?'
  }
];
(async () => {
  const response = await prompts(questions);
  // => response => { username, age, about }
})();

# Prompt Objects

询问对象,除了stdin和stdout其他key都可以为函数,当值为函数时,提供3个参数(prev,values,prompt),prev是上一个询问的值,values是所有询问的值,prompt是上一个询问对象

{
  type: String | Function,
  name: String | Function,
  message: String | Function,
  initial: String | Function | Async Function
  format: Function | Async Function,
  onRender: Function
  onState: Function
  stdin: Readable
  stdout: Writeable
}

# type

当type值为falsy时,跳过该问题。type的所有类型如下:

text
password
invisible
number
confirm
list
toggle
select
multiselect
autocompleteMultiselect
autocomplete
date

# Options

# onSubmit

(async () => {
  const questions = [{ ... }];
  const onSubmit = (prompt, answer) => console.log(`Thanks I got ${answer} from ${prompt.name}`);
  const response = await prompts(questions, { onSubmit });
})();

# onCancel

(async () => {
  const questions = [{ ... }];
  const onCancel = prompt => {
    console.log('Never stop prompting!');
    return true;
  }
  const response = await prompts(questions, { onCancel });
})();

# override

从命令行解析参数提前回答问题

const prompts = require('prompts');
prompts.override(require('yargs').argv);
(async () => {
  const response = await prompts([
    {
      type: 'text',
      name: 'twitter',
      message: `What's your twitter handle?`
    },
    {
      type: 'multiselect',
      name: 'color',
      message: 'Pick colors',
      choices: [
        { title: 'Red', value: '#ff0000' },
        { title: 'Green', value: '#00ff00' },
        { title: 'Blue', value: '#0000ff' }
      ],
    }
  ]);
  console.log(response);
})();

# inject

提前提供问题答案,此功能只用于测试

const prompts = require('prompts');
prompts.inject([ '@terkelg', ['#ff0000', '#0000ff'] ]);
(async () => {
  const response = await prompts([
    {
      type: 'text',
      name: 'twitter',
      message: `What's your twitter handle?`
    },
    {
      type: 'multiselect',
      name: 'color',
      message: 'Pick colors',
      choices: [
        { title: 'Red', value: '#ff0000' },
        { title: 'Green', value: '#00ff00' },
        { title: 'Blue', value: '#0000ff' }
      ],
    }
  ]);
  // => { twitter: 'terkelg', color: [ '#ff0000', '#0000ff' ] }
})();