许多团队在制定前端工程方案时会加入脚手架模块。虽然不同的团队对工程化的理解和实施有所差异,但是对于脚手架的定位基本是一致的:创建项目初始文件。这是一条看起来十分简单地准则,但是对于这条准则应该如何理解,如何实施却并不是一件很简单地事情。
在探索这条准则的深度之前,我们不妨看看类似的一些成熟方案,比如Eclipse。这个大名鼎鼎的IDE软件被很多Java和Android开发者使用。通过Eclipse创建一个新项目时,它提供了丰富的配置项,这些配置项可以归纳简化为以下流程:选择项目类型 -> 选择项目目录 -> 配置项目细节 -> 最终确认 -> 完成。这是脚手架最基本也是必须具备的流程。从这个流程中可以总结出脚手架的本质:方案的封装。
由此,我们明确了脚手架的定义:脚手架作用是创建项目的初始文件,本质是方案的封装。
当然,脚手架创建项目流程之中还有很多细节,并且前端项目的多样性和复杂性更加为脚手架流程的实现增加了难度。这篇文章简单阐述一下笔者的一些浅见,希望能够给大家一些启发。
1. 脚手架在前端工程中的角色
1.1 “用完即弃”的脚手架
之前写过一篇浅析前端工程化,简单介绍了前端工作流模型,简化之后可以用下图概括:
脚手架在前端工作流中负责项目起始阶段创建初始文件。与其他功能模块不同的是,脚手架是一个完全“启下”的模块,它没有任何前置依赖。创建完成项目初始文件之后,脚手架就再无用武之地了。
“用完即弃”的工作模式令脚手架的实现由很大的跃迁性。你可以用最简单的复制粘贴就能完成脚手架的工作,而一个完备、成熟的脚手架即使提供了非常丰富的交互配置,最终目的也“只”是创建了一堆初始的项目文件。既然结果一样,那为什么还要花费时间和人力成品去开发复杂的脚手架方案呢?
跃迁是量子力学术语,意思是状态发生跳跃式变化的过程。之所以将这个词用在这里是因为高度完备的脚手架相比较低级形态的脚手架而言,能够带来质的飞跃。
这是一个非常现实的问题,互联网产品迭代的快速节奏下,开发团队最注重的就是投入产出比,而脚手架的投入产出比“看上去”是最低的。环顾目前前端的工具生态,最多的是构建工具,当然我们不可否定构建确实是最复杂的功能。而脚手架工具是最少的,前端社区对脚手架的讨论也非常稀少。你可能听说过大名鼎鼎的yeoman,但是很难再想出第二个脚手架工具了。
单独来看,脚手架可能并不具备很高的“性价比”,但如果你的团队有一套完整的前端工程体系,脚手架的作用就会被放大。前端工程体系的功能涵盖范围广,封装的方案类型多,对应的配置项也非常复杂。而且,大多数前端工程体系的开发者并不是一线的业务开发者。对于业务开发者来说,这套工程体系就是一个黑盒,他们不需要了解其中的复杂原理,只需要知道如何配置即可。所以业务开发者的需求就是快速开发快速配置,并且生成的配置项跟项目要对应,既要满足项目的功能需求,又不能有“混淆视听”的冗余功能。
前端工程体系不是Vue、React这种开发框架,工程体系只是一种“服务”,是辅助性质的。学习曲线应该平缓,即使文档再清晰易懂,也不应该要求业务开发者去花时间学习各种细节。这就是脚手架要解决的切实问题,简单说就是:
- 快速生成配置;
- 降低框架学习成本。
随着前端工程体系越来越复杂,脚手架的角色会越来越重要。
1.2 脚手架需要具备的要素
1.2.1 执行环境仅限本地
在讨论实现一个脚手架要考虑哪些要素之前,我们不妨先看看脚手架的执行环境。回顾前文提到的简易前端工作流,最简单的情形是:框架提供一套完整的本地工具链,脚手架、开发、开发服务器、构建和部署测试都是在本地环境执行,如下图:
进一步的团队会搭建CI(持续集成)平台,将构建和部署功能迁移至云端,这样做便于工作流程控制和代码统一管理。如下图:
不论哪种工作流,脚手架始终是在本地执行。
1.2.2 模式不固定
前端脚手架之所以没有固定的模式,是由于不同的公司对于前端工程师的定位不固定。比如有些公司的前端仍然是“切图仔”;有些公司的前端负责浏览器端的所有逻辑开发但是html模板层仍然由服务端工程师维护;还有些比较前沿的团队提倡“大前端”,负责浏览器层与中间层(主要承载html的渲染功能)。前端工程师定位的不固定造成了前端项目模式的不固定,脚手架自然也具备了多样性。
不论是哪种工作模式,一个优秀的前端脚手架都应该具备以下几点要素:
- 丰富但不繁琐的配置项;
- 与其他功能模块联动,生成对应的基本配置项;
- 自动安装依赖;
- 底层的高度可扩展性;
- 支持多种运行环境,比如命令行和Node.js API。
如何理解“丰富但不繁琐”呢?举个例子,假设构建功能支持自动生成css sprites,配置项有两个:
- 是否启用css sprites;
- 指定散列icon目录。
脚手架在实现针对css sprites的配置项时是不是应该将这两个配置都开放给用户配置呢?显然是不需要的,脚手架只要开放是否启用css sprites的配置项即可,因为这是影响这项功能最重要的一点,散列icon的目录即使用户不配置,使用默认的方案也不会造成任何不便。
另外,在实现脚手架时不应该只看到当前的需求,还应该考虑后续需求的变更和新增。所以一个优秀的脚手架应该具备高度的可扩展性,便于定制不同类型的方案。从这个角度来说,目前yeoman是做得最好的。
2. 开源前端脚手架方案剖析
明确了脚手架的基本工作模式,我们不妨看看目前业内有哪些可以借鉴的案例。我们在这里介绍三种形态的脚手架:
- sails是一个Node.js fullstack框架,其使用的sails generate脚手架主要是针对服务端代码设计;
- 优酷PHP中间层框架是笔者前团队使用的开发框架,目前并未开源。其使用的脚手架相对sails来说比较简单,只能创建一个完整的webapp,包括Controller层和浏览器层代码;
- yeoman是广为人知的开源脚手架工具,它本身不提供任何直接创建文件的功能,而是一个脚手架底层框架,你可以定制自己的脚手架实现。
其中两个是开源项目,大家可以在Github上获取对应的源码。
2.1 sails - Node.js fullstack框架
sails是一个Node.js全栈框架,服务端使用MVC架构。sails generate是sails的脚手架模块,默认可以创建以下几种模块的初始代码:
- app - 创建一个新sails项目;
- api - 创建一对model和controller;
- model - 创建一个model;
- controller - 创建一个controller;
- adapter - 创建一个adapter;
- generator - 创建一个脚手架模板。
sails框架中的Adapter可以简单理解为简化model操作API的映射适配器。
大家注意最后一种类型:generator。sails在默认的脚手架基础上,开放了自定义脚手架模板的API。
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. 总结
虽然前端脚手架没有固定形态,但是有必须具备的要素。从功能实现的角度,要考虑与业务的高度匹配;从底层框架的角度,要具备高度的可扩展性和执行环境多样性支持。
这可能是目前针对前端脚手架理念说的废话最多的一篇文章了,哈哈。所述内容都是笔者的一些浅薄的心得,希望能够给大家一些启发。
PS:做了一个简单地视频分享,大家可以使用微信扫描二维码观看。