❏ Yeoman脚手架工具的价值讨论
❏ generator[生成器
]的内部结构
❏ generator[生成器
]的项目模板
❏ Yeoman脚手架工具的核心运起色制
❏ Yeoman 的主要组装流程css
全部新事物都不是凭空产生的,它们的出现总有某些内在的驱动力。一项新技术,一个新工具的出现更是如此。不知道从何时开始起,我接触新事物新技术以及某些工具的时候,总愿意多花点时间想想它出现的缘由是什么?由于时间、精力等等这些东西都很宝贵,IT从业人员对这些资源尤为敏感,因此新技术或者新工具的出现我认为有几种状况:html
更完美的替代方案
解决问题的技术方案
如今,咱们来研究下Yeoman的价值,或者说Yeoman出现的意义是什么?Yeoman的出现解决了什么样的问题?前端
咱们假设有这样的开发场景:公司的开发团队,基于某些特定的技术栈已经完成了项目A的开发和上线等工做,项目A的基本状况以下node
技术栈:JavaScript + HTML + CSS + Bootstrap + jQuery
工做流:npm(包管理工具) + bower(下载器) + grunt
版本管理工具:Gitjquery
项目总体目录结构(简化后)git
. ├── Gruntfile.js ├── bower.json ├── node_modules │ ├── abbrev ··· │ └── xtend ├── package-lock.json ├── package.json ├── build │ ├── css │ │ └── style.min.css │ └── js │ ├── index.js │ └── index.min.js ├── dist └── src ├── css │ └── style.css ├── index.html ├── js │ └── index.js ├── libs │ ├── bootstrap │ └── jquery └── template
由于项目A已经上线发布,如今公司要求着手开展新的项目B,通过需求评审和技术选型后,新项目B采用的工做流和项目A保持一致,技术栈在原有的基础上尝试使用TypeScript来处理脚本部分引入Vue框架,其它部分保持不变。咱们发现项目A和项目B它们的结构基本上是一致的(好比项目的目录就够,都须要拥有Gruntfile.js和package.json等文件),可是有些部分又不太同样,好比package.json文件中的项目名称、开发依赖等。typescript
这个时候,咱们在对项目B进行初始化的方式能够尝试如下操做方式:npm
若是咱们采用方案① 你会发现这个过程你在初始化项目A的时候就已经作过了,是重复性的工做,毫无技术含量可是又费时费力。
若是咱们采用方案② 你会发现要修改的文件有些多,每一个文件要改的字段也比较多,并且容易遗漏老是调不通会出现各类问题,心烦意乱。json
若是你会使用Yeoman脚手架工具的话,那么对于上面的开发场景你就会多一个方案③,在使用方案③来初始化项目B的时候,你只须要动动手指在终端中输入$ yo 生成器名称
再使用交互方式简单配置某些特定值,初始化的工做就完成了。这就是Yeoman的价值所在,初始化项目的时候你没必要再把本身沉入到琐碎重复无技术成长的费力工做中,也没必要老是像个机器人般进入到拷贝-粘贴-修改这样无止境的循环中。脚手架工具是那么的简单直接和高效,你甚至能够省出点加班的时间来看世界杯了 : )bootstrap
我知道有一些杠精要出来喷了。“解决这种初始化问题不用搞的这么复杂,我彻底能够把项目结构和固定不变的部分抽取出来托管到gitHub仓库,要初始化项目的时候 $ git clone一下不就行了吗?”
说的颇有道理,可是clone下来的仓库虽然结构和必要文件已经准备好了,但不少文件是否是还得修改?那你会顶回来“难道使用Yeoman初始化就不须要修改了吗?”
固然也要修改,不过就算是修改那改起来也颇有趣味还So快!
另外,若是新项目的总体结构以及技术选型和已有的项目很不同,那你抽取后交由git管理的仓库就没用了,由于八字不合啊。使用Yeoman就没用这样的顾虑,在Yeoman-generator列表有好几千现成的generator供你选择,总有一款适合你!!!
我要求太太…过高,实在谁也看不上?不要紧,generator这家伙还能够私人订制,你彻底能够根据本身的需求来定制须要的generator,你一高兴甚至还能把它发布到社区造福全人类。
搞清楚 generator的价值所在和应用场景以后,咱们就能够开始谈论generator相关的话题了,前面介绍过Yeoman脚手架工具的做用是帮助咱们依据特定的技术栈需求来初始化项目,在安装了yo工具以后,只须要在终端中使用相似$ yo generator--xx
的命令先安装对应的generator而后再$ yo xx
搭建便可。至于如何找到匹配当前技术选型的generator,能够去官网的generator列表搜索,这些生成器中有很大一部分来自于对应框架的做者或者Yeoman官方团队,质量有保证且更新很及时。固然,咱们也能够建立本身的generator并发布。关于如何建立本身的generator,咱们放到另外一篇文章Yeoman脚手架生成器建立来解决。
简单说Yeoman作的工做其实就是根据当前的生成器(generator)来复制固定的项目模板文件到新项目中,而新项目中的某些文件须要配置,这部分工做由安装时候的交互式指令来完成(至关于传递参数给模板文件)。
generator主要由组装指令
和项目模板
两部分组成。
组装指令
Yeoman generator中的generators/app/index.js文件是整个生成器的核心部分,该文件用于告知Yeoman该如何来组织并搭建项目,咱们能够在该文件中设置初始化项目时必要的安装提示和选项来让用户选择,以及每一个文件应该如何复制和修改,是否须要加载依赖和Node包等内容。
项目模板
项目模板包括初始化项目须要的全部必须文件。这些文件又能够简单的划分为固定文件
、灵活文件
、可选文件
和依赖文件
。所谓固定文件
就是在每一个初始项目中都如出一辙的文件,譬如index.js、style.css等文件,在具体处理的时候这些文件只须要简单复制便可。灵活文件
指的是那些须要根据用户选择来作简单修改而后才能复制的文件,譬如index.html文件(title等信息需根据用户输入来指定)。对于可选文件
来讲,它们并非必须的,譬如某些基础框架有的项目中须要,有的项目中也许并不须要,这部分文件的处理方式须要交给用户来决定。
前面已经介绍过了Yeoman生成器的组成部分主要是组装指令和项目模板。对于整个Yeman脚手架工具来讲,项目模板这部分就至关因而搭建脚手架须要用到的原材料,而组装指令用来决定和控制全部的具体行动是什么。
如今咱们开始深刻的来讨论项目模板这部份内容,须要先明白的是“可以知足全部需求的万能的项目模板是不存在的”
。由于这世界上每一个项目组,每一个产品甚至每一个人的需求(要求)都各有不一样。因此,在实践中你必需要对当前项目的需求和采用的技术栈有深刻的理解,这样你才能知道目标项目的目录结构会是什么样的? 哪些文件是必不可少的。
若是你的项目和采用的技术栈比较大众化,那么搜索一个合适的generator基本就能知足需求,拿来主义便可。若是你的项目无论结构仍是所采用的技术看上去都那么的非凡和特别,那么就多花一点点时间建立个本身的generator吧,若是你须要处理多个这样的项目,那就更应该了。在建立或者理解generator的时候,咱们能够根据前面对项目模板文件的划分状况来区别对待不一样的文件。
固定文件
固定文件是在每一个项目中初始内容都同样的必要文件。
好比咱们可能老是会把代码的结构划分为src
、build
和dist
三个目录,在src目录下面拥有js、css和lib文件目录,index.js和style.css等文件。这些文件都是必要的,刚开始的时候多是空的或者只有几行简单的代码。这些文件的特色是,在使用组装指令操做(一般是复制-移动)这些文件的时候,不须要对它们进行任何的修改。
灵活文件
灵活文件和固定文件差很少,也是初始化项目所必须的,但不一样的项目中这些文件的内容也会稍有不一样,这些不一样之处可能很细微(好比仅仅是名字、协议这些),也可能差别巨大。好比,咱们经常使用的构建工做流中的bower.json
和package.json
文件,它们是必不可少的,可是它们都须要当前项目的项目名称和协议等信息才能正常工做。像这样的灵活文件还有index.html,在这个文件中的title标签中应该使用当前项目的名称。
灵活文件中的部份内容须要在安装该生成器的时候,由用户交互式配置输入的信息来进行设定。
可选文件
可选文件并非搭建初始化项目时所必须的文件,若是没有那么不要紧,若是有那彷佛更好。这些通常在用户交互式配置的时候,以是否题的方式交由用户决定,譬如是否使用less 是否安装Bootstrap等。
依赖文件
依赖文件指的是某些经常使用的框架、插件或者是Node模块,这些文件并不须要你在项目模板文件中提供,而后经过组装指令去一个个复制。由于基本上成熟的项目中都会使用既定的工做流(主要包括依赖和包的下载、项目的自动化构建等),因此咱们彻底只须要在package.json
或者bower.json
等文件中设置好依赖便可,而后在组装指令的相关代码中经过this.installDependencies()
相似的代码来调用npm或者是bower执行install命令便可。
当您为项目准备好(搜索或本身建立)合适的generator以后,就能够用它们来搭建项目了。generator的执行须要在终端中使用yo命令来操做。yo是Yeoman的核心命令,主要用来链接生成器和项目结构。咱们能够把yo命令理解为generator的执行器,它知道怎么找到对应的generator,也知道该如何执行它们。
在使用yo命令行工具和生成器来初始化项目以前,须要先把指定的生成器(generator)下载安装到本地(若是是本身建立的生成器,那么能够经过$ npm link
命令以软链接的方式生成一个全局的npm包,个人是mac OSX系统,生成的npm包会保存在/usr/local/lib/node_modules/路径,若是使用的是别人发布的generator,那么请使用$ npm install -g generator-xxx
的方式来安装)。
这里须要注意的是yo命令行工具主要负责前期工做,在使用的时候它主要检查当前安装的generator有哪些,指定的generator是否可以正常工做,若是能,那么它就会调用generator的组装指令,把剩下部分的工做交接给generator来完成。generator接管项目的组装流程以后,会按app/index.js中的要求来处理文件的复制等工做
。
下面给出脚手架工具初始化项目时的核心流程。
这里对yo的主要命令进行简单说明
$ yo
执行该命令的时候,yo会搜索并列出全部本地可用的生成器$ yo 生成器名称
好比对于generator-typescript
生成器,那么执行的命令就是$ yo typescript
。该命令会先检查enerator-typescript
生成器是否可用。若是可用,那么就接着以 ①交互式配置 ② 写入文件 ③ 下载安装依赖的顺序来执行组装指令。
组装指令是用来让Yeoman建立项目所需文件的一系列具体的命令(代码)。典型的组装流程分为三个步骤:
① 交互式配置。这个步骤经过向用户提问或直接输入配置信息来完成模板传参。
② 写入文件。把项目模板中的指定文件复制到新项目的指定目录中。
③ 安装依赖。下载并安装全部保存在bower.json和package.json文件中的依赖和Node模块。
① 交互式配置
Yeoman在执行生成器的时候,首先会执行安装提示以交互式的方式来询问用户,目的是为了获取生成器所须要的一些参数,好比项目的名称、做者、使用的开原协议以及是否安装和使用某些组件等。
这部分功能,须要使用到inquirer包,这个包的做用是生成选项来让用户选择。下面给出代码示例:
prompting() { const prompts = [ { type : 'input', name : 'appName', message : '请输入项目名称:', default : this.appname //appname是内置对象,表明工程名,这里就是ys }, { type : 'input', name : 'appAuthor', message : '请输入做者姓名:', default : '文顶顶' }, { type: 'list', name: 'appLicense', message: '请选择使用的license:', choices: ['MIT', 'ISC', 'Apache-2.0', 'AGPL-3.0'] }, { type : 'confirm', name : 'isIncludeBootstrap', message : '是否须要使用bootStrap框架?', default : false }, ]; return this.prompt(prompts).then(props => { // To access props later use this.props.someAnswer; this.props = props; });
咱们能够看到在代码中,这些交互式配置都由prompts来进行维护,prompts是一个对象数组,数组中的每一个元素对象就表明着一个具体的安装提示,在使用yo命令运行该生成器的时候,它的执行状况以下:
_-----_ ╭──────────────────────────╮ | | │ 欢迎使用 │ |--(o)--| │ generator-wen! │ `---------´ │ Author:文顶顶 │ ( _´U`_ ) ╰──────────────────────────╯ /___A___\ / | ~ | __'.___.'__ ´ ` |° ´ Y ` ? 请输入项目名称: wendingdingTest ? 请输入做者姓名: 文顶顶 ? 请选择使用的license: Apache-2.0 ? 是否须要使用bootStrap框架? (y/N) yes
prompts中的每一个对象元素就表明着一个安装提示,上面代码一共提供了四个安装提示。每一个对象中的type属性用于代表交互的类型,其中输入项目名称和做者姓名是input型的
,表示接收用户的输入,至关于填空题。选择使用的license是list
型的,它提供了多个选项供用户选择,您能够认为这种类型是单选题。是否须要使用bootStrap框架是confirm
型的,默认为false,若是须要安装那么须要输入YES,这至关因而非题。
交互式配置过程当中用户作出的全部选择和输入都会被保存到this.props对象中,能够经过访问this.props.isIncludeBootstrap属性来肯定是否须要安装Bootstrap。
message属性
保存是每一条安装提示的提示信息。name属性
是最重要的属性之一,它做为key用来访问用户的选择结果。default属性
保存的是默认值,即当用户跳过当前安装提示的时候,name对应的value值将使用default中保存的默认值来设置。
② 写入文件
写入文件这个过程会把项目模板复制到指定的目录中,若是是固定文件那么就直接拷贝,若是是灵活文件那么还须要把某些参数传递给指定的模板文件。这个过程在代码中由writing() 函数体现,另外系统还提供了两个函数(fs.copyTpl和fs.copy
)用来执行具体的操做。
writing() { mkdirp("build"); //建立build文件目录 mkdirp("dist"); //建立dist文件目录 mkdirp("src/template"); //建立src/template文件目录 //传递参数this.props.appName渲染index.html文件 //把项目模板中的index.html文件复制到新项目的src路径下 this.fs.copyTpl( this.templatePath('index.html'), this.destinationPath('src/index.html'), {appName: this.props.appName} ); //把项目模板中的style.css文件复制到新项目的src/css路径下 this.fs.copy( this.templatePath('css/style.css'), this.destinationPath('src/css/style.css') ); //...... }
fs.copy方法会把指定文件复制到目标路径。
fs.copyTpl方法会先传递参数给模板文件,通过模板引擎处理后再进行复制。
③ 下载和安装依赖
这个阶段作的事情很是简单,就是调用npm或者是bower来下载并安装依赖和相关的node模块。Yeoman提供了几个对应的方法来处理这个过程。
this.npmInstall()
使用Npm来安装package.json中的依赖和模块,至关于在终端中输入$ npm install
指令。
this.bowerInstall()
使用Bower来安装bower.json中的依赖和模块,至关于在终端中输入$ bower install
指令。
this.installDependencies()
调用Bower和Npm而且安装package.json和bower.json中依赖的全部模块,至关于前后调用了npmInstall和bowerInstall方法。
最后,为了帮助更好的理解Yeoman组装流程的三个阶段,给出下面的示意图。