脚手架架构设计和框架搭建

脚手架的作用

开发脚手架的核心目标是:提升前端研发效能

脚手架的核心价值

  1. 自动化:项目重复代码拷贝/git 操作/发布上线操作
  2. 标准化:项目创建/git flow/发布流程/回滚流程
  3. 数据化:研发过程系统化、数据化,使得研发过程可量化

和自动化构建工具的区别

  1. 不满足需求:jenkins、travis 通常在 git hooks 中触发,需要在服务端执行,无法覆盖研发人员本地的功能,如:创建项目自动挡化、本地 git 操作自动化等
  2. 定制负责:jenkins、travis 定制过程需要开发插件,其过程较为复杂,需要使用 java 语音,对前端开发不够友好

入门

脚手架本质上来说,是一个操作系统的客户端。
它通过命令行执行:

vue create vue-test-app

脚手架的实现原理

通过 npm 全局安装一个 脚手架例如 @vue/cli 后,会解析 package.json 文件中的 bin 配置 去在全局的bin目录下(/usr/local/bin),创建一个软连接,链接到全局的node_modules目录下 @vue对应的执行文件(../lib/node_modules/@vue/cli/bin/vue.js), 软连接的名称就是 bin 配置的 key,连接的文件就是 bin 配置的 value,value 指向的文件中需要设置 #! /usr/bin/env node 来标识文件需要用node来执行

基于 lerna 搭建自己的脚手架并且发布到 npm

安装方法

    npm install -g @sunshine-cli/core

执行命令

    sunshine-cli

进阶

理解 yargs 常用 API 和 开发流程

#!/usr/bin/env node
const yargs = require('yargs/yargs')
const dedent = require('dedent')
const log = require("npmlog")
const { hideBin } = require('yargs/helpers')
const pkg = require("../package.json");
const context = {
  lernaVersion: pkg.version,
};
const argv = process.argv.slice(2)
const listCommand = {
  command: 'list',
  describe: 'list local packsges',
  aliases: ["ls", "la", "ll"],
  builder: yargs => {
    return yargs
  },
  handler: argv => {
    console.log(argv)
  }
}
const cli = yargs()

yargs()
.usage("Usage: $0 <command> [options]") 
// 配置脚手架的用法
.demandCommand(1, "A command is required. Pass --help to see all available commands and options.")
// 配置最少需要参数的个数
.recommendCommands()
// 当输入的命令不对时,会根据算法去匹配最接近的正确命令的提示
.strict()
// 无法识别的信息错误提示
.command(listCommand)
// 向脚手架注入命令
.options({
  init: {
    describe: 'init scaffold',
    type: 'string',
    alias: 'i'
  }
})
.fail((msg, err) => {
  // certain yargs validations throw strings :P
  const actual = err || new Error(msg);
  // ValidationErrors are already logged, as are package errors
  if (actual.name !== "ValidationError" && !actual.pkg) {
    // the recommendCommands() message is too terse
    if (/Did you mean/.test(actual.message)) {
      console.log(cli.parsed, 'argv')
      log.error("lerna", `Unknown command `);
    }

    log.error("lerna", actual.message);
  }

  // exit non-zero so the CLI can be usefully chained
  cli.exit(actual.code > 0 ? actual.code : 1, actual);
})
.group(['help', 'version'], "Global Options:")
.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
`)
.parse(argv, context)

理解 lerna 实现原理

  • lerna 是基于git和npm的包管理工具
  • 实现原理
    1. 通过import-local判断当前工程中是否存在lerna包,有的话优先调用当前目录下的
    2. 通过yargs生成脚手架,主要包括globalOptions的创建、command注入、参数解析等等;command最主要的两个回调是builder和handler方法 ,分别的作用是builder用于构架命令是可以执行的参数、改命令用法的例子等,handler用于实现该命令的功能,比较重要
    3. lerna在本地开发时可以配置本地依赖,而不需要npm link的方式只需要在package.json中配置"@lerna/add": "file:../../commands/add", 即可,在代码发布时(lerna publish)会自动替换该路径

import-local 实现原理,理解 require.resolve 实现原理

  • import-local主要作用是查找本地项目中是否存在该package,有的话会优先用本地的,这样的好处是可以解除全局和本地版本冲突的问题
  • 实现原理 重要实现
    • fs.realPathSync该方法当找到路劲中存在软连接时,会重头开发在查找一遍,这样做的目的是为了防止软连接中还有软连接
    • 遍历过程中生成的子路径会缓存到knownHard和cache中,这样的好处是提高查询效率;
    • 遍历完成后得到的真实路径也会添加到缓存中,key为原始路径origin,下次就可以直接从缓存中拿到结果
Copyright © imooc-lego (2020 - present) all right reserved,powered by GitbookFile Modify: 2021-06-27 08:04:56

results matching ""

    No results matching ""