前端工程化日益盛行,脚手架成为了咱们平常开发中必不可少的东西,例如:vue-cli、react-create-app
等等。前端
使用脚手架,咱们能够很方便的简化咱们的开发流程,有效的提升咱们的研发能效vue
例如咱们须要从零开始搭建一个项目,首先须要去建立目录,在个目录下去建立相应初始化的文件,去配置 webpack、gulp、rollup
等模块打包器,这每每会花费咱们一天甚至数天的时间。然而脚手架只须要在命令行敲入简简单单的一行命令,便可在短短的几分钟内为你建立一个项目模板,极大程度上节省了咱们的时间成本。java
相信大部分的同窗对脚手架的认识只停留在使用上面,今儿咱们就来了解一下脚手架的原理。node
注:本文章是使用 Node.js 进行脚手架开发的react
你们能够想想脚手架的做用是什么?开发脚手架的核心目标是什么?webpack
没错,就是提高研发效能!git
项目重复、代码拷贝、git 操做、发布上线操做
项目建立、git flow、发布流程、回滚流程
研发过程系统化、数据化、使研发过程能够被量化
有的同窗可能会问到,世面上已经有了 jenkins、travis
等自动化构建工具了,并且也很成熟,为何还要开发相关的脚手架?web
jenkins、travis
一般在 git hooks
中触发,须要在服务端执行,没法覆盖研发人员本地的功能,如:建立项目自动化、本地 git
操做自动化等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 也有了更深刻的了解。也是突破现有技术瓶颈的一个方向,也是做为一个高级前端开发工程师必需要掌握的技能。