聊聊前端脚手架

一、许多团队在制定前端工程方案时会加入脚手架模块。虽然不同的团队对工程化的理解和实施有所差异,但是对于脚手架的定位基本是一致的:创建项目初始文件。这是一条看起来十分简单地准则,但是对于这条准则应该如何理解,如何实施却并不是一件很简单地事情。

二、在探索这条准则的深度之前,我们不妨看看类似的一些成熟方案,比如Eclipse。这个大名鼎鼎的IDE软件被很多Java和Android开发者使用。通过Eclipse创建一个新项目时,它提供了丰富的配置项,这些配置项可以归纳简化为以下流程:选择项目类型 -> 选择项目目录 -> 配置项目细节 -> 最终确认 -> 完成。这是脚手架最基本也是必须具备的流程。从这个流程中可以总结出脚手架的本质:方案的封装。

三、脚手架作用是创建项目的初始文件,本质是方案的封装。

1.脚手架在前端工程中的角色

1.1 “用完即弃”的脚手架
595796-20170330204649539-235709455.jpg

脚手架在前端工作流中负责项目起始阶段创建初始文件。与其他功能模块不同的是,脚手架是一个完全“启下”的模块,它没有任何前置依赖。创建完成项目初始文件之后,脚手架就再无用武之地了。
“用完即弃”的工作模式令脚手架的实现由很大的跃迁性。你可以用最简单的复制粘贴就能完成脚手架的工作,而一个完备、成熟的脚手架即使提供了非常丰富的交互配置,最终目的也“只”是创建了一堆初始的项目文件。既然结果一样,那为什么还要花费时间和人力成品去开发复杂的脚手架方案呢?

