乐趣区

关于javascript:学习vuecli背后的过程

vue create my-vue-project 执行后产生了什么,程序执行

  • 【零碎】零碎定位到 bin/vue.js 文件,通过 node bin/vue.js create my-project 来执行该文件;
  • 【vue.js】bin/vue.js利用 commander 来定义命令选项 create,将create 命令匹配到 create 办法(lib/create.js),执行该办法;
  • 【create.js】lib/create.js应用 Inquirer.js 来询问用户,进行我的项目配置;
  • 【Creator.js】依据用户配置生成 package.json 文件(根底信息,从我的项目配置中注入对应的开发依赖 devDependencies);
  • 【Creator.js】执行 npm i 来装置依赖;(PS: 这里封装了罕用的 npm 操作,能够间接拷贝到本人我的项目中应用)
  • 【Creator.js】加载 vue-cli 插件(@vue/cli-service 是第一个被执行的插件);
  • 【Generator.js】执行所有插件(执行 cli-service 插件会生成我的项目文件构造);
  • 【Creator.js】生成 README.md 文件;

下面就是 create 命令的根本执行过程,如果咱们想扩大 create 办法,例如依照咱们的定义的模板生成目录构造,能够新建一个插件(generator,能够参考 cli-service),在插件里生成自定义的目录构造即可。

一,命令执行过程

当你在控制台敲下 npm -v 并回车的时候,到底产生了什么?

咱们先来看看 npm 这个命令在哪。通过执行 which npm,(不理解 which 命令的同学能够参考这里:linux 命令之 which),能够看到,npm 命令的可执行文件在 /usr/local/bin/npm,关上文件夹一看,是个替身,右键“显示原身”(Mac 用户的办法,其余用户请搜寻“软链接”),就能定位到该命令在哪:/usr/local/lib/node_modules/npm/bin/npm-cli.js,看到是 js 代码置信大家曾经松了一口气,咱们先不急着看npm-cli.js 外面的源,咱们先思考一个问题:

Q1:零碎是怎么找到 npm 这个这个命令的可执行文件的?

A1:理解 which 命令的同学都晓得,which命令会依照 PATH 变量中的门路程序来查找可执行文件。执行 echo $PATH 能够打印出该变量内容:/usr/local/bin:/usr/bin:/bin(例如这是我的局部内容,目录间用‘:’分隔),所以零碎会先在 /usr/local/bin 上面找 npm 执行文件,/usr/local/bin/npm链接到 /usr/local/lib/node_modules/npm/bin/npm-cli.js。所以调用npm 命令相当于执行npm-cli.js

总的来说:在控制台执行命令时,零碎会先去环境门路(PATH)中找到可执行文件,而后执行该文件

那么,有同学好奇:

Q2:零碎又是怎么执行这些文件 (例如下面的 npm-cli) 的呢?

A2:关上 npm-cli.js 文件,咱们能看到的第一行代码就是:#!/usr/bin/env node,这行代码到底有什么用呢?具体可参考:stackoverflow – #!/usr/bin/env 到底有什么用?,大抵意思是 告知零碎用什么解释程序来执行该文件 ,例如#!/usr/bin/env node 就是告知零碎,npm-cli.js要用 node 来执行。因而 npm -v 相当于node /usr/local/lib/node_modules/npm/bin/npm-cli.js -v

$ node /usr/local/lib/node_modules/npm/bin/npm-cli.js -v
6.4.1

二,npm 包打造 cli 的原理

理解完命令执行过程之后,咱们就能够打造本人的 cli 命令了。

①先编写 my-cli.js 文件:

#!/usr/bin/env node
console.log('Hello cli!');

②在 /usr/local/bin 下(或者 PATH 里的任意门路下)创立软链接:

ln -s my-cli.js my-cli

③给 my-cli 命令增加可执行权限:(若不增加权限,会报错bash: /usr/local/bin/my-cli: Permission denied)

chmod 777 my-cli

④验证成果:

$ my-cli
Hello cli!

在下面的根底上,咱们尽管能打造本人的命令,然而这个命令要想给团队应用,就须要每个人都拷贝 my-cli.js 文件,创立软链接,增加可执行权限,十分繁琐。怎么将本人的命令散发进来给他人应用呢?

咱们再往前摸索一步,一起打造一个基于 npm 散发的命令。

咱们在下载应用一个 npm 模块命令的时候,咱们会这样:

npm install -g @vue/cli
vue create my-project

全局装置 vue-cli 这个 npm 模块之后,咱们全局新增了 vue 命令,这背地到底产生了什么?是 npm install 帮咱们把下面提到的②③步主动执行了 (如有谬误,欢送指出)。既然npm 曾经帮咱们实现这些简略然而繁琐的脚本操作,那咱们只须要依照 npm 的标准来配置一下代码即可。流程比较简单,请参考:通过 npm 包来制作命令行工具的原理。

总结一下开发过程:

  1. npm init新建 npm 模块目录;
  2. 开发命令(例如下面的my-cli.js);
  3. package.json中增加 bin 字段(bin: {"my-cli": "./my-cli.js"});
  4. 公布 npm;
  5. 全局装置即可应用my-cli;

三,VUE-CLI 中外围库

vue-cli 源码 理解怎么优雅地实现一个 cli。

介绍几个 vue-cli 外面用到的几个库:

  1. commander – 命令行参数解析库;
  2. Inquirer.js – 命令行罕用交互模式汇合(问答,抉择 …);
  3. chalk – 在命令行款式丑化;
  4. ora – 命令行 loader;

commander简直是开发 cli 必不可少的工具,原理(参考 commander 源码),根本应用办法如下:

#!/usr/bin/env node
var program = require('commander');

program
  .version('0.1.0')
  .option('-p, --peppers', 'Add peppers')
  .option('-P, --pineapple', 'Add pineapple')
  .option('-b, --bbq-sauce', 'Add bbq sauce')
  .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
  .parse(process.argv);

外围流程如下:

1. 通过 option 定义收集命令的性能选项;

2. parse 解析命令参数(有 process 取得);

3. 由命令参数去匹配后面收集到的性能选项,执行后面的办法(将参数传入);

/**
 * Parse `argv`, settings options and invoking commands when defined.
 *
 * @param {Array} argv
 * @return {Command} for chaining
 * @api public
 */

Command.prototype.parse = function(argv) {
  // implicit help
  if (this.executables) this.addImplicitHelpCommand();

  // store raw args
  this.rawArgs = argv;

  // guess name
  this._name = this._name || basename(argv[1], '.js');

  // github-style sub-commands with no sub-command
  if (this.executables && argv.length < 3 && !this.defaultExecutable) {
    // this user needs help
    argv.push('--help');
  }

  // process argv
  var parsed = this.parseOptions(this.normalize(argv.slice(2)));
  var args = this.args = parsed.args;

  var result = this.parseArgs(this.args, parsed.unknown);

  // executable sub-commands
  var name = result.args[0];

  var aliasCommand = null;
  // check alias of sub commands
  if (name) {aliasCommand = this.commands.filter(function(command) {return command.alias() === name;
    })[0];
  }

  if (this._execs[name] && typeof this._execs[name] !== 'function') {return this.executeSubCommand(argv, args, parsed.unknown);
  } else if (aliasCommand) {
    // is alias of a subCommand
    args[0] = aliasCommand._name;
    return this.executeSubCommand(argv, args, parsed.unknown);
  } else if (this.defaultExecutable) {
    // use the default subcommand
    args.unshift(this.defaultExecutable);
    return this.executeSubCommand(argv, args, parsed.unknown);
  }

  return result;
};

原文参考:cli 原理解析

退出移动版