前端工程化系列[06]-Yeoman脚手架核心机制

前端工程化系列[05] Yeoman脚手架使用入门这边文章中,对Yeoman的使用做了简单的入门介绍,这篇文章我们将接着探讨Yeoman这个脚手架工具内部的核心机制,主要包括以下内容

? Yeoman脚手架工具的价值讨论
? generator[生成器]的内部结构
? generator[生成器]的项目模板
? Yeoman脚手架工具的核心运转机制
? Yeoman 的主要组装流程

Yeoman这样的脚手架工具解决了什么问题?

所有新事物都不是凭空产生的,它们的出现总有某些内在的驱动力。一项新技术,一个新工具的出现更是如此。不知道从什么时候开始起,我接触新事物新技术以及某些工具的时候,总愿意多花点时间想一想它出现的原因是什么?因为时间、精力等等这些东西都很宝贵,IT从业人员对这些资源尤其敏感,所以新技术或者新工具的出现我认为有几种情况:

  • 已有的技术或工具存在缺陷,作者们靠自己的才学推出更完美的替代方案
  • 已有的技术或工具无法解决既定的需求,作者们探索出解决问题的技术方案
  • 纯粹闲的蛋疼(这种情况一般比较少见)

现在,我们来研究下Yeoman的价值,或者说Yeoman出现的意义是什么?Yeoman的出现解决了什么样的问题?

我们假设有这样的开发场景:公司的开发团队,基于某些特定的技术栈已经完成了项目A的开发和上线等工作,项目A的基本情况如下

技术栈:JavaScript + HTML + CSS + Bootstrap + jQuery
工作流:npm(包管理工具) + bower(下载器) + grunt
版本管理工具: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

说明:上面的目录中src为代码的工作目录,bulid为构建后目录,dist为发布目录。

因为项目A已经上线发布,现在公司要求着手开展新的项目B,经过需求评审和技术选型后,新项目B采用的工作流和项目A保持一致,技术栈在原有的基础上尝试使用TypeScript来处理脚本部分引入Vue框架,其它部分保持不变。我们发现项目A和项目B它们的结构基本上是一致的(比如项目的目录就够,都需要拥有Gruntfile.js和package.json等文件),但是有些部分又不太一样,比如package.json文件中的项目名称、开发依赖等。

这个时候,我们在对项目B进行初始化的方式可以尝试以下操作方式:

  • 方案① 从0开始创建目录结构,集成工作流配置开发环境
  • 方案② 从项目A中拷贝目录结构和固定文件,对于不同的部分一个个修改

如果我们采用方案① 你会发现这个过程你在初始化项目A的时候就已经做过了,是重复性的工作,毫无技术含量但是又费时费力。
如果我们采用方案② 你会发现要修改的文件有些多,每个文件要改的字段也比较多,而且容易遗漏总是调不通会出现各种问题,心烦意乱。

如果你会使用Yeoman脚手架工具的话,那么对于上面的开发场景你就会多一个方案③,在使用方案③来初始化项目B的时候,你只需要动动手指在终端中输入$ yo 生成器名称再使用交互方式简单配置某些特定值,初始化的工作就完成了。这就是Yeoman的价值所在,初始化项目的时候你不必再把自己沉入到琐碎重复无技术成长的费力工作中,也不必总是像个机器人般进入到拷贝-粘贴-修改这样无止境的循环中。脚手架工具是那么的简单直接和高效,你甚至可以省出点加班的时间来看世界杯了 : )

我知道有一些杠精要出来喷了。“解决这种初始化问题不用搞的这么复杂,我完全可以把项目结构和固定不变的部分抽取出来托管到gitHub仓库,要初始化项目的时候 $ git clone一下不就好了吗?”

说的很有道理,但是clone下来的仓库虽然结构和必要文件已经准备好了,但很多文件是不是还得修改?那你会顶回来“难道使用Yeoman初始化就不需要修改了吗?”当然也要修改,不过就算是修改那改起来也很有趣味还So快!

Yeoman使用交互式的方式来对项目文件中需要灵活处理的部分进行配置,这部分内容我们称为组装指令,具体再文章的后面会进行讲解。

