脚手架闲聊 | 七日打卡

楔子

前端工程化日益盛行,脚手架成为了咱们平常开发中必不可少的东西,例如:vue-cli、react-create-app 等等。前端

使用脚手架,咱们能够很方便的简化咱们的开发流程,有效的提升咱们的研发能效vue

例如咱们须要从零开始搭建一个项目,首先须要去建立目录,在个目录下去建立相应初始化的文件,去配置 webpack、gulp、rollup 等模块打包器,这每每会花费咱们一天甚至数天的时间。然而脚手架只须要在命令行敲入简简单单的一行命令,便可在短短的几分钟内为你建立一个项目模板,极大程度上节省了咱们的时间成本。java

相信大部分的同窗对脚手架的认识只停留在使用上面,今儿咱们就来了解一下脚手架的原理。node

注:本文章是使用 Node.js 进行脚手架开发的react

脚手架的做用

你们能够想想脚手架的做用是什么?开发脚手架的核心目标是什么?webpack

没错,就是提高研发效能!git

脚手架的核心价值

  1. 自动化:项目重复、代码拷贝、git 操做、发布上线操做
  2. 标准化:项目建立、git flow、发布流程、回滚流程
  3. 数据化:研发过程系统化、数据化、使研发过程能够被量化

和自动化构建工具的区别

有的同窗可能会问到,世面上已经有了 jenkins、travis 等自动化构建工具了,并且也很成熟,为何还要开发相关的脚手架?web

  1. 需求不知足:jenkins、travis 一般在 git hooks 中触发,须要在服务端执行,没法覆盖研发人员本地的功能,如:建立项目自动化、本地 git 操做自动化等
  2. 定制复杂:jenkins、travis 定制过程须要开发插件,其过程较为复杂,须要使用 java 语言,对前端开发不够友好

脚手架的本质

脚手架本质上来讲,其实就是一个操做系统的客户端。vue-cli

它经过命令行来执行,例如:npm

vue create vue-project
复制代码

脚手架的执行原理

为何咱们在命令行中输入 vue create vue-project 后就能执行呢?

用户在命令行中输入了命令 vue create vue-project ,操做系统首先会在全局的环境变量里面去查找 vue 这个环境变量,找到后就会去执行它,没有找到就会报错,以下图所示:

脚手架的实现原理

经过 npm 全局安装一个脚手架例如 @vue/cli 后,会去解析 package.json 文件中的 bin 配置,而后会去在 node 的安装目录下的 bin 目录中,建立一个软链接而且链接到软件包中,软链接的名称就是 bin 配置的 key(键值对的键),链接的文件就是 bin 配置的 value(键值对的值)value 指向的文件中须要设置 #! /usr/bin/env node 来标识文件执行的方法

实现一个最简单的脚手架

第一步:咱们须要建立一个文件夹 test-cli;
第二步:在命令行中,进入到 test-cli 文件夹,而后执行 npm init 初始化项目;
第三步:修改 package.json 文件,在里面的配置项里加上以下的:

{
    ...
    "bin": {
      "test-cli": "./bin/index.js"
    },
    ...
}
复制代码

第四步:在 test-cli 里面新建一个 bin 文件夹,而且在里面建立一个 index.js 文件,接下来打开 index.js 文件在里面第一行写上 #! /usr/bin/env node;
第五步:能够写上一些内容了,好比 console.log('xxx') 滑稽脸;
第六步:在命令行中,进入到 test-cli 文件夹,而后执行 npm link;
第七步:在命令行中,输入 test-cli 而且回车,你就会发如今命令行中就会打印出 xxx;

这就是一个最简单的脚手架了,若是你想作的更好一点的,好比经常使用脚手架的一些命令式操做能够了解一下 yargs、commander 两个插件,这里给上一个基于 commander 的注册命令的代码,有兴趣的同窗能够复制到刚刚的 index.js 里面执行一下 test-cli --help

#! /usr/bin/env node

const commander = require('commander')
const pkg = require('../package.json')

// 获取 commander 的单例
// const { program } = commander

// 手动实例化一个 commander 实例
const program = new commander.Command()

program
    .name(Object.keys(pkg.bin)[0])
    .usage('<command> [options]')
    .version(pkg.version)
    .option('-d, --debug', '是否开启调试模式', false)
    .option('-e, --env <envName>', '获取环境变量名称', false)

// addCommand 注册子命令
const service = new commander.Command('service')
service
    .command('start [port]')
    .description('start service at some port')
    .action((prot, cmdObj) => {
        console.log('do server start', prot)
    })
service
    .command('stop')
    .description('stop service')
    .action(() => {
        console.log('do server stop')
    })


program.addCommand(service)

program.on('option:debug', () => {
    console.log('debug')
})

program.on('command:*', (obj) => {
    console.log('未知的命令', obj)
    const availableCommands = program.commands.map(cmd => cmd.name())
    console.log('可用的命令', availableCommands)
})

program    
    .parse(process.argv)

// console.log(program.debug)
// console.log(program.env)
// console.log(program.opts())
复制代码

总结

脚手架的开发博大精深,它为我打开了一个新世界的大门,同时也让我对 Node.js 也有了更深刻的了解。也是突破现有技术瓶颈的一个方向,也是做为一个高级前端开发工程师必需要掌握的技能。

相关文章
相关标签/搜索