javascript
如何选择JavaScript构建工具之Babel、Browserify、Webpack、Grunt以及Gulp
當我們開始一個新的 JavaScript 項目時,我們需要考慮的第一件事就是搭建一個前端編譯環境。但是在面對眾多的 JavaScript 構建工具時,我們卻無所適從,不知道究竟哪一個才是最適合我們的。
想象一下,如果有一個很簡單的判斷標準,讓你知道如何針對不同的項目,選取不同的前端構建工具,那是不是很美好呢?事實上,在使用自動構建系統,積累了5年的項目開發經驗之后,我總結出來如下內容。相信我,它是可以讓你明白不同構建工具的使用場景的。
開門見山
判斷你的項目需要使用哪種構建工具是很容易的:
- 如果是小項目的話,基于 ES6 編譯器即可
- 如果是單頁應用的話,還需要一個模塊打包器
- 如果你的項目,部署在了生產環境之中,除了上述之外,還需要一個能夠自動執行的任務運行器
下面是我推薦的一些可以滿足你上述需求的前端構建工具:
- 使用 Babel 可以編譯適配 ES6 代碼
- 使用 Webpack 能夠打包 JavaScript 文件以及其相關的依賴
- 使用 Gulp 能夠自動化地將文件批量重命名,從而刷新靜態資源文件的緩存
那么,問題來了,前端構建工具那么多,為什么我偏偏推薦上述的這些呢?
追根溯源
我對很多流行的 JavaScript 構建工具進行了分析,并分別找出了它們的優點與缺點。既然編譯器是無論如何都需要的,那么我們就從編譯器開始說起吧。
編譯器
ES5 版的 JavaScript 并不是那么優雅。盡管 ES6 與 ES7 有了非常大的提升,但是目前的瀏覽器并不支持 ES6 與 ES7。
幸運的是,有很多工程師打造了能夠將新的 JavaScript 代碼轉換成瀏覽器支持的 JavaScript 代碼的工具,有的甚至還在此基礎上,加入了新的特性與功能 — 例如微軟的 TypeScript 。但是如果我們要在眾多的 JavaScript 編譯器中,選取一個最接近 JavaScript 官方代碼風格的,那么Babel無疑是最優秀的。
Babel
在閱讀完這篇文章之后,如果你必須要學著使用一款工具,那么這款工具肯定就是 Babel 了
Babel的功能并不會讓你大吃一驚,正如你所期待的那樣,它主要是將 ES6 代碼轉換成瀏覽器所支持的 ES5 代碼而已。還有一點就是它允許你在 Babel 已擁有的轉換器基礎之上,定制屬于你自己的轉換器——欣喜的是,Babel的社區在轉換器方面,已經為我們提供了很多。此外,它還能夠對 ES7 的特性進行轉換,例如 async / await 以及 decorators。同時,它也提供了對 React JSX 的支持。
盡管 Babel 在轉換 JavaScript 代碼方面做得足夠優秀,但是除此之外,它不能幫我們做任何事情。事實上,它甚至不能通過ES6 的 import 和export的表達式,將我們的多個文件進行合并。這也是為什么我們接下來需要一個模塊打包器了。
模塊打包器
大多數的項目,無論規模多大,程序員都習慣于將代碼拆分到多個文件之中。盡管你可以使用 script 標簽,來一個個地引入這些單獨的js文件,但是你終究還是需要基于不同文件的依賴關系來決定它們引入的先后順序的。在這件事情上,工具能夠比你做得更好,這也就是為什么你需要使用模塊打包器,來將一些文件自動化地打包進一個單獨的文件的原因。
盡管我們可以從網上找到很多的模塊打包器,但是只有兩款是最具代表性的:Browserify 與 Webpack
Browserify
Browserify 可以使得 Node packages 獲得瀏覽器的支持。當然,它也可以幫助我們將 Web 應用打包成一個 Node Packages。
這種以 Node 為中心的哲學,有很多的好處。使用 Browserify 來打包一個應用是非常容易的。你可以使用 Node 內置的模塊,例如 path ,也可以引用你之前在Node項目中寫過的任何代碼。當然,缺點就是,你的單頁應用通常需要的資源,正好是 Node 項目不需要的,例如 CSS 、圖片以及字體。
盡管存在這種問題,但是這種問題也并不是不能解決的。許多人已經寫了插件來使得 Browserify 可以打包這些資源。這些插件可以使你能夠轉換 ES6 到 ES5 、打包 CSS、分離你的代碼到多個文件之中等等。但是考慮到這些插件違背了 Browserify 這一工具的設計初衷,它的配置將會比較混亂。
因此,盡管 Browserify 是一款能夠優雅地將 Node Packages 打包成瀏覽器支持形式的工具,但是如果你寫的是一個單頁應用,那么你最好選擇一款專門用于打包、并且能夠打包所有資源文件的模塊打包器。
Webpack
Webpack 是一款能夠將許多的 JavaScript 模塊以及它的相關依賴打包進一個單獨文件的工具。它并不需要你給出這些模塊的依賴具體是哪些,只要它能夠打包成 JavaScript 模塊即可。
只要它能夠打包成 JavaScript 模塊即可?這意味著它不支持 CSS 和圖片,是嗎?當然不是,Webpack 是可以通過各種 loaders 來將各種資源文件都轉換成 JavaScript 模塊的神器。
Loaders 是一種能夠處理不同資源文件的轉換器。它們能夠接收任何形式的資源文件,也能輸出任何形式的資源文件,而不僅僅是 JavaScript 。而且,這種操作也是可以鏈式的,它允許你先將 SCSS 文件轉換為 CSS,然后再將CSS 轉換為 JavaScript 模塊。然后,Webpack 再對這些 JavaScript 模塊統一打包!
如果非要說 Webpack 有什么缺點的話,那就是許多流行的案例項目都包含了令開發人員感到害怕的 Webpack 復雜的配置文件。如果你按照我的 configuring Webpack with Babel in 26 lines 教程來做的話,你就會發現解決這種問題是如此的 so easy。
經過上述的分析,現在你應該知道怎樣使用模塊打包器來生成一系列的靜態資源文件了。但是有了這些文件之后,我們該怎么做呢?這就是該任務運行器發揮作用的時候了。
任務運行器
任務運行器是用來定義并運行任務的工具。簡言之,任何你可能在命令行上執行的操作,都可以通過任務運行器來完成。
在使用任務運行器之前,理解這句話是非常重要的:不要為了編寫任務而編寫任務。也就是說,如果你自己編寫一個任務來進行模塊打包,這也是可以的。但是如果你把這件事情交給Webpack去做的話,你只需要啟動一下 Webpack 就好了,我們完全沒有必要重復造輪子。
編寫一些你的模塊打包器不能處理的任務才是有必要的,例如為模塊打包器自動生成的靜態資源文件在網頁中插入一個 script 標簽。
Grunt
Grunt 是一個運行你先前定義過的任務的工具。也就是說,如果你不定義任務,基本上 Grunt 不能為你做任何事情。
原因就在于,Grunt 的任務并不是使用 JavaScript 的代碼來定義,而是通過一系列的配置對象來進行聲明式的定義的。為了保持 Grunt 核心包的大小,它的所有配置對象都是插件化的 — 從監控文件變化到復制、串聯文件。
這種做法也是有它的優勢的。Grunt 有成千上萬的插件,基本上你不需要編寫任何代碼,針對不同的需求,選取其一,直接拿來用即可。它最大的問題其實在于,如果你感覺確實有必要對插件運行的效果做一些微調的話,通過編寫純 JavaScript 代碼是沒法實現的,你必須要為此重新編寫一個 Grunt 插件了。
Gulp
Gulp,類似 Grunt ,也是一個用來定義并運行任務的工具。
Grunt 與Gulp 最大的不同就在于 Grunt 使用配置對象來聲明任務的運行方式,而 Gulp 則使用 JavaScript 的函數來定義任務。也正是由于 Gulp 知道如何處理 JavaScript 返回的 streams 或者 promises ,這使得你在編寫任務的時候具備很大的靈活性。
Gulp 與 Grunt 一樣,也擁有非常豐富的插件庫。不過考慮到 Gulp 的插件提供的都是一些原始基礎的功能,你也可以引用 Node 模塊來豐富完善你的 Gulp 任務體系。
Gulp 最大的問題在于 streams 與 promises 的對接對新手來說可能是比較困難的。但是這也是一個雙刃劍,隨著實踐經驗的積累,你就能夠體會到 streams 與 promises 的好處了。
譯自:James K Nelson, http://jamesknelson.com/which-build-system-should-i-use-for-my-javascript-app/
總結
以上是生活随笔為你收集整理的如何选择JavaScript构建工具之Babel、Browserify、Webpack、Grunt以及Gulp的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Nginx日志优化
- 下一篇: JavaScript的Map和WeakM