另外,如果新项目的整体结构以及技术选型和已有的项目很不一样,那你抽取后交由git管理的仓库就没用了,因为八字不合啊。使用Yeoman就没用这样的顾虑,在Yeoman-generator列表有好几千现成的generator供你选择,总有一款适合你!!!

我要求太太…太高,实在谁也看不上?没关系,generator这家伙还可以私人订制,你完全可以根据自己的需求来定制需要的generator,你一高兴甚至还能把它发布到社区造福全人类。

Yeoman-generator的内部结构

搞清楚 generator的价值所在和应用场景之后,我们就可以开始谈论generator相关的话题了,前面介绍过Yeoman脚手架工具的作用是帮助我们依据特定的技术栈需求来初始化项目,在安装了yo工具之后,只需要在终端中使用类似$ yo generator--xx的命令先安装对应的generator然后再$ yo xx搭建即可。至于如何找到匹配当前技术选型的generator,可以去官网的generator列表搜索,这些生成器中有很大一部分来自于对应框架的作者或者Yeoman官方团队,质量有保证且更新很及时。当然,我们也可以创建自己的generator并发布。关于如何创建自己的generator,我们放到另一篇文章Yeoman脚手架生成器创建来解决。

简单说Yeoman做的工作其实就是根据当前的生成器(generator)来复制固定的项目模板文件到新项目中,而新项目中的某些文件需要配置,这部分工作由安装时候的交互式指令来完成(相当于传递参数给模板文件)。

需要注意的是,Yeoman的设计仅仅只提供了一小部分核心的API,而真正繁重的初始化工作是交给每个具体的generator来完成的。

generator主要由组装指令项目模板两部分组成。

组装指令

Yeoman generator中的generators/app/index.js文件是整个生成器的核心部分,该文件用于告知Yeoman该如何来组织并搭建项目,我们可以在该文件中设置初始化项目时必要的安装提示和选项来让用户选择,以及每个文件应该如何复制和修改,是否需要加载依赖和Node包等内容。

项目模板

项目模板包括初始化项目需要的所有必须文件。这些文件又可以简单的划分为固定文件灵活文件可选文件依赖文件。所谓固定文件就是在每个初始项目中都一模一样的文件,譬如index.js、style.css等文件,在具体处理的时候这些文件只需要简单复制即可。灵活文件指的是那些需要根据用户选择来做简单修改然后才能复制的文件,譬如index.html文件(title等信息需根据用户输入来指定)。对于可选文件来说,它们并不是必须的,譬如某些基础框架有的项目中需要,有的项目中也许并不需要,这部分文件的处理方式需要交给用户来决定

项目模板文件的类别

前面已经介绍过了Yeoman生成器的组成部分主要是组装指令和项目模板。对于整个Yeman脚手架工具来说,项目模板这部分就相当于是搭建脚手架需要用到的原材料,而组装指令用来决定和控制所有的具体行动是什么。

现在我们开始深入的来讨论项目模板这部分内容,需要先明白的是“能够满足所有需求的万能的项目模板是不存在的”。因为这世界上每个项目组,每个产品甚至每个人的需求(要求)都各有不同。所以,在实践中你必须要对当前项目的需求和采用的技术栈有深入的理解,这样你才能知道目标项目的目录结构会是什么样的? 哪些文件是必不可少的。

如果你的项目和采用的技术栈比较大众化,那么搜索一个合适的generator基本就能满足需求,拿来主义即可。如果你的项目不管结构还是所采用的技术看上去都那么的非凡和特别,那么就多花一点点时间创建个自己的generator吧,如果你需要处理多个这样的项目,那就更应该了。在创建或者理解generator的时候,我们可以根据前面对项目模板文件的划分情况来区别对待不同的文件。

固定文件

固定文件是在每个项目中初始内容都一样的必要文件。

比如我们可能总是会把代码的结构划分为srcbuilddist三个目录,在src目录下面拥有js、css和lib文件目录,index.js和style.css等文件。这些文件都是必要的,刚开始的时候可能是空的或者只有几行简单的代码。这些文件的特点是,在使用组装指令操作(通常是复制-移动)这些文件的时候,不需要对它们进行任何的修改。