这是一个非常现实的问题,互联网产品迭代的快速节奏下,开发团队最注重的就是投入产出比,而脚手架的投入产出比“看上去”是最低的。环顾目前前端的工具生态,最多的是构建工具,当然我们不可否定构建确实是最复杂的功能。而脚手架工具是最少的,前端社区对脚手架的讨论也非常稀少。你可能听说过大名鼎鼎的yeoman,但是很难再想出第二个脚手架工具了。
单独来看,脚手架可能并不具备很高的“性价比”,但如果你的团队有一套完整的前端工程体系,脚手架的作用就会被放大。前端工程体系的功能涵盖范围广,封装的方案类型多,对应的配置项也非常复杂。而且,大多数前端工程体系的开发者并不是一线的业务开发者。对于业务开发者来说,这套工程体系就是一个黑盒,他们不需要了解其中的复杂原理,只需要知道如何配置即可。所以业务开发者的需求就是快速开发快速配置,并且生成的配置项跟项目要对应,既要满足项目的功能需求,又不能有“混淆视听”的冗余功能。
前端工程体系不是Vue、React这种开发框架,工程体系只是一种“服务”,是辅助性质的。学习曲线应该平缓,即使文档再清晰易懂,也不应该要求业务开发者去花时间学习各种细节。这就是脚手架要解决的切实问题,简单说就是:
- 快速生成配置;
- 降低框架学习成本。
随着前端工程体系越来越复杂,脚手架的角色会越来越重要。
######1.2 脚手架需要具备的要素
1.2.1 执行环境仅限本地
在讨论实现一个脚手架要考虑哪些要素之前,我们不妨先看看脚手架的执行环境。回顾前文提到的简易前端工作流,最简单的情形是:框架提供一套完整的本地工具链,脚手架、开发、开发服务器、构建和部署测试都是在本地环境执行,如下图:
![595796-20170330204704883-611380969.png](http://upload-images.jianshu.io/upload_images/6380152-a8b9d510490efe2b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
进一步的团队会搭建CI(持续集成)平台,将构建和部署功能迁移至云端,这样做便于工作流程控制和代码统一管理。如下图:
![595796-20170330204715086-1453851525.png](http://upload-images.jianshu.io/upload_images/6380152-91cf6b80ed43320e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
不论哪种工作流,脚手架始终是在本地执行。
1.2.2 模式不固定
前端脚手架之所以没有固定的模式,是由于不同的公司对于前端工程师的定位不固定。比如有些公司的前端仍然是“切图仔”;有些公司的前端负责浏览器端的所有逻辑开发但是html模板层仍然由服务端工程师维护;还有些比较前沿的团队提倡“大前端”,负责浏览器层与中间层(主要承载html的渲染功能)。前端工程师定位的不固定造成了前端项目模式的不固定,脚手架自然也具备了多样性。
不论是哪种工作模式,一个优秀的前端脚手架都应该具备以下几点要素:
      1.丰富但不繁琐的配置项;
      2.与其他功能模块联动,生成对应的基本配置项;
      3.自动安装依赖;
      4.底层的高度可扩展性;
      5.支持多种运行环境,比如命令行和Node.js API。
如何理解“丰富但不繁琐”呢?举个例子,假设构建功能支持自动生成css sprites,配置项有两个:
    1.是否启用css sprites;
    2.指定散列icon目录。
脚手架在实现针对css sprites的配置项时是不是应该将这两个配置都开放给用户配置呢?显然是不需要的,脚手架只要开放是否启用css sprites的配置项即可,因为这是影响这项功能最重要的一点,散列icon的目录即使用户不配置,使用默认的方案也不会造成任何不便。
另外,在实现脚手架时不应该只看到当前的需求,还应该考虑后续需求的变更和新增。所以一个优秀的脚手架应该具备高度的可扩展性,便于定制不同类型的方案。从这个角度来说,目前yeoman是做得最好的。

####2. 开源前端脚手架方案剖析
>明确了脚手架的基本工作模式,我们不妨看看目前业内有哪些可以借鉴的案例。我们在这里介绍三种形态的脚手架:
- [sails](http://sailsjs.com/)是一个Node.js fullstack框架,其使用的[sails generate](http://sailsjs.com/documentation/reference/command-line-interface/sails-generate)脚手架主要是针对服务端代码设计;
- 优酷PHP中间层框架是笔者前团队使用的开发框架,目前并未开源。其使用的脚手架相对sails来说比较简单,只能创建一个完整的webapp,包括Controller层和浏览器层代码;
- [yeoman](http://yeoman.io/)是广为人知的开源脚手架工具,它本身不提供任何直接创建文件的功能,而是一个脚手架底层框架,你可以定制自己的脚手架实现。
######2.1 sails - Node.js fullstack框架
sails是一个Node.js全栈框架,服务端使用MVC架构。[sails generate](http://sailsjs.com/documentation/reference/command-line-interface/sails-generate)是sails的脚手架模块,默认可以创建以下几种模块的初始代码:
- app - 创建一个新sails项目;
- api - 创建一对model和controller;
- model - 创建一个model;
- controller - 创建一个controller;
- adapter - 创建一个adapter;
- generator - 创建一个脚手架模板。
~~~sails框架中的[Adapter](http://sailsjs.com/documentation/concepts/extending-sails/adapters)可以简单理解为简化model操作API的映射适配器。
大家注意最后一种类型:generator。sails在默认的脚手架基础上,开放了自定义脚手架模板的[API](http://sailsjs.com/documentation/concepts/extending-sails/generators/custom-generators)。
sails默认的脚手架大都是针对服务端代码的,如果不借助其他脚手架模板,浏览器端的代码(JavaScript/CSS/Views)只能手动添加。
######2.2 优酷 - PHP中间层框架
优酷的PHP中间层框架并未开源,所以就粗略的介绍一下吧。
中间层框架不涉及Model层,不涉及数据库操作,只包括Controller和View层。这个框架的理念是:任何一个模块都被视为一个webapp,每个webapp都是一个SPA,比如登录/注册模块Passport、订阅模块Subscribe等。脚手架只能创建一种文件类型:一个完整的webapp。其中包括Controller文件、Resource文件(浏览器层)和路由配置文件。
由于每个模块webapp都是一个SPA,包含一个Controller文件,一个view入口文件、一个入口js文件和一个css文件,所以脚手架创建的初始文件就已经够用了,开发者只需要手动添加子模块文件即可。同时,技术栈统一,build功能封装完备,不需要额外配置。这种形态的脚手架基本满足了优酷PHP中间层框架的需求
######2.3 yeoman - 可能是最好的开源脚手架框架
提起脚手架这三个字就不得不提yeoman这名老将。Yeoman在2012年Google I/O上首次发布,至今已经5年的光景了。对于前端技术圈子来说,5年的时间可以让绝大部分的技术遭到淘汰,而yeoman坚持到了今天,且扔未现衰退之势。我们可以短暂回顾一下5年前的前端技术,你可能会想到Knockout和Backbone,也可能会想到YUI 3,甚至可能会想起被ExtJS所支配的恐怖。然后再看看这些在当时热火朝天的技术目前的市场状态,是否都已是昨日黄花垂垂老矣?而yeoman之所以能“活”这么久,得益于它明确的定位。
yeoman的slogan是“THE WEB'S SCAFFOLDING TOOL FOR MODERN WEBAPPS”-脚手架工具,但我个人认为称之为脚手架框架更为合适。yeoman不能直接创建项目文件,它提供了一套完整的开发脚手架API,你可以通过这些API定制符合自己业务需求的任意的脚手架方案。换句话说,yeoman不封装任何方案,它是完全开放、高度可扩展的。
yeoman的API具备了前文所列出的脚手架需要具备的所有要素,如果你需要开发一个属于自己的脚手架,yeoman是最好的选择。后续的博文会详细介绍如何使用yeoman提供的Node.js API将其集成到工程化框架中。

###3. 总结
虽然前端脚手架没有固定形态,但是有必须具备的要素。从功能实现的角度,要考虑与业务的高度匹配;从底层框架的角度,要具备高度的可扩展性和执行环境多样性支持。

推荐阅读更多精彩内容