前端构建工具之争——Webpack vs Gulp 谁会被拍死在沙滩上
- 理想的前端開發(fā)流程
- Gulp 為何物
- webpack 又是從哪冒出來的
- 結(jié)論
文章有點(diǎn)長(zhǎng),總共 1800 字,閱讀需要 18 分鐘。哈哈,沒耐心的直接戳我到高潮部分。
理想的前端開發(fā)流程
在說構(gòu)建工具之前得先說說咱期望的前端開發(fā)流程是怎樣的?
- 寫業(yè)務(wù)邏輯代碼(例如 es6,scss,pug 等)
- 處理成瀏覽器認(rèn)識(shí)的(js,css,html)
- 瀏覽器自動(dòng)刷新看到效果
前端開發(fā)就是在不斷的 123..123..123.... 循環(huán)中進(jìn)行的,上面的后兩步(也就是 2 和 3)應(yīng)該是 自動(dòng)化 的,前端開發(fā)者理應(yīng)只需關(guān)注第 1 步——寫業(yè)務(wù)邏輯代碼。
自動(dòng)化的事情應(yīng)該交由構(gòu)建工具來做,時(shí)下流行的前端構(gòu)建工具有 gulp 和 webpack(有人說 webpack 不算是構(gòu)建工具,我覺得這沒什么好爭(zhēng)的。橫看成嶺側(cè)成峰,我覺得從當(dāng)前 webpack 所能做的事情來看,說它是構(gòu)建工具絲毫不為過)。本文不會(huì)對(duì) gulp 和 webpack 的概念和內(nèi)容做深入解析,而是希望從宏觀的角度研究他們的優(yōu)勢(shì)短缺和適用場(chǎng)景,從而說清長(zhǎng)期彌漫在前端圈二者之間撲朔迷離的關(guān)系。
什么是構(gòu)建工具
構(gòu)建工具是一段自動(dòng)根據(jù)源代碼生成可使用文件的程序,構(gòu)建過程包括打包、編譯、壓縮、測(cè)試等一切需要對(duì)源代碼進(jìn)行的相關(guān)處理。構(gòu)建工具的目的是實(shí)現(xiàn)構(gòu)建過程的自動(dòng)化,使用它可以讓咱們避免機(jī)械重復(fù)的勞動(dòng)(這怕是程序員最不能忍受的了),從而解放我們的雙手。
解放了雙手干什么
哇槽,愛干什么干什么。
Gulp 為何物
先來聽聽 Ta 的官網(wǎng)是怎么說:
Gulp 致力于 自動(dòng)化和優(yōu)化 你的工作流,它是一個(gè)自動(dòng)化你開發(fā)工作中 痛苦又耗時(shí)任務(wù) 的工具包。
想一想咱們?nèi)粘5拈_發(fā)工作中痛苦又耗時(shí)任務(wù)有哪些呢?
- 用 es6,typescript 編寫的腳本文件需要編譯成瀏覽器認(rèn)識(shí)的 javascript
- 用 scss,less 編寫的樣式文件需要編譯成瀏覽器認(rèn)識(shí)的 css
- 檢查代碼是否符合書寫規(guī)范,跑單元測(cè)試和集成測(cè)試
- 開發(fā)環(huán)境如果有 sourcemaps 的話調(diào)試起來就方便多了,修改完代碼瀏覽器能自動(dòng)刷新立即看到效果就更好了
- 生產(chǎn)環(huán)境部署代碼需要壓縮合并靜態(tài)文件,添加文件指紋控制緩存
- blabla...更多的你自己想吧
Gulp 聲稱要幫咱們實(shí)現(xiàn) 自動(dòng)化,那他是怎樣幫助咱們實(shí)現(xiàn)自動(dòng)化的呢?這就不得不先提一嘴牛逼哄哄的 NodeJS。
Node 背景小知識(shí)
Node 使前端 Jser 有了脫離瀏覽器工作的能力,要擱以前的話咱們寫的 js 要么嵌到 html 頁面里,然后用瀏覽器打開 html 頁面才能運(yùn)行js,要么就是在瀏覽器開發(fā)者工具的 Console 面板里編寫運(yùn)行代碼片段??傊疀]了瀏覽器這個(gè)宿主,咱們的 js 就 run 不起來。Node 這貨突發(fā)奇想,把開發(fā)者工具的 Console 給摳下來了,從此 js 可以脫離瀏覽器直接在 node 里運(yùn)行。相當(dāng)于 js 現(xiàn)在有了兩個(gè)宿主環(huán)境,一個(gè)是瀏覽器,一個(gè)是 node。當(dāng)然了,Node 可不是開發(fā)者工具里的 Console,那只是打個(gè)比方。它是基于Chrome V8 引擎實(shí)現(xiàn)的一個(gè) JavaScript 運(yùn)行環(huán)境,功能其實(shí)類似 Console 面板,但提供了大量實(shí)用的 API,感興趣的同學(xué)可前往 Node官網(wǎng) 詳細(xì)了解,英文吃力的騷年 戳這里。Node 可以算是前端革命式的創(chuàng)新,隨 node 一起發(fā)布的 node 包管理器 npm(node package manager) 也已經(jīng)是全球最大的開源庫生態(tài)系統(tǒng)。node/npm 這對(duì)組合一出,前端生態(tài)迎來了大爆發(fā),一時(shí)間為解決各種問題的 node 包層出不窮,遍地開花。gulp 就是披荊斬棘,一路過五關(guān)斬六將闖出來的一個(gè)小 node 包。
扯談完畢,接下來就來看看 gulp 是不是在裝逼,他到底能不能幫我們實(shí)現(xiàn)自動(dòng)化。
作為一個(gè) node 包,標(biāo)準(zhǔn)打開方式當(dāng)然是:
npm i -g gulp然后呢,這里以編譯 less 為例,首先安裝編譯 less 需要用到的 node 包:
npm i --save-dev gulp gulp-less前面已經(jīng)全局安裝過 gulp 了,怎么又本地安裝了一遍
前面的 -g 是全局安裝,是為了執(zhí)行你所編寫的 gulp 任務(wù),即 gulp yourTask。而后面的 --save-dev 是本地安裝,是為了咱們編寫任務(wù)時(shí)使用 gulp 提供的 api,例如 gulp.src()、gulp.task()、gulp.dest() 等等。當(dāng)然也是可以直接使用全局安裝的 gulp 的 api 的,但是強(qiáng)烈不推薦,因?yàn)檫@樣涉及到 gulp 版本控制的問題,而且使用全局 gulp 的 api 的話就會(huì)產(chǎn)生環(huán)境依賴(你假設(shè)環(huán)境已經(jīng)全局安裝了gulp,萬一沒裝呢,程序不就出錯(cuò)了)。
接著在項(xiàng)目的根目錄下新建一個(gè) gulpfile.js 文件,這是 gulp 的默認(rèn)配置文件。
gulpfile.js 必須放在項(xiàng)目根目錄?
當(dāng)然也可放在其他目錄,但這樣的話就得在啟動(dòng) gulp 任務(wù)時(shí)手動(dòng)指定 gulp 配置文件 gulp yourTask --gulpfile yourGulpfilePath,可能還需要全局安裝 gulp-cli,所以除非有特殊需要,否則就放在項(xiàng)目根目錄就行了,這樣最簡(jiǎn)單。
配置文件的名字必須是 gulpfile.js 嗎?
不區(qū)分大小寫,取成 gULPFile.js 的話 gulp 也能認(rèn)識(shí),只要 toLowerCase 之后是 gulpfile 就行了,如果取其它名字那你就又得使用 --gulpfile 選項(xiàng)去指定了。
現(xiàn)在工程目錄結(jié)構(gòu)已經(jīng)成了下面的樣子:
構(gòu)建前 gulp 工程目錄結(jié)構(gòu)
接下來就是在 gulpfile.js 里編寫 gulp task(gulp 把為每個(gè)痛苦又耗時(shí)任務(wù)編寫的處理方法稱為一個(gè) task):
const gulp = require('gulp'); const less = require('gulp-less');gulp.task('build:less', function(){return gulp.src('./src/*.less').pipe(less()).pipe(gulp.dest('./dist')); });最后就是打開一個(gè)終端,在終端里運(yùn)行 gulp build:less。好了,編譯后的文件已經(jīng)被輸出到了 dist 目錄:
構(gòu)建后 gulp 工程目錄結(jié)構(gòu)
至此你已經(jīng)算是一個(gè) gulp 磚家了,這基本上就是 gulp 的全部?jī)?nèi)容。怎么樣,是不是夠簡(jiǎn)單,夠絲滑。這也是 gulp 的突出特點(diǎn)——易于學(xué)習(xí),易于使用,五分鐘成磚家。如果想要執(zhí)行解決其他痛苦又耗時(shí)的任務(wù),只需下載安裝對(duì)應(yīng)的 gulp 插件包,然后依次類推寫一個(gè) gulp.task 出來就行了。
這些源代碼具體是怎樣被處理的
這通常不需要關(guān)心,因?yàn)?gulp 插件包已為你做好了,并且封裝的非常漂亮,你只需要告訴 gulp 你要什么,gulp 及其插件會(huì)幫你打點(diǎn)好一切。這就好比你把一份電子文檔傳進(jìn)打印機(jī),告訴它我要一份 A4 紙打印,呲呲呲~,打印機(jī)就吐出來一張 A4 紙,上面是你的文檔內(nèi)容。源代碼就是你的電子文檔,gulp 插件就是打印機(jī),生成的可用文件就是你手里的那張 A4 紙,你不用關(guān)心打印機(jī)內(nèi)部是怎樣工作的,因?yàn)樗庋b的很好,或者你可以把打印機(jī)拆了一探究竟也行。
Gulp 是基于流的?
流(Stream)不是 gulp 創(chuàng)造的概念,而是從 unix 時(shí)代就開始使用的 I/O 機(jī)制,一直到現(xiàn)在仍在廣泛使用。Node 封裝了一個(gè) stream 模塊專門用來對(duì)流進(jìn)行操作。gulp 所基于的流即是 Node 封裝起來的 stream。上面 gulp.task() 代碼里面的 pipe 方法并不是 gulp 提供的 api,而是 node 的 api,準(zhǔn)確的說應(yīng)該是 node 的 stream 模塊提供的 api。具體是怎么實(shí)現(xiàn)的呢:gulp.src() 的返回值是 node Stream 的一個(gè)實(shí)例,之后的 pipe 調(diào)用的其實(shí)是這個(gè)實(shí)例的 pipe 方法,而 pipe 方法的返回值依然是 node Stream 實(shí)例,以此實(shí)現(xiàn)前面的 .pipe().pipe().pipe() 這種串聯(lián)寫法。熟悉 jQuery 的同學(xué)應(yīng)該很清楚這種技巧。
webpack 又是從哪冒出來的
gulp 似乎是完美的,對(duì)前端開發(fā)工作中每一項(xiàng)痛苦又耗時(shí)任務(wù)都能見招拆招,各個(gè)擊破。然而前端發(fā)展速度之快超乎想象,對(duì)頁面性能和用戶體驗(yàn)更是追求極致,以至于 gulp 某些領(lǐng)域尤其大型 SPA(單頁應(yīng)用)顯得有些不夠用了:
- 單頁應(yīng)用的核心是模塊化,ES6 之前 JavaScript 語言本身一直是沒有模塊系統(tǒng)的,導(dǎo)致 AMD,CMD,UMD 各種輪子模塊化方案都蹦出來。對(duì)這種模塊化亂象,gulp 顯得無能為力,gulp 插件對(duì)這一塊也沒有什么想法。不過也可以理解,模塊化解決方案可不是誰都能 hold 住的,需要考慮的問題太多了;
- 對(duì)前沿的 SPA 技術(shù) gulp 處理起來顯得有些力不從心,例如 Vue 的單文件組件,gulp 配合一些插件可以勉強(qiáng)處理,但是很蹩腳。其實(shí)歸根結(jié)底,還是模塊化處理方面的不足;
- 優(yōu)化頁面加載速度的一條重要法則就是減少 http 請(qǐng)求。gulp 只是對(duì)靜態(tài)資源做流式處理,處理之后并未做有效的優(yōu)化整合,也就是說 gulp 忽略了系統(tǒng)層面的處理,這一塊還有很大的優(yōu)化空間,尤其是移動(dòng)端,那才真的是一寸光陰一寸金啊,哪怕是幾百毫秒的優(yōu)化所帶來的收益(用戶?流量?付費(fèi)?)絕對(duì)超乎你的想象。別跟我說 gulp-concat,CSS Sprites,這倆玩意兒小打小鬧還行,遇上大型應(yīng)用根本拿不上臺(tái)面?,F(xiàn)在的頁面動(dòng)輒上百個(gè)零碎資源(圖片,樣式表,腳本),也就是上百個(gè) http 請(qǐng)求,因此這個(gè)優(yōu)化需求還是相當(dāng)迫切的。關(guān)于為何減少 http 請(qǐng)求可以有效降低頁面加載時(shí)間戳這里。
- blabla... 你自己想吧,主要就是大型單頁應(yīng)用方面有短板;
時(shí)勢(shì)造英雄。webpack 一聲吼,大張旗鼓地挖起了gulp 的墻角。
老規(guī)矩,先看看webpack官網(wǎng)怎么吹牛逼介紹自己的:
Webpack 是當(dāng)下最熱門的前端資源模塊化管理和打包 工具。它可以將許多松散的模塊按照依賴和規(guī)則打包成符合生產(chǎn)環(huán)境部署的前端資源。還可以將按需加載的模塊進(jìn)行代碼分割,等到實(shí)際需要的時(shí)候再異步加載。
是不是看完一臉懵逼,不明覺厲。其實(shí)翻譯過來就是 “在我眼里,什么都是模塊”。webpack “萬物皆模塊” 的理念和 SPA 配合起來簡(jiǎn)直是金童玉女,天作之合。這也是 webpack 短時(shí)間內(nèi)名聲大噪,直接撼動(dòng) gulp 地位的主要原因。
webpack 的理念比較前衛(wèi),它本身也帶來了很多新的概念和內(nèi)容,諸如加載器(loader)、依賴圖(Dependency Graph)等等。和 gulp 兩小時(shí)成磚家的學(xué)習(xí)難度相比,webpack 或許你研究?jī)商烊匀粫?huì)暈頭轉(zhuǎn)向。
接下來簡(jiǎn)單看一下 webpack 的主要工作方式。
webpack 和 gulp 一樣也是一個(gè)小 node 包,打開方式自然是:
npm i -g webpack npm i --save-dev webpack和 gulp 一樣,全局安裝是為了執(zhí)行 webpack 任務(wù),本地安裝是為了使用 webpack 提供的 api。
安裝完 webpack 之后在項(xiàng)目根目錄下新建一個(gè) webpack.config.js,這是 webpack 的默認(rèn)配置文件,同 gulp 的 gulpfile.js 的功能類似。webpack.config.js 同樣是不區(qū)分大小寫的,取成 webPACk.CONfig.js 的話 webpack 也能認(rèn)識(shí),但是取成其他名字或放在別的目錄就需要使用 --config 選項(xiàng)去指定配置文件了。
現(xiàn)在工程目錄結(jié)構(gòu)如下:
構(gòu)建前webpack工程目錄結(jié)構(gòu)
接下來就是在 webpack.config.js 里配置需要的選項(xiàng),注意了,webpack 與 gulp 的重要不同就是使用方式 由編程式變成了配置式:
const path = require('path');module.exports = {entry: './src/index.js', // 告訴 webpack 你要編譯哪個(gè)文件output: { // 告訴 webpack 你要把編譯后生成的文件放在哪filename: 'bundle.js',path: path.join(__dirname, 'dist')} };最后仍然和 gulp 類似,就是在終端里運(yùn)行 webpack(終端里一般會(huì)出現(xiàn)一大坨編譯信息)。好了,現(xiàn)在 webpack 已經(jīng)把編譯好的文件輸出到了 dist 目錄:
構(gòu)建后webpack工程目錄結(jié)構(gòu)
看到這是不是已經(jīng)一頭霧水了,在你還沒明白發(fā)生了什么的時(shí)候 webpack 已經(jīng)把事情干完了。這也是 webpack 和 gulp 作業(yè)方式的重要不同:Gulp 是搭了個(gè)臺(tái)子,讓 gulp 插件在上面唱戲,盡情表演,所有構(gòu)建相關(guān)的具體事情都交由 gulp 插件去做。而 Webpack 就牛逼了,webpack 先搭了個(gè)臺(tái)子,然后自己在上面唱嗨了,仔細(xì)一聽,他在上面唱的是《我們不一樣》,當(dāng)然了他也是讓 webpack 插件在上面唱戲的。
也就是說 webpack 把很多功能都封裝進(jìn)了自己身體里面,使得自己強(qiáng)大同時(shí)臃腫。現(xiàn)在你可以在 ./src/index.js 文件里直接寫 ES6 代碼,因?yàn)?webpack 把編譯 ES6 的工作已經(jīng)封裝到自己的實(shí)現(xiàn)里了,使得 webpack 看起來原生支持 ES6 而不需要借助第三方插件,其實(shí)他內(nèi)部也是用了第三方插件的,所以你不用再專門去下一個(gè) babel 之類的插件去轉(zhuǎn)譯 ES6。這樣封裝的好處是使用起來很方便,不好的地方就是使用者完全不知道發(fā)生了什么,構(gòu)建完了還一臉懵逼。
上面僅是 webpack 使用的最最最簡(jiǎn)單示例,簡(jiǎn)直連 “hello world” 都算不上。具體怎樣打包各種資源(typescript,樣式表,圖片,字體等等)可前往 webpack官網(wǎng) 深入學(xué)習(xí),想看中文的同學(xué)使勁 戳這里。
webpack “一切皆模塊” 的特點(diǎn)完美解決了上面 gulp 暴露的幾個(gè)短板,連 webpack 官網(wǎng)也說自己是因?yàn)榭吹浆F(xiàn)存的模塊打包器都不太適合大型 SPA 應(yīng)用,于是決定打造一個(gè)適合大型 SPA 應(yīng)用的模塊打包器,也就是說 webpack 其實(shí)就是為大型 SPA 而生的。
webpack 怎么實(shí)現(xiàn)像 gulp 一樣對(duì)大量源文件進(jìn)行流式處理
人家 webpack 本來就沒打算做這事。webpack 不是以取代 gulp 為目的的,而是為了給大型 SPA 提供更好的構(gòu)建方案。對(duì)大量源文件進(jìn)行流式處理是 gulp 擅長(zhǎng)的事,webpack 不想搶,也沒必要搶。即使搶,也無非是再造一個(gè)蹩腳的 gulp 出來而已。
既然 webpack 模塊化這么強(qiáng),那以后模塊化就全用 webpack 好了
webpack 模塊化是強(qiáng),但是他胖啊,不是所有人都抱得動(dòng),主要是他為了提供更多的功能封裝進(jìn)了太多東西,所以選擇上還是需要因地制宜。如果單純只是打包 js(多頁應(yīng)用往往是這種需求),完全可以使用 rollup,browserify 這種小而美的實(shí)現(xiàn),因?yàn)樗麄冎蛔鲆患隆虬黬s。而如果需要將圖片,樣式,字體等所有靜態(tài)資源全部打包,webpack 毫無疑問是首選。這也是為什么越來越多的流行庫和框架開始從 webpack 轉(zhuǎn)向使用 rollup 進(jìn)行打包,因?yàn)樗麄冎恍枰虬?js,webpack 好多強(qiáng)大功能根本用不到。連 rollup 官網(wǎng)也坦言如果你在構(gòu)建一個(gè)庫,rollup 絕對(duì)是首選,但如果是構(gòu)建一個(gè)應(yīng)用,那么請(qǐng)選 webpack。
結(jié)論
我看好多人說 gulp 和 webpack 不是一類東西,我不這么覺得,雖然說兩者的出發(fā)點(diǎn)確實(shí)是不一樣的,gulp 走的是流式處理路線,webpack 走的是模塊處理路線,但是兩者所要達(dá)成的目標(biāo)卻是一樣的,那就是促進(jìn)前端領(lǐng)域的自動(dòng)化和工程化管理。webpack 發(fā)展到現(xiàn)在,已經(jīng)非常強(qiáng)大了,強(qiáng)大到在構(gòu)建方面 gulp 能做的事 webpack 基本上都可以勝任,gulp 做不了的 webpack 也能搞。同樣的那些開發(fā)工作中痛苦又耗時(shí)的任務(wù),gulp 和 webpack 都能解決,只是解決思路有天壤之別。
下表是從各個(gè)角度對(duì) gulp 和 webpack 做的對(duì)比:
| Gulp | Webpack | |
| 定位 | 基于流的自動(dòng)化構(gòu)建工具 | 一個(gè)萬能模塊打包器 |
| 目標(biāo) | 自動(dòng)化和優(yōu)化開發(fā)工作流,為通用 website 開發(fā)而生 | 通用模塊打包加載器,為移動(dòng)端大型 SPA 應(yīng)用而生 |
| 學(xué)習(xí)難度 | 易于學(xué)習(xí),易于使用,api總共只有5個(gè)方法 | 有大量新的概念和api,不過好在有詳盡的官方文檔 |
| 適用場(chǎng)景 | 基于流的作業(yè)方式適合多頁面應(yīng)用開發(fā) | 一切皆模塊的特點(diǎn)適合單頁面應(yīng)用開發(fā) |
| 作業(yè)方式 | 對(duì)輸入(gulp.src)的 js,ts,scss,less 等源文件依次執(zhí)行打包(bundle)、編譯(compile)、壓縮、重命名等處理后輸出(gulp.dest)到指定目錄中去,為了構(gòu)建而打包 | 對(duì)入口文件(entry)遞歸解析生成依賴關(guān)系圖,然后將所有依賴打包在一起,在打包之前會(huì)將所有依賴轉(zhuǎn)譯成可打包的 js 模塊,為了打包而構(gòu)建 |
| 使用方式 | 常規(guī) js 開發(fā),編寫一系列構(gòu)建任務(wù)(task)。 | 編輯各種 JSON 配置項(xiàng) |
| 優(yōu)點(diǎn) | 適合多頁面開發(fā),易于學(xué)習(xí),易于使用,接口優(yōu)雅。 | 可以打包一切資源,適配各種模塊系統(tǒng) |
| 缺點(diǎn) | 在單頁面應(yīng)用方面輸出乏力,而且對(duì)流行的單頁技術(shù)有些難以處理(比如 Vue 單文件組件,使用 gulp 處理就會(huì)很困難,而 webpack 一個(gè) loader 就能輕松搞定) | 不適合多頁應(yīng)用開發(fā),靈活度高但同時(shí)配置很繁瑣復(fù)雜?!按虬磺小?這個(gè)優(yōu)點(diǎn)對(duì)于 HTTP/1.1 尤其重要,因?yàn)樗匈Y源打包在一起能明顯減少瀏覽器訪問頁面時(shí)的資源請(qǐng)求數(shù)量,從而減少應(yīng)用程序必須等待的時(shí)間。但這個(gè)優(yōu)點(diǎn)可能會(huì)隨著 HTTP/2 的流行而變得不那么突出,因?yàn)?HTTP/2 的多路復(fù)用可以有效解決客戶端并行請(qǐng)求時(shí)的瓶頸問題。 |
| 結(jié)論 | 瀏覽器多頁應(yīng)用(MPA)首選方案 | 瀏覽器單頁應(yīng)用(SPA)首選方案 |
gulp 為何不吸取百家之長(zhǎng),把 webpack 的東西集成進(jìn)來,反正都是開源的
騰訊那么牛逼,你說他怎么不把阿里巴巴集成進(jìn)來。集成應(yīng)該是沒可能,因?yàn)?gulp 和 webpack 的定位不一樣。所以,沒有放之天下而皆準(zhǔn)的解決方案,只有具體問題具體分析選擇適合的解決方案才能正確地解決問題。gulp 和 webpack 只是我們解決問題的工具,不要被工具束縛了手腳不能前進(jìn)。
扯了這么多,到底誰會(huì)被拍死在沙灘上
可以看出來,這兩個(gè)工具其實(shí)各有優(yōu)缺,都有用武之地。合理地配合使用,取長(zhǎng)補(bǔ)短,才能發(fā)揮最大的威力,所以這倆基友并不是互斥的,而是互補(bǔ)的,誰也不會(huì)被拍死在沙灘上。
臨末,送大家一個(gè)福利 ?
轉(zhuǎn)載于:https://www.cnblogs.com/iovec/p/7921177.html
總結(jié)
以上是生活随笔為你收集整理的前端构建工具之争——Webpack vs Gulp 谁会被拍死在沙滩上的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python - Windows系统下安
- 下一篇: 12月7日学习内容整理:ORM单表操作