64

前言

在前端项目的规模和复杂性不断提升的情况下,各类构建思想和相应工具层出不穷。本文竭己所能对比了当下13个构建工具,包括BrowserifyWebpackRollupGruntGulpYeoman6个广为流行的工具,FISAthenaWeFlowCooking等4个国产工具,以及三大框架:ReactVueAngular的官方脚手架。希望能在项目初期的构建工具选型上为大家提供些参考。

全览

构建工具可以分为三类:模块化打包类、任务流构建类和集合型工具类(脚手架)。其中最为突出的,当属用于模块化打包的Webpack和用于任务流构建的Gulp。下面是截至2018年11月28日某时某刻,GitHub上各个工具的Star数目(听说Star数目可以造假?好生无聊的家伙们!)。

Star 数目对比图

前端的构建一般包括JS转码(使用BabelES6TypeScript自转等)、CSS转码(LessSassCss)、代码或资源的合并与压缩,基础检查和各类测试等等。这些虽与本文关系密切,但都不在讨论的范围之内。原因有二:一是实现这些功能的都是某些插件,不是工具本身,各类构建工具都是直接或间接(调用以自己的模式封装后的插件)使用它们的;二是本文介绍的是,构建方向上的类别和各类别里不同工具间的差异,与具体的操作无关。

模块化打包类

现在的前端项目基本是模块化的,原因就不在这多说。而模块化意味着分散,无法直接用于呈现,因此需要进行相应的打包形成一个整体。有些执行环境(Node)能自动打包各个模块,而有些(浏览器)则因为技术或其它考虑需要自行操作。模块化打包工具就是为模块化项目在浏览器上的优化呈现而服务的。

模块化打包的核心是:找出依赖,打包成体。各类工具的基本运行思路便是根据已有配置,从某个文件开始,递归的找出所有与其相关的依赖模块,打包成某种类型的可直接在浏览器中运行的一个或多个新文件。这之中还可以优化输出,以实现代码分离、异步加载和长效缓存等高级功能。

Browserify

官网 | GitHub

正如其官网介绍的,Browserify会递归的分析,项目中所有使用require引入的JS模块(包括Node内置模块)并打包,使得Node类项目能在浏览器上运行。不过对于与项目有关的其它资源,比如Css和图片等,依然需要手动管理。虽然网上已有人编写了支持此些功能的插件,但这不仅违背了设计初衷,也使配置变得杂乱。而且对于要求越来越高的单页面应用来说,它能提供的助力着实已显疲惫。

Webpack

官网 | 中文 | GitHub

稳定版已到v4.26.0,本文以此版本为据。另附加官方的对比文档

Webpack 官网图

Webpack的设计思想新颖实用,社区活跃,功能强大全面,已经是针对前端各类资源的、目前最优秀的模块化管理和打包工具。它入门简单,基本的常用功能能很快上手,并用于实际开发。但精通不易,毕竟打包已是web开发中最重要的挑战之一,必然要耗费些许精力。学习尚且不易,介绍就更为困难,得要有一本书的厚度。所幸此节不是详细介绍,只是亮点阐述,善哉善哉。

入门已趋简单

掌握了构建的基本思路,任意工具的入门都是较为简单的(读者批:废话)。之所以强调Webpack入门简单,是为了减轻有意者学习之前的顾虑。一方面是它刚被推出时,由于自身的概念新颖而且文档不全面,使开发者处于懵懵懂懂的状态,总感觉离真谛还差些距离。另一方面是它的体系着实庞大,仔细想想都不免胆怯。笔者初次接触时便是这些个感受。

但现在不一样。吃土的日子已经远去,啃草的梦想还会远吗?大家准备好镰刀!

Webpack第四版在入门上的方便性体现在三方面。一是基础功能高度集成和约定优于配置思想:安装好Webpack及其CLI后便可直接打包JSJSON文件,与Browserify一样简单。二是官方文档详细(而且有基本同步的中文版),无论是概念的解析、实际运用的示例还是接口的展示都十分完备。三是现在使用和介绍Webpack的人已经很多了,因此网上的各路资料和相应问题的解决方案都十分丰富。你还在犹豫?

一切皆模块

如从官网上截取的图片所示,在Webapck眼中一切文件(.js.css.jpg.woff.csv.ts等除了某些用于下载的静态大文件外)都是模块,都能通过与JS相似的方式被打包,并安置于合适浏览器渲染的位置。真是十分优秀的立足点。以此思想便可囊括前端会使用到的几乎所有资源,可以十分方便的统一管理和安置,更为便捷和高效。

而且此思想就是为单页面应用而生的。在Webpack的另一层意境中,一个asset(各类资源)是一个模块,一个component是一个模块,一个module也是一个模块。而单页面应用的特点,不就是应用的更新不是整个页面的更新,而是某个modulecomponentasset的更新吗?十分的契合。

有人说Webpack的缺点在服务端渲染(或说多页面应用)上。喂喂,一来别人的目标本就不在此,二是多页面应用也不需要如此复杂的支持体系。

高效的构建性能

