常见 npm 包

在进去 vue-cli 源码学习之前,这里先介绍下在 vue-cli 项目中用到的一些必备的 npm 包,这样在后面分析源码的时候会比较快的理解(handlebarsmetalsmithconsolidate 主要用于 vue init 命令)。

  • commander:node.js command-line interfaces made easy。
  • Inquirer:A collection of common interactive command line user interfaces。
  • execa:A better child_process
  • handlebars:一个 javascript 语义模版库。
  • metalsmith;An extremely simple, pluggable static site generator。
  • chalk:Terminal string styling done right。
  • download-git-repo:Download and extract a git repository (GitHub, GitLab, Bitbucket) from node。
  • consolidate:Template engine consolidation library for node.js 。

下面逐个介绍:

commander

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

#!/usr/bin/env node

const program = require('commander')

program
  .version('0.0.1')
  .command('rmdir <dir> [otherDirs...]')
  .action(function(dir, otherDirs) {
    console.log('rmdir %s', dir);
    if (otherDirs) {
      otherDirs.forEach(function(oDir) {
        console.log('rmdir %s', oDir);
      });
    }
  });

program.parse(process.argv);

这段代码为 commander.js 官方的一个示例,它展示了 commander.js 可变参数的特性,可以在 action 的回调中获取对应的参数,当然也可以通过 process.argv 获取,commander.js 中文文档

Inquirer

Inquirer 为交互式命令行工具,比如执行 vue create 命令会有以下的命令行交互:

Inquirer 的基本使用如下:

var inquirer = require('inquirer');
inquirer
  .prompt([
    /* Pass your questions in here */
  ])
  .then(answers => {
    // Use user feedback for... whatever!!
  });

inquirer.prompt 接受一个 questions 数组, 一个 question 对象包含 typenamemessagedefault 等等字段,然后通过回调获取命令行交互的值,详细文档

execa

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

const execa = require('execa');

(async () => {
	const {stdout} = await execa('echo', ['unicorns']);
	console.log(stdout);
	//=> 'unicorns'
})();

上面例子就是执行 echo unicorns 命令输出 unicorns。关于 execa 更多的用法可查看 详细文档

handlebars

handlebars 是一个 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>

这是官方的一个 demo, 就是通过 Handlebarscompile 方法将模板编译成 html 。在 vue-cliinit 命令中,利用 Handlebars.registerHelper 方法注册了一些 helper,这样就可以在模板中方便的使用这些 helper详细文档

metalsmith

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

Metalsmith(__dirname)
  .use(markdown())
  .use(layouts('handlebars'))
  .build(function(err) {
    if (err) throw err;
    console.log('Build finished!');
  });

这段代码就是通过使用 metalsmith-markdownmetalsmith-layouts 插件 将 markdown 文件以 handlebars 的模板形式来生成html 文件,在 vue-cliinit 命令中使用了三个插件:askQuestions filterFiles renderTemplateFiles 从这名字就知道这个插件的作用了。编写 metalsmith 其实不是很难,官方对插件的编写介绍地比较详细,示例代码:

metalsmith-myplugin:

// we would like you to use debug
var debug = require('debug')('metalsmith-myplugin');
var multimatch = require('multimatch');

// Expose `plugin`.
module.exports = plugin;

function plugin(opts){
  opts.pattern = opts.pattern || [];

  return function (files, metalsmith, done){

    setImmediate(done);
    Object.keys(files).forEach(function(file){
      if(multimatch(file, opts.pattern).length) {
        debug('myplugin working on: %s', file);

        //
        // here would be your code
        //

      }
    });
  };
}

关于 metalsmith 的更多介绍以及语法可查看详细文档

chalk

chalk 是用于修改控制台字符串的样式,包括字体样式(加粗),颜色以及背景颜色等。

使用比较简单:

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

更多的用法以及 API 可查看详细文档

download-git-repo

download-git-repo 是用于 从 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 是一个模版引擎整合库,它的作用是把一些著名的模板引擎适配成 Express 兼容的接口。在 vue-cliinit 命令中利用 consolidate.handlebars.render 是实现模版的渲染。在 /example/metalsmith 目录里有个 demo,就是通过 metalsmith 以及consolidate.handlebars.render 方法将一个 package.jsonhandlebars 的模板引擎来渲染,在项目里运行

npm run metalsmith

希望可以通过这个小 demo 可以比较好地理解 metalsmithhandlebarsconsolidate 以及inquirer,关于 consolidate 的更多语法请查看详细文档

总结

这部分主要介绍了在利用 node 搭建脚手架工具时一些常见的 npm 包,对这些 npm 包进行一定的了解后,在后面看源码的时候会比较容易些,下面开始进行源码分析。