1. 脚手架实现原理,基于 Lerna 搭建自己的脚手架并发布到npm
1.1脚手架简述
脚手架本质是一个操作系统得客户端,它通过命令行执行
vue create vue-test-app
上面这条命令主要由3个部分组成
- 主命令 
vue - command 
create - command的 param 
vue-test-app 
1.2脚手架的执行原理图

脚手架的执行原理如下:
- 在终端输入 
vue create vue-test-app - 终端解析出 
vue命令 - 终端在环境变量中找到 
vue命令 - 终端根据 
vue命令链接倒实际文件vue.js - 终端利用 
node执行vue.js vue.js解析 command / optionsvue.js执行 command- 执行完毕,退出执行
 
1.3为什么全局安装 @vue/cli 后会添加的命令为 vue?
全局安装脚手架,会根据脚手架根目录的package.json 中的 bin 来决定脚手架的命令
"bin": {
    "vue": "bin/vue.js"
}
1.4全局安装 @vue/cli 时发生了什么?
全局安装脚手架后,会在node的目录下的node_modules生成 @vue 的脚手架包,并且会在 node的安装目录下生成一个vue环境变量,而这个环境变量的名字就取决于 @vue 的脚手架包根目录的 package.json 中的bin
1.5为什么 vue 执行一个 js 文件,我们却可以直接通过vue命令去执行它?
因为在脚手架根目录的 package.json 中的bin 所指向的真正执行的 vue.js 中有
#!/usr/bin/env node
相当于我们执行 node vue.js
2. 理解 Yargs 常用 API 和开发流程
const yargs  = require('yargs/yargs')
// 一个ES6字符串标签,从多行字符串中去除缩进。
const dedent = require("dedent");
const cli = yargs()
const argv = process.argv.slice(2)
// 注入额外参数
const context = {
  diaoVersion: '1.0.0',
};
cli
  // 开启严格模式,输入无效命令会报错无法识别命令
  .strict()
  // 在头部输出一段信息
  .usage('Usage: diao-cli [command] <options>')
  // 设置需要输入命令的最小值,这里设置最少输入一个命令,否则则抛出错误信息
  .demandCommand(1, "A command is required. Pass --help to see all available commands and options.")
  // 如果没有找到匹配的命令,yargs提供关于类似命令的建议
  .recommendCommands()
  // 在有错误的时候执行,可以在这里自定义错误信息
  .fail((err, msg) => {
    console.error('err:', err)
  })
  // 设置 command 的别名
  .alias('h', 'help')
  .alias('v', 'version')
  // 设置命令行输出时候的宽度
  .wrap(cli.terminalWidth())
  // 在命令行末尾打印的消息
  .epilogue(dedent`
    When a command fails, all logs are written to lerna-debug.log in the current working directory.
    For more information, find our manual at https://github.com/lerna/lerna
  `)
  // 配置额外选项
  .options({
    debug: {
      type: 'boolean',
      describe: 'Bootstrap debug mode',
      alias: 'd'
    }
  })
  // 配置额外选项
  .option("registry", {
    type: "string",
    describe: 'Define global registry',
    alias: 'r'
  })
  // 对选项进行分组
  .group(['debug'], 'Dev Options')
  .group(['registry'], 'Extra Options')
  // 注册命令
  .command('init [name]', 'Do init a project', (yargs) => {
    yargs
      .option('name', {
        type: 'string',
        describe: 'Name of a project',
        alias: 'n'
      })
  }, (argv) => {
    console.log(argv)
  })
  // 注册命令
  .command({
    command: 'list',
    aliases: ['ls', 'la', 'll'],
    describe: 'List local packages',
    builder: (yargs) => {},
    handler: (argv) => {
      console.log(argv)
    }
  })
  // 解析命令输入参数
  .parse(argv, context)
3. 理解 Lerna 实现原理
Lerna 是基于 git+npm 的多package项目管理工具
3.1常用命令
npm init -y
npm install -g lerna (// 全局安装)
npm install lerna
lerna -v ( // 输出版本号说明安装成功)
lerna init (// 初始化lerna项目,会创建一个lerna.json)
// 经过上面init这一步,会初始化git仓库,再搞一个.gitignore 配置一些不用上传的目录
git remote xxx (// 添加远程仓库)
lerna create core (// 创建一个package)
lerna create utils(// 又创建了一个package)
lerna add (// 批量给两个package都安装依赖)
lerna publish (// 发布项目)
3.2Lerna 实现原理
懵逼中,后面回过头再看~
4. 理解 import-local 实现原理,理解 require.resolve 实现原理
懵逼中,后面回过头再看~