单页面应用或说需要构建才能展示的应用,相比多页面应用,从每次修改到重新呈现要多经历一个构建的阶段。实际操作中,如果项目庞大而构建性能不够优化,一个小小的修改(打印某值)都会消耗5秒以上的时间,对开发者来说真是个地狱!而优化的方法不外乎两点,一是开发者优化项目的构建思路,二是构建工具优化自身的构建性能。

Webpack拥有较理想的构建性能。在开发阶段,当开启了Webpack的模块热替换之后(使用webpack-dev-server会自动开启),一旦检测到文件被修改,会在应用程序运行过程中通过冒泡捕获的方式最小化替换、添加或删除模块,而无需重新加载整个页面。类似Dom渲染中的回流:如果子元素发生的大小变化,会影响兄弟元素但不影响父元素,那么父元素及其它是无需重新绘制的。而且即便完全重新构建,也会保留先前的应用程序状态,减少等待时间。

活跃的社区

活跃的社区可以提升系统的丰富度,降低学习与使用的成本。

Webapck社区十分活跃,应用于各种需求的插件都被一一封装而可直接使用(官方也统一展示和说明了一些常用的优秀的LoaderPlugin)。不单单是其它工具的高度协调,开发中的各个阶段:搭建本地服务器、集成测试等,以及与任务流工具(GulpGrunt)的集成等等方面的解决或最优方案,都是丰富和全面的。基本上可以想到的需求,在这个社区中,都能直接借鉴他人已有的成果。

Rollup

官网 | 中文 | GitHub

Rollup定位为一个JS模块打包器(明指JS),主要用来构建JS库,也可服务于一些无需代码拆分和动态导入的小型应用程序。能在Webpack已稳居打包之首的情况下杀出一条血路,得到VueD3ThreeReact等著名库的青睐,想必其着手点和性能有过人之处。

Rollup本身结构简单,需要的配置项也不多,再加文档全面,所以很容易上手并全部掌握。它使用ES6本身的Module语法作为自己的标准,而不是诸如CommonJSAMD等以前的解决方案。这意味着按照Module标准编成的代码,不仅现在可以借助Rollup打包运行,未来更能在实现此标准的浏览器上直接运行。

通过Module的特性,Rollup开创了Tree-shaking功能——清除没有在项目中使用到的代码。它基于显式的importexport语句的方式,通过静态分析,排除了任何未在实际中使用的代码,能极大的减少构建于已有模块的项目体积。再加上其构建基本不添加自身的控制代码,使打包后的文件真正的达到纯净二字。想想还有点痒痒,我挠挠裆部。

与 Webpack 对比

RollupWebpack因其定位和专注点是可以共同存在并相互支持的。

正如Rollup官网所说的,Rollup更适合构建独立的JS库,而Webpack为资源丰富的应用程序。虽然Webpack也增加了自己的Tree-shaking功能,但在编译后的输出代码中,简单地运行自动minifier检测未使用的变量,得到的结果是不如原生的静态分析。更何况Webpack生成的代码一定是经过自己包装后的代码——将每个模块封装在一个函数中,再置于一个包中,通过浏览器能使用的require方式逐一执行这些模块。

任务流构建类

基于任务的构建行为,是不在乎操作对象是否为模块化的。

这类工具的目标是通过配置来解放日常需要重复的工作——转化、合并压缩和单元测试等等。有人说:这些操作WebpackRollup不是也能做?是的,基本能做。实际上,在用模块化构建工具的开发中,很少会用到任务流构建工具。但这绝不是说任务流工具会被取代,也不会被取代,至少多页面应用需要。再说任务流工具是十分纯粹的自动化行为,与模块化打包工具立足点就不一样,何谈取代一说。

Grunt

官网 | 中文 | GitHub

Grunt虽是老牌构建工具,但依然被许多知名项目如WordPressTwitterJquery等使用,也拥有持续更新的完整生态圈和中文文档。它是通过配置驱动——通过获取到的JSON配置执行操作,来流水线式执行相应任务。虽然在学习成本和执行效率上不出众,但如果项目原本就是通过它自动化构建的,是没有必要迁移到其它工具的。

