前言
在前端專案的規模和複雜性不斷提升的情況下,各類構建思想和相應工具層出不窮。本文竭己所能對比了當下13個構建工具,包括Browserify
、Webpack
、Rollup
、Grunt
、Gulp
和Yeoman
6個廣為流行的工具,FIS
、Athena
、WeFlow
和Cooking
等4個國產工具,以及三大框架:React
,Vue
和Angular
的官方腳手架。希望能在專案初期的構建工具選型上為大家提供些參考。
全覽
構建工具可以分為三類:模組化打包類、任務流構建類和集合型工具類(腳手架)。其中最為突出的,當屬用於模組化打包的Webpack
和用於任務流構建的Gulp
。下面是截至2018年11月28日某時某刻,GitHub
上各個工具的Star
數目(聽說Star
數目可以造假?好生無聊的傢伙們!)。
前端的構建一般包括JS轉碼(使用Babel
轉ES6
或TypeScript
自轉等)、CSS轉碼(Less
或Sass
轉Css
)、程式碼或資源的合併與壓縮,基礎檢查和各類測試等等。這些雖與本文關係密切,但都不在討論的範圍之內。原因有二:一是實現這些功能的都是某些外掛,不是工具本身,各類構建工具都是直接或間接(呼叫以自己的模式封裝後的外掛)使用它們的;二是本文介紹的是,構建方向上的類別和各類別裡不同工具間的差異,與具體的操作無關。
模組化打包類
現在的前端專案基本是模組化的,原因就不在這多說。而模組化意味著分散,無法直接用於呈現,因此需要進行相應的打包形成一個整體。有些執行環境(Node
)能自動打包各個模組,而有些(瀏覽器)則因為技術或其它考慮需要自行操作。模組化打包工具就是為模組化專案在瀏覽器上的優化呈現而服務的。
模組化打包的核心是:找出依賴,打包成體。各類工具的基本執行思路便是根據已有配置,從某個檔案開始,遞迴的找出所有與其相關的依賴模組,打包成某種型別的可直接在瀏覽器中執行的一個或多個新檔案。這之中還可以優化輸出,以實現程式碼分離、非同步載入和長效快取等高階功能。
Browserify
正如其官網介紹的,Browserify
會遞迴的分析,專案中所有使用require
引入的JS模組(包括Node
內建模組)並打包,使得Node
類專案能在瀏覽器上執行。不過對於與專案有關的其它資源,比如Css
和圖片等,依然需要手動管理。雖然網上已有人編寫了支援此些功能的外掛,但這不僅違背了設計初衷,也使配置變得雜亂。而且對於要求越來越高的單頁面應用來說,它能提供的助力著實已顯疲憊。
Webpack
穩定版已到v4.26.0
,本文以此版本為據。另附加官方的對比文件。
Webpack
的設計思想新穎實用,社群活躍,功能強大全面,已經是針對前端各類資源的、目前最優秀的模組化管理和打包工具。它入門簡單,基本的常用功能能很快上手,並用於實際開發。但精通不易,畢竟打包已是web
開發中最重要的挑戰之一,必然要耗費些許精力。學習尚且不易,介紹就更為困難,得要有一本書的厚度。所幸此節不是詳細介紹,只是亮點闡述,善哉善哉。
入門已趨簡單
掌握了構建的基本思路,任意工具的入門都是較為簡單的(讀者批:廢話)。之所以強調Webpack
入門簡單,是為了減輕有意者學習之前的顧慮。一方面是它剛被推出時,由於自身的概念新穎而且文件不全面,使開發者處於懵懵懂懂的狀態,總感覺離真諦還差些距離。另一方面是它的體系著實龐大,仔細想想都不免膽怯。筆者初次接觸時便是這些個感受。
但現在不一樣。吃土的日子已經遠去,啃草的夢想還會遠嗎?大家準備好鐮刀!
Webpack
第四版在入門上的方便性體現在三方面。一是基礎功能高度整合和約定優於配置思想:安裝好Webpack
及其CLI
後便可直接打包JS
和JSON
檔案,與Browserify
一樣簡單。二是官方文件詳細(而且有基本同步的中文版),無論是概念的解析、實際運用的示例還是介面的展示都十分完備。三是現在使用和介紹Webpack
的人已經很多了,因此網上的各路資料和相應問題的解決方案都十分豐富。你還在猶豫?
一切皆模組
如從官網上擷取的圖片所示,在Webapck
眼中一切檔案(.js
、.css
、.jpg
、.woff
、.csv
和.ts
等除了某些用於下載的靜態大檔案外)都是模組,都能通過與JS
相似的方式被打包,並安置於合適瀏覽器渲染的位置。真是十分優秀的立足點。以此思想便可囊括前端會使用到的幾乎所有資源,可以十分方便的統一管理和安置,更為便捷和高效。
而且此思想就是為單頁面應用而生的。在Webpack
的另一層意境中,一個asset
(各類資源)是一個模組,一個component
是一個模組,一個module
也是一個模組。而單頁面應用的特點,不就是應用的更新不是整個頁面的更新,而是某個module
或component
或asset
的更新嗎?十分的契合。
有人說Webpack
的缺點在服務端渲染(或說多頁面應用)上。喂喂,一來別人的目標本就不在此,二是多頁面應用也不需要如此複雜的支援體系。
高效的構建效能
單頁面應用或說需要構建才能展示的應用,相比多頁面應用,從每次修改到重新呈現要多經歷一個構建的階段。實際操作中,如果專案龐大而構建效能不夠優化,一個小小的修改(列印某值)都會消耗5秒以上的時間,對開發者來說真是個地獄!而優化的方法不外乎兩點,一是開發者優化專案的構建思路,二是構建工具優化自身的構建效能。
Webpack
擁有較理想的構建效能。在開發階段,當開啟了Webpack
的模組熱替換之後(使用webpack-dev-server
會自動開啟),一旦檢測到檔案被修改,會在應用程式執行過程中通過冒泡捕獲的方式最小化替換、新增或刪除模組,而無需重新載入整個頁面。類似Dom
渲染中的迴流:如果子元素髮生的大小變化,會影響兄弟元素但不影響父元素,那麼父元素及其它是無需重新繪製的。而且即便完全重新構建,也會保留先前的應用程式狀態,減少等待時間。
活躍的社群
活躍的社群可以提升系統的豐富度,降低學習與使用的成本。
Webapck
社群十分活躍,應用於各種需求的外掛都被一一封裝而可直接使用(官方也統一展示和說明了一些常用的優秀的Loader
和Plugin
)。不單單是其它工具的高度協調,開發中的各個階段:搭建本地伺服器、整合測試等,以及與任務流工具(Gulp
、Grunt
)的整合等等方面的解決或最優方案,都是豐富和全面的。基本上可以想到的需求,在這個社群中,都能直接借鑑他人已有的成果。
Rollup
Rollup
定位為一個JS
模組打包器(明指JS
),主要用來構建JS
庫,也可服務於一些無需程式碼拆分和動態匯入的小型應用程式。能在Webpack
已穩居打包之首的情況下殺出一條血路,得到Vue
、D3
、Three
和React
等著名庫的青睞,想必其著手點和效能有過人之處。
Rollup
本身結構簡單,需要的配置項也不多,再加文件全面,所以很容易上手並全部掌握。它使用ES6
本身的Module
語法作為自己的標準,而不是諸如CommonJS
和AMD
等以前的解決方案。這意味著按照Module
標準編成的程式碼,不僅現在可以藉助Rollup
打包執行,未來更能在實現此標準的瀏覽器上直接執行。
通過Module
的特性,Rollup
開創了Tree-shaking
功能——清除沒有在專案中使用到的程式碼。它基於顯式的import
和export
語句的方式,通過靜態分析,排除了任何未在實際中使用的程式碼,能極大的減少構建於已有模組的專案體積。再加上其構建基本不新增自身的控制程式碼,使打包後的檔案真正的達到純淨二字。想想還有點癢癢,我撓撓襠部。
與 Webpack 對比
Rollup
和Webpack
因其定位和專注點是可以共同存在並相互支援的。
正如Rollup
官網所說的,Rollup
更適合構建獨立的JS
庫,而Webpack
為資源豐富的應用程式。雖然Webpack
也增加了自己的Tree-shaking
功能,但在編譯後的輸出程式碼中,簡單地執行自動minifier
檢測未使用的變數,得到的結果是不如原生的靜態分析。更何況Webpack
生成的程式碼一定是經過自己包裝後的程式碼——將每個模組封裝在一個函式中,再置於一個包中,通過瀏覽器能使用的require
方式逐一執行這些模組。
任務流構建類
基於任務的構建行為,是不在乎操作物件是否為模組化的。
這類工具的目標是通過配置來解放日常需要重複的工作——轉化、合併壓縮和單元測試等等。有人說:這些操作Webpack
和Rollup
不是也能做?是的,基本能做。實際上,在用模組化構建工具的開發中,很少會用到任務流構建工具。但這絕不是說任務流工具會被取代,也不會被取代,至少多頁面應用需要。再說任務流工具是十分純粹的自動化行為,與模組化打包工具立足點就不一樣,何談取代一說。
Grunt
Grunt
雖是老牌構建工具,但依然被許多知名專案如WordPress
、Twitter
和Jquery
等使用,也擁有持續更新的完整生態圈和中文文件。它是通過配置驅動——通過獲取到的JSON
配置執行操作,來流水線式執行相應任務。雖然在學習成本和執行效率上不出眾,但如果專案原本就是通過它自動化構建的,是沒有必要遷移到其它工具的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// 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
Gulp
是新型的構建工具,雖與Grunt
的功能相同,但其構建過程卻有三大優勢。
程式碼驅動
程式碼驅動即通過執行實際程式碼驅動程式執行,與常見的配置驅動不同(Webpack
、Rollup
和Grunt
等都是配置驅動)。從任務流構建的角度上看,程式碼驅動相比配置驅動有三點好處:一是高度的靈活;二是沒有過多的配置項,減少學習成本;三是更方便錯誤的斷定和異常情況的除錯。
1 2 3 4 5 6 |
// 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
操作,極大增加了大型專案的構建速度。比方說轉化Scss
成Css
,Grunt
的操作流程是:讀取Scss
檔案、轉化成Css
、儲存到磁碟,讀取Css
、壓縮處理最後儲存到磁碟;而Gulp
得操作是:讀取Scss
檔案、轉化成Css
、壓縮處理最後儲存到磁碟。一步到位,無需多次的IO
操作。
簡單明瞭
Gulp
有十分精簡的API
。你能想到各種型別的任務,基本是通過僅有的五個可鏈式操作的方法實現的嗎?不僅僅是學習和使用方便,編寫後的功能也是一目瞭然。雖然程式碼驅動相比配置驅動,需要自己寫的程式碼增加,但一是沒增加難度只是函式名的多次重寫,二是相對程式碼驅動的好處來說可以忽略。
集合型工具類
集合型工具類便是常說的腳手架,也可以看作是以模組化或任務流工具為主體的,各類常用工具的高度封裝。它是一個開箱即可用的集合體,類似前後端同構時代的後端框架。它會根據你的選擇,生成一個完整的、已配置好各類工具的、具有某些特定程式碼約定的專案框架。這些配置幾乎包攬前端開發的整個流程,甚至可以整合自動化部署等後端介面。
官方框架
React CLI | Vue CLI | Angular CLI
集合型工具一般為單頁面應用服務,而單頁面應用需要使用某個前端框架。無論你是用React
、Vue
或Angular
,還是其它框架,首先得想到它是否有官方腳手架。比如Vue
有Vue CLI
。一般推薦有官方腳手架的直接使用官方的。因為現代前端框架一般不單獨執行,需結合官方提供的其它工具,比如路由、狀態管理等。而且各個框架及配件更新不斷,每次更新都可能導致與其它外掛的相容問題,新的功能可能需要某些特定外掛才能發揮作用。這是一項工程,僅靠個人或某些團體很難照顧周全的。而各個框架又都有意識的通過官方腳手架來充分展示新的特性,降低學習和使用的成本。我們何樂而不為呢?
Yeoman
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
釋出,方便你我他。