在前端項目的規(guī)模和復(fù)雜性不斷提升的情況下,各類構(gòu)建思想和相應(yīng)工具層出不窮。本文竭己所能對比了當(dāng)下13個構(gòu)建工具,包括 Browserify
、 Webpack
、 Rollup
、 Grunt
、 Gulp
和 Yeoman
6個廣為流行的工具, FIS
、 Athena
、 WeFlow
和 Cooking
等4個國產(chǎn)工具,以及三大框架: React
, Vue
和 Angular
的官方腳手架。希望能在項目初期的構(gòu)建工具選型上為大家提供些參考。
構(gòu)建工具可以分為三類:模塊化打包類、任務(wù)流構(gòu)建類和集合型工具類(腳手架)。其中最為突出的,當(dāng)屬用于模塊化打包的 Webpack
和用于任務(wù)流構(gòu)建的 Gulp
。下面是截至2018年11月28日某時某刻, GitHub
上各個工具的 Star
數(shù)目(聽說 Star
數(shù)目可以造假?好生無聊的家伙們?。?/span>
前端的構(gòu)建一般包括JS轉(zhuǎn)碼(使用 Babel
轉(zhuǎn) ES6
或 TypeScript
自轉(zhuǎn)等)、CSS轉(zhuǎn)碼( Less
或 Sass
轉(zhuǎn) Css
)、代碼或資源的合并與壓縮,基礎(chǔ)檢查和各類測試等等。這些雖與本文關(guān)系密切,但都不在討論的范圍之內(nèi)。原因有二:一是實現(xiàn)這些功能的都是某些插件,不是工具本身,各類構(gòu)建工具都是直接或間接(調(diào)用以自己的模式封裝后的插件)使用它們的;二是本文介紹的是,構(gòu)建方向上的類別和各類別里不同工具間的差異,與具體的操作無關(guān)。
現(xiàn)在的前端項目基本是模塊化的,原因就不在這多說。而模塊化意味著分散,無法直接用于呈現(xiàn),因此需要進(jìn)行相應(yīng)的打包形成一個整體。有些執(zhí)行環(huán)境( Node
)能自動打包各個模塊,而有些(瀏覽器)則因為技術(shù)或其它考慮需要自行操作。模塊化打包工具就是為模塊化項目在瀏覽器上的優(yōu)化呈現(xiàn)而服務(wù)的。
模塊化打包的核心是:找出依賴,打包成體。各類工具的基本運行思路便是根據(jù)已有配置,從某個文件開始,遞歸的找出所有與其相關(guān)的依賴模塊,打包成某種類型的可直接在瀏覽器中運行的一個或多個新文件。這之中還可以優(yōu)化輸出,以實現(xiàn)代碼分離、異步加載和長效緩存等高級功能。
官網(wǎng) | GitHub
正如其官網(wǎng)介紹的, Browserify
會遞歸的分析,項目中所有使用 require
引入的JS模塊(包括 Node
內(nèi)置模塊)并打包,使得 Node
類項目能在瀏覽器上運行。不過對于與項目有關(guān)的其它資源,比如 Css
和圖片等,依然需要手動管理。雖然網(wǎng)上已有人編寫了支持此些功能的插件,但這不僅違背了設(shè)計初衷,也使配置變得雜亂。而且對于要求越來越高的單頁面應(yīng)用來說,它能提供的助力著實已顯疲憊。
官網(wǎng) | 中文 | GitHub
穩(wěn)定版已到 v4.26.0
,本文以此版本為據(jù)。另附加官方的對比文檔。
Webpack
的設(shè)計思想新穎實用,社區(qū)活躍,功能強(qiáng)大全面,已經(jīng)是針對前端各類資源的、目前最優(yōu)秀的模塊化管理和打包工具。它入門簡單,基本的常用功能能很快上手,并用于實際開發(fā)。但精通不易,畢竟打包已是 web
開發(fā)中最重要的挑戰(zhàn)之一,必然要耗費些許精力。學(xué)習(xí)尚且不易,介紹就更為困難,得要有一本書的厚度。所幸此節(jié)不是詳細(xì)介紹,只是亮點闡述,善哉善哉。
入門已趨簡單
掌握了構(gòu)建的基本思路,任意工具的入門都是較為簡單的(讀者批:廢話)。之所以強(qiáng)調(diào) Webpack
入門簡單,是為了減輕有意者學(xué)習(xí)之前的顧慮。一方面是它剛被推出時,由于自身的概念新穎而且文檔不全面,使開發(fā)者處于懵懵懂懂的狀態(tài),總感覺離真諦還差些距離。另一方面是它的體系著實龐大,仔細(xì)想想都不免膽怯。筆者初次接觸時便是這些個感受。
但現(xiàn)在不一樣。吃土的日子已經(jīng)遠(yuǎn)去,啃草的夢想還會遠(yuǎn)嗎?大家準(zhǔn)備好鐮刀!
Webpack
第四版在入門上的方便性體現(xiàn)在三方面。一是基礎(chǔ)功能高度集成和約定優(yōu)于配置思想:安裝好 Webpack
及其 CLI
后便可直接打包 JS
和 JSON
文件,與 Browserify
一樣簡單。二是官方文檔詳細(xì)(而且有基本同步的中文版),無論是概念的解析、實際運用的示例還是接口的展示都十分完備。三是現(xiàn)在使用和介紹 Webpack
的人已經(jīng)很多了,因此網(wǎng)上的各路資料和相應(yīng)問題的解決方案都十分豐富。你還在猶豫?
一切皆模塊
如從官網(wǎng)上截取的圖片所示,在 Webapck
眼中一切文件( .js
、 .css
、 .jpg
、 .woff
、 .csv
和 .ts
等除了某些用于下載的靜態(tài)大文件外)都是模塊,都能通過與 JS
相似的方式被打包,并安置于合適瀏覽器渲染的位置。真是十分優(yōu)秀的立足點。以此思想便可囊括前端會使用到的幾乎所有資源,可以十分方便的統(tǒng)一管理和安置,更為便捷和高效。
而且此思想就是為單頁面應(yīng)用而生的。在 Webpack
的另一層意境中,一個 asset
(各類資源)是一個模塊,一個 component
是一個模塊,一個 module
也是一個模塊。而單頁面應(yīng)用的特點,不就是應(yīng)用的更新不是整個頁面的更新,而是某個 module
或 component
或 asset
的更新嗎?十分的契合。
有人說 Webpack
的缺點在服務(wù)端渲染(或說多頁面應(yīng)用)上。喂喂,一來別人的目標(biāo)本就不在此,二是多頁面應(yīng)用也不需要如此復(fù)雜的支持體系。
高效的構(gòu)建性能
單頁面應(yīng)用或說需要構(gòu)建才能展示的應(yīng)用,相比多頁面應(yīng)用,從每次修改到重新呈現(xiàn)要多經(jīng)歷一個構(gòu)建的階段。實際操作中,如果項目龐大而構(gòu)建性能不夠優(yōu)化,一個小小的修改(打印某值)都會消耗5秒以上的時間,對開發(fā)者來說真是個地獄!而優(yōu)化的方法不外乎兩點,一是開發(fā)者優(yōu)化項目的構(gòu)建思路,二是構(gòu)建工具優(yōu)化自身的構(gòu)建性能。
Webpack
擁有較理想的構(gòu)建性能。在開發(fā)階段,當(dāng)開啟了 Webpack
的模塊熱替換之后(使用 webpack-dev-server
會自動開啟),一旦檢測到文件被修改,會在應(yīng)用程序運行過程中通過冒泡捕獲的方式最小化替換、添加或刪除模塊,而無需重新加載整個頁面。類似 Dom
渲染中的回流:如果子元素發(fā)生的大小變化,會影響兄弟元素但不影響父元素,那么父元素及其它是無需重新繪制的。而且即便完全重新構(gòu)建,也會保留先前的應(yīng)用程序狀態(tài),減少等待時間。
活躍的社區(qū)
活躍的社區(qū)可以提升系統(tǒng)的豐富度,降低學(xué)習(xí)與使用的成本。
Webapck
社區(qū)十分活躍,應(yīng)用于各種需求的插件都被一一封裝而可直接使用(官方也統(tǒng)一展示和說明了一些常用的優(yōu)秀的 Loader
和 Plugin
)。不單單是其它工具的高度協(xié)調(diào),開發(fā)中的各個階段:搭建本地服務(wù)器、集成測試等,以及與任務(wù)流工具( Gulp
、 Grunt
)的集成等等方面的解決或最優(yōu)方案,都是豐富和全面的?;旧峡梢韵氲降男枨?,在這個社區(qū)中,都能直接借鑒他人已有的成果。
官網(wǎng) | 中文 | GitHub
Rollup
定位為一個 JS
模塊打包器(明指 JS
),主要用來構(gòu)建 JS
庫,也可服務(wù)于一些無需代碼拆分和動態(tài)導(dǎo)入的小型應(yīng)用程序。能在 Webpack
已穩(wěn)居打包之首的情況下殺出一條血路,得到 Vue
、 D3
、 Three
和 React
等著名庫的青睞,想必其著手點和性能有過人之處。
Rollup
本身結(jié)構(gòu)簡單,需要的配置項也不多,再加文檔全面,所以很容易上手并全部掌握。它使用 ES6
本身的 Module
語法作為自己的標(biāo)準(zhǔn),而不是諸如 CommonJS
和 AMD
等以前的解決方案。這意味著按照 Module
標(biāo)準(zhǔn)編成的代碼,不僅現(xiàn)在可以借助 Rollup
打包運行,未來更能在實現(xiàn)此標(biāo)準(zhǔn)的瀏覽器上直接運行。
通過 Module
的特性, Rollup
開創(chuàng)了 Tree-shaking
功能——清除沒有在項目中使用到的代碼。它基于顯式的 import
和 export
語句的方式,通過靜態(tài)分析,排除了任何未在實際中使用的代碼,能極大的減少構(gòu)建于已有模塊的項目體積。再加上其構(gòu)建基本不添加自身的控制代碼,使打包后的文件真正的達(dá)到純凈二字。想想還有點癢癢,我撓撓襠部。
與 Webpack 對比
Rollup
和 Webpack
因其定位和專注點是可以共同存在并相互支持的。
正如 Rollup
官網(wǎng)所說的, Rollup
更適合構(gòu)建獨立的 JS
庫,而 Webpack
為資源豐富的應(yīng)用程序。雖然 Webpack
也增加了自己的 Tree-shaking
功能,但在編譯后的輸出代碼中,簡單地運行自動 minifier
檢測未使用的變量,得到的結(jié)果是不如原生的靜態(tài)分析。更何況 Webpack
生成的代碼一定是經(jīng)過自己包裝后的代碼——將每個模塊封裝在一個函數(shù)中,再置于一個包中,通過瀏覽器能使用的 require
方式逐一執(zhí)行這些模塊。
基于任務(wù)的構(gòu)建行為,是不在乎操作對象是否為模塊化的。
這類工具的目標(biāo)是通過配置來解放日常需要重復(fù)的工作——轉(zhuǎn)化、合并壓縮和單元測試等等。有人說:這些操作 Webpack
和 Rollup
不是也能做?是的,基本能做。實際上,在用模塊化構(gòu)建工具的開發(fā)中,很少會用到任務(wù)流構(gòu)建工具。但這絕不是說任務(wù)流工具會被取代,也不會被取代,至少多頁面應(yīng)用需要。再說任務(wù)流工具是十分純粹的自動化行為,與模塊化打包工具立足點就不一樣,何談取代一說。
官網(wǎng) | 中文 | GitHub
Grunt
雖是老牌構(gòu)建工具,但依然被許多知名項目如 WordPress
、 Twitter
和 Jquery
等使用,也擁有持續(xù)更新的完整生態(tài)圈和中文文檔。它是通過配置驅(qū)動——通過獲取到的 JSON
配置執(zhí)行操作,來流水線式執(zhí)行相應(yīng)任務(wù)。雖然在學(xué)習(xí)成本和執(zhí)行效率上不出眾,但如果項目原本就是通過它自動化構(gòu)建的,是沒有必要遷移到其它工具的。
// Grunt 的配置驅(qū)動示例
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']);
};
官網(wǎng) | 中文 | GitHub
Gulp
是新型的構(gòu)建工具,雖與 Grunt
的功能相同,但其構(gòu)建過程卻有三大優(yōu)勢。
代碼驅(qū)動
代碼驅(qū)動即通過執(zhí)行實際代碼驅(qū)動程序執(zhí)行,與常見的配置驅(qū)動不同( Webpack
、 Rollup
和 Grunt
等都是配置驅(qū)動)。從任務(wù)流構(gòu)建的角度上看,代碼驅(qū)動相比配置驅(qū)動有三點好處:一是高度的靈活;二是沒有過多的配置項,減少學(xué)習(xí)成本;三是更方便錯誤的斷定和異常情況的調(diào)試。
// Gulp 的代碼驅(qū)動示例
gulp.src('./client/templates/*.jade')
.pipe(jade())
.pipe(gulp.dest('./build/templates'))
.pipe(minify())
.pipe(gulp.dest('./build/minified_templates'));
Node流
Gulp
作為后來者,充分利用 NodeJS
流的思想進(jìn)行 IO
操作,極大增加了大型項目的構(gòu)建速度。比方說轉(zhuǎn)化 Scss
成 Css
, Grunt
的操作流程是:讀取 Scss
文件、轉(zhuǎn)化成 Css
、存儲到磁盤,讀取 Css
、壓縮處理最后存儲到磁盤;而 Gulp
得操作是:讀取 Scss
文件、轉(zhuǎn)化成 Css
、壓縮處理最后存儲到磁盤。一步到位,無需多次的 IO
操作。
簡單明了
Gulp
有十分精簡的 API
。你能想到各種類型的任務(wù),基本是通過僅有的五個可鏈?zhǔn)讲僮鞯姆椒▽崿F(xiàn)的嗎?不僅僅是學(xué)習(xí)和使用方便,編寫后的功能也是一目了然。雖然代碼驅(qū)動相比配置驅(qū)動,需要自己寫的代碼增加,但一是沒增加難度只是函數(shù)名的多次重寫,二是相對代碼驅(qū)動的好處來說可以忽略。
集合型工具類便是常說的腳手架,也可以看作是以模塊化或任務(wù)流工具為主體的,各類常用工具的高度封裝。它是一個開箱即可用的集合體,類似前后端同構(gòu)時代的后端框架。它會根據(jù)你的選擇,生成一個完整的、已配置好各類工具的、具有某些特定代碼約定的項目框架。這些配置幾乎包攬前端開發(fā)的整個流程,甚至可以集成自動化部署等后端接口。
React CLI | Vue CLI | Angular CLI
集合型工具一般為單頁面應(yīng)用服務(wù),而單頁面應(yīng)用需要使用某個前端框架。無論你是用 React
、 Vue
或 Angular
,還是其它框架,首先得想到它是否有官方腳手架。比如 Vue
有 VueCLI
。一般推薦有官方腳手架的直接使用官方的。因為現(xiàn)代前端框架一般不單獨運行,需結(jié)合官方提供的其它工具,比如路由、狀態(tài)管理等。而且各個框架及配件更新不斷,每次更新都可能導(dǎo)致與其它插件的兼容問題,新的功能可能需要某些特定插件才能發(fā)揮作用。這是一項工程,僅靠個人或某些團(tuán)體很難照顧周全的。而各個框架又都有意識的通過官方腳手架來充分展示新的特性,降低學(xué)習(xí)和使用的成本。我們何樂而不為呢?
官網(wǎng) | GitHub
Yeoman
是一個專為現(xiàn)代前端而生的、靈活通用的腳手架工具。
它的運作方式和其它腳手架不同。在安裝好 CLI
后,需要找到一個符合要求的 Generator
(一個 npm
包,相當(dāng)于腳手架),使用 Yeoman
運行安裝,生成初始化的項目。你也可以自行配置,使用 Yeoman
封裝成符合特定需求的 Generator
,并發(fā)布出去。等到下次,其他人或你自己,需要生成符合此要求的項目時,便可以直接安裝并使用 Yeoman
生成。
這樣有明顯的兩點好處:一是節(jié)省體力。在開始一個有特定需求的新項目時,如果有老項目可借鑒,一般會直接復(fù)制相關(guān)文件。但這樣的復(fù)制文件可能不純粹,即增加體積又帶來安全隱患。二是在社區(qū)的支持下,很多有特殊要求的腳手架,早已有人解決并發(fā)布成 Generator
,是沒必要自己動手的。
百度 - FIS - 官網(wǎng) | GitHub
微信 - WeFlow - 官網(wǎng) | GitHub
京東 - Athena - 官網(wǎng) | GitHub
餓了么 - Cooking(名字與公司的性質(zhì)相得益彰) - 官網(wǎng) | GitHub
作為程序員或至各行各業(yè),在與年齡增長速度相當(dāng)?shù)膲毫ο?,工資的高低自然成為日常性的評定標(biāo)準(zhǔn)。但在同行老友的酒桌上或某個太陽異常溫煦下的小道上,能使自己為自己而不是其他事驕傲的,也肯定是“老子之前做過些什么”之類的實際付出而不是物質(zhì)方面的獲得。因此能夠成為被公司支持的、被眾多人使用的、開源框架維護(hù)團(tuán)隊中的程序員,多少是更為幸福的一類。
這些由國內(nèi)各個前端團(tuán)隊開發(fā)的集合型腳手架,都是基于自用在實踐中得到的最為符合本身需求的產(chǎn)品。里面的包含內(nèi)容十分豐富,不僅僅是這以上提到的前端本職工作,還有與后端的集成方案或自動化部署配置等。且流程簡化,開箱即可使用。不過這些筆者都沒用過,也沒有打算用。不是打趣,原因很現(xiàn)實,有識之士可以在文章下留言。不用卻依然寫出的原因倒是簡單:宣傳,宣傳即贊許和期盼;湊數(shù),湊到13種好立個多少浮夸的標(biāo)題。
個人觀點,不喜請噴,但要和藹可親。
如果是使用某個前端框架開發(fā)應(yīng)用程序,推薦框架官方的腳手架。如果是自己頭腦發(fā)熱想開源個 JS
庫,推薦 Rollup
打包。如果不是模塊化項目,又需要自動化處理一些事情,推薦 Gulp
作為構(gòu)建工具。如果項目有特殊要求或作為核心的部件比較稀有,可以先查看 Yeoman
上是否有符合要求的 Generator
,沒有就只能自食其力。最后如果你處在已有自己腳手架的公司(比如餓了么),可能要按規(guī)章制度使用 Cooking
為自己的仕途烹煮些吃食。肚子真餓,這種宣傳餓了么會返優(yōu)惠券嗎?
聯(lián)系客服