// Grunt 的配置驱动示例
module.exports = function(grunt) {
  grunt.initConfig({
    jshint: {
      files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
      options: {
        globals: {
          jQuery: true
        }
      }
    },
    watch: {
      files: ['<%= jshint.files %>'],
      tasks: ['jshint']
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.registerTask('default', ['jshint']);

};

Gulp

官网 | 中文 | GitHub

Gulp是新型的构建工具,虽与Grunt的功能相同,但其构建过程却有三大优势。

代码驱动

代码驱动即通过执行实际代码驱动程序执行,与常见的配置驱动不同(WebpackRollupGrunt等都是配置驱动)。从任务流构建的角度上看,代码驱动相比配置驱动有三点好处:一是高度的灵活;二是没有过多的配置项,减少学习成本;三是更方便错误的断定和异常情况的调试。

// Gulp 的代码驱动示例
gulp.src('./client/templates/*.jade')
  .pipe(jade())
  .pipe(gulp.dest('./build/templates'))
  .pipe(minify())
  .pipe(gulp.dest('./build/minified_templates'));

Node流

Gulp作为后来者,充分利用NodeJS流的思想进行IO操作,极大增加了大型项目的构建速度。比方说转化ScssCssGrunt的操作流程是:读取Scss文件、转化成Css、存储到磁盘,读取Css、压缩处理最后存储到磁盘;而Gulp得操作是:读取Scss文件、转化成Css、压缩处理最后存储到磁盘。一步到位,无需多次的IO操作。

简单明了

Gulp有十分精简的API。你能想到各种类型的任务,基本是通过仅有的五个可链式操作的方法实现的吗?不仅仅是学习和使用方便,编写后的功能也是一目了然。虽然代码驱动相比配置驱动,需要自己写的代码增加,但一是没增加难度只是函数名的多次重写,二是相对代码驱动的好处来说可以忽略。

集合型工具类

集合型工具类便是常说的脚手架,也可以看作是以模块化或任务流工具为主体的,各类常用工具的高度封装。它是一个开箱即可用的集合体,类似前后端同构时代的后端框架。它会根据你的选择,生成一个完整的、已配置好各类工具的、具有某些特定代码约定的项目框架。这些配置几乎包揽前端开发的整个流程,甚至可以集成自动化部署等后端接口。

官方框架

React CLI | Vue CLI | Angular CLI

集合型工具一般为单页面应用服务,而单页面应用需要使用某个前端框架。无论你是用ReactVueAngular,还是其它框架,首先得想到它是否有官方脚手架。比如VueVue CLI。一般推荐有官方脚手架的直接使用官方的。因为现代前端框架一般不单独运行,需结合官方提供的其它工具,比如路由、状态管理等。而且各个框架及配件更新不断,每次更新都可能导致与其它插件的兼容问题,新的功能可能需要某些特定插件才能发挥作用。这是一项工程,仅靠个人或某些团体很难照顾周全的。而各个框架又都有意识的通过官方脚手架来充分展示新的特性,降低学习和使用的成本。我们何乐而不为呢?

Yeoman

官网 | GitHub

Yeoman是一个专为现代前端而生的、灵活通用的脚手架工具。

它的运作方式和其它脚手架不同。在安装好CLI后,需要找到一个符合要求的Generator(一个npm包,相当于脚手架),使用Yeoman运行安装,生成初始化的项目。你也可以自行配置,使用Yeoman封装成符合特定需求的Generator,并发布出去。等到下次,其他人或你自己,需要生成符合此要求的项目时,便可以直接安装并使用Yeoman生成。

这样有明显的两点好处:一是节省体力。在开始一个有特定需求的新项目时,如果有老项目可借鉴,一般会直接复制相关文件。但这样的复制文件可能不纯粹,即增加体积又带来安全隐患。二是在社区的支持下,很多有特殊要求的脚手架,早已有人解决并发布成Generator,是没必要自己动手的。

国内其它

百度 - FIS - 官网 | GitHub
微信 - WeFlow - 官网 | GitHub
京东 - Athena - 官网 | GitHub
饿了么 - Cooking(名字与公司的性质相得益彰) - 官网 | GitHub

作为程序员或至各行各业,在与年龄增长速度相当的压力下,工资的高低自然成为日常性的评定标准。但在同行老友的酒桌上或某个太阳异常温煦下的小道上,能使自己为自己而不是其他事骄傲的,也肯定是“老子之前做过些什么”之类的实际付出而不是物质方面的获得。因此能够成为被公司支持的、被众多人使用的、开源框架维护团队中的程序员,多少是更为幸福的一类。

这些由国内各个前端团队开发的集合型脚手架,都是基于自用在实践中得到的最为符合本身需求的产品。里面的包含内容十分丰富,不仅仅是这以上提到的前端本职工作,还有与后端的集成方案或自动化部署配置等。且流程简化,开箱即可使用。不过这些笔者都没用过,也没有打算用。不是打趣,原因很现实,有识之士可以在文章下留言。不用却依然写出的原因倒是简单:宣传,宣传即赞许和期盼;凑数,凑到13种好立个多少浮夸的标题。

总结

个人观点,不喜请喷,但要和蔼可亲。

如果是使用某个前端框架开发应用程序,推荐框架官方的脚手架。如果是自己头脑发热想开源个JS库,推荐Rollup打包。如果不是模块化项目,又需要自动化处理一些事情,推荐Gulp作为构建工具。如果项目有特殊要求或作为核心的部件比较稀有,可以先查看Yeoman上是否有符合要求的Generator,没有就只能自食其力。最后如果你处在已有自己脚手架的公司(比如饿了么),可能要按规章制度使用Cooking为自己的仕途烹煮些吃食。肚子真饿,这种宣传饿了么会返优惠券吗?

最后,如果是自食其力的搭建前人没有的脚手架,推荐使用Yeoman发布,方便你我他。


wmaker
2.9k 声望4.7k 粉丝

保持节奏。