灵活文件

灵活文件和固定文件差不多,也是初始化项目所必须的,但不同的项目中这些文件的内容也会稍有不同,这些不同之处可能很细微(比如仅仅是名字、协议这些),也可能差异巨大。比如,我们常用的构建工作流中的bower.jsonpackage.json文件,它们是必不可少的,但是它们都需要当前项目的项目名称和协议等信息才能正常工作。像这样的灵活文件还有index.html,在这个文件中的title标签中应该使用当前项目的名称。

灵活文件中的部分内容需要在安装该生成器的时候,由用户交互式配置输入的信息来进行设定。

可选文件

可选文件并不是搭建初始化项目时所必须的文件,如果没有那么没关系,如果有那似乎更好。这些一般在用户交互式配置的时候,以是否题的方式交由用户决定,譬如是否使用less 是否安装Bootstrap等。

依赖文件

依赖文件指的是某些常用的框架、插件或者是Node模块,这些文件并不需要你在项目模板文件中提供,然后通过组装指令去一个个复制。因为基本上成熟的项目中都会使用既定的工作流(主要包括依赖和包的下载、项目的自动化构建等),所以我们完全只需要在package.json或者bower.json等文件中设置好依赖即可,然后在组装指令的相关代码中通过this.installDependencies()类似的代码来调用npm或者是bower执行install命令即可。

Yeoman脚手架运转的核心机制

当您为项目准备好(搜索或自己创建)合适的generator之后,就可以用它们来搭建项目了。generator的执行需要在终端中使用yo命令来操作。yo是Yeoman的核心命令,主要用来连接生成器和项目结构。我们可以把yo命令理解为generator的执行器,它知道怎么找到对应的generator,也知道该如何执行它们。

注意:yo基于NodeJS且需要在任何文件目录中使用,所以在安装yo命令的时候应该使用-g来进行全局安装。安装过程请参考:Yeoman脚手架使用入门

在使用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的主要组装流程

组装指令是用来让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,这相当于是非题。

交互式配置这部分可以根据项目的实际情况来设置prompts中的对象元素,除上面介绍的这些类型外,您还可以通过查看inquirer.js的文档来获取更多内容。

交互式配置过程中用户做出的所有选择和输入都会被保存到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组装流程的三个阶段,给出下面的示意图。



前端工程化系列[06]-Yeoman脚手架核心机制

原文地址:https://www.cnblogs.com/wendingding/p/9938874.html

时间: 2024-11-09 18:41:34

前端工程化系列[06]-Yeoman脚手架核心机制的相关文章

前端工程化系列[03]-Grunt构建工具的运转机制

在前端工程化系列[02]-Grunt构建工具的基本使用这篇文章中,已经对Grunt做了简单的介绍,此外,我们还知道了该如何来安装Grunt环境,以及使用一些常见的插件了,这篇文章主要介绍Grunt的核心组件和运转机制. Grunt是一套前端自动化构建工具,可以帮助我们简化开发中需要反复处理的任务,甚至可以实现自动构建等功能. Grunt拥有数量庞大的插件,这些插件能够帮助我们处理开发中遇到的绝大多数构建任务,比如代码的预编译.压缩.代码检查.单元测试等.但为什么在终端输入Grunt相关命令,就能

前端工程化系列[01]-Bower包管理工具的使用

本文主要介绍前端开发中常用的包管理工具Bower,具体包括Bower的基本情况.安装.使用和常见命令等内容,最后还介绍了依赖树管理的常见方式以及Bower采用的策略并进行了比较. 1.1 关于Bower Bower是一款优秀的包管理器,它由Twitter公司开发,支持以命令行的方式来对包进行搜索.下载.更新和卸载. 模块或组件指独立完整的模块,可以是应用的一部分或者是扩展,依赖可以是jQuery或backbone这样的库,也可以像Bootstrap这样的UI框架或者是UI组件. 包英文(pack

前端优化带来的思考,浅谈前端工程化

重复优化的思考 这段时间对项目做了一次整体的优化,全站有了20%左右的提升(本来载入速度已经1.2S左右了,优化度很低),算一算已经做了四轮的全站性能优化了,回顾几次的优化手段,基本上几个字就能说清楚: 传输层面:减少请求数,降低请求量执行层面:减少重绘&回流 传输层面的从来都是优化的核心点,而这个层面的优化要对浏览器有一个基本的认识,比如: ① 网页自上而下的解析渲染,边解析边渲染,页面内CSS文件会阻塞渲染,异步CSS文件会导致回流 ② 浏览器在document下载结束会检测静态资源,新开线

腾讯IVWEB前端工程化工具feflow思考与实践

本篇文章主要介绍腾讯IVWEB团队从0到1在工程化的思考和实践.feflow的全称是Front-end flow(前端工作流),致力于提升研发效率和规范的工程化解决方案.愿景是通过feflow,可以使项目创建.开发.构建.规范检查到最终项目上线的整个过程更加自动化和标准化. 要解决的问题 项目的目录结构按约定生成 团队有一套开发规范进行约束 支持多种类型的构建,包括Fis构建和webpack构建 团队内部的代码贡献统计.离线包内置App等 为了解决上述问题,我们于17年2月底开始投入工程化fef

58到家周俊鹏:webpack PK fis,实现前端工程化我更喜欢前者

责编:陈秋歌,关注前端开发领域,寻求报道或者投稿请发邮件chenqg#csdn.net. 欢迎加入"CSDN前端开发者"微信群,参与热点.难点技术交流.请加群主微信「Rachel_qg」,申请入群,务必注明「公司+职位」.另可申请加入CSDN前端开发QQ群:465281214. 2016年,SDCC(中国软件开发者大会)相继走进了上海.深圳.成都.杭州各地.11月18日-20日将在北京完美收官.作为大会的重要分专题,前端开发专题已邀请到58到家高级前端工程师周俊鹏担任大会讲师,现场将分

四大维度解锁Webpack3.0前端工程化

四大维度解锁Webpack3.0前端工程化网盘地址:https://pan.baidu.com/s/1NBzFqMELoFxxvFtxp0YluQ 密码: pd36备用地址(腾讯微云):https://share.weiyun.com/50QY3pp 密码:d4uwwj 第1章 课程简介讲述课程背景,从前端开发的变化 到 前端工具的发展变化,介绍了课程内容,课程安排. 第2章 学习准备讲述模块化开发的思想.学习环境准备,webpack 的概况,版本更迭,核心概念等,为开始实践学习webpack

浅析前端工程化

1. 什么是前端工程化 自有前端工程师这个称谓以来,前端的发展可谓是日新月异.相比较已经非常成熟的其他领域,前端虽是后起之秀,但其野蛮生长是其他领域不能比的.虽然前端技术飞快发展,但是前端整体的工程生态并没有同步跟进.目前绝大多数的前端团队仍然使用非常原始的"切图(FE)->套模板(RD)"的开发模式,这种模式下的前端开发虽说不是刀耕火种的原始状态,但是效率非常低下. 前端的工程化问题与传统的软件工程虽然有所不同,但是面临的问题是一样的.我们首先回顾一下传统的软件开发流程模型:

JavaScript进阶系列06,事件委托

在"JavaScript进阶系列05,事件的执行时机, 使用addEventListener为元素同时注册多个事件,事件参数"中已经有了一个跨浏览器的事件处理机制.现在需要使用这个事件处理机制为页面元素注册事件方法. □ 点击页面任何部分触发事件 创建一个script1.js文件. (function() { eventUtility.addEvent(document, "click", function(evt) { alert('hello'); }); }(

java io系列06之 序列化总结(Serializable 和 Externalizable)

本章,我们对序列化进行深入的学习和探讨.学习内容,包括序列化的作用.用途.用法,以及对实现序列化的2种方式Serializable和Externalizable的深入研究. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_06.html 1. 序列化是的作用和用途 序列化,就是为了保存对象的状态:而与之对应的反序列化,则可以把保存的对象状态再读出来. 简言之:序列化/反序列化,是Java提供一种专门用于的保存/恢复对象状态的机制. 一般在以下几种