前端構建工具webpack有什麼缺陷?

發現最近似乎webpack比較火,和requireJS和browserify相比,它也確實有一些獨到的優勢。

但是有沒有哪些場景是不適合用webpack的嗎?比如非SPA(Single Page Application)網站是否不適合webpack?另外它的工具鏈是否有Grunt/Gulp那麼成熟呢?大家在用的過程中遇到過哪些坑?


充斥著大量名字類似 what-the-fuck-is-this-plugin 的插件,以及這個插件附帶的一千種配置一萬種副作用,以至於每次出現打包的問題都會產生哲學三問:

  • 這個插件幹了什麼?
  • 我的配置有錯誤嗎?
  • 這個插件真的沒有bug嗎?


不知道是不是我的姿勢不對,Webpack 目前在做 Server-side render/Isomorphic/Universal 時真是坑得一比……

好不容易,你終於喜歡上了在 .js 里 require 一切資源的快感,無論 CSS,Sass 還是圖片,Webpack 都會用覆寫 require() 的黑魔法幫你搞定……現在你想在 Node 里也搞這些了,哪有這樣的 require 給你用啊!Build 出來的東西直接扔到 Node 里你就等著各種報錯吧……

為什麼會報錯?就算你配置成 `target: node` 還把 `CommonsChunkPlugin` 關掉,你要不要用 css-loader? css-loader 代碼里一堆堆的 document 和 window 你在 Node 環境哪裡找 DOM 和 BOM 啊;當然,url-loader 這種瀏覽器無關的倒是仍然可以用……

官方的案例 webpack/react-webpack-server-side-example · GitHub 簡直就是自己 hack 自己好嗎,css-loader 不能用了自己封裝一個然後把行內樣式吐到 react render 里,chunk 的 filename 加 hash 完拿不到了自己去 stats 里取,真開心……人家自己都說了:

This example is meant as inspiration to develop an framework that can do server-side rendering of react with webpack. You shouldn"t use the code, only the idea.

至於這篇 Backend Apps with Webpack (Part I) ,教我們如何 hack 掉 node_modules 的問題,教我們如何把所有的 css 文件都忽略掉(喂)……最後還開心的問你「That wasn"t hard, was it?」,Fxxk off dude!

這大概也是為什麼在網上搜 Isomorphic React blah blah 基本都是用 gulp + browserify 來做構建工具的原因吧:webpack 在設計之初主要還是沖著瀏覽器端(尤其是 SPA)去的,牛逼在人家對依賴的理解上,也因此才打出 Unversial Bundler + Code Splitting + Load on demand 這種組合技;如果只是在 server 端用做工具流工具就毫無優勢了,強依賴靜態分析的做法在靈活性上被 gulp 與 browserify 這種小而美的工具完爆,比如你都不依賴一個 scss 你怎麼 transform 它,比如做持續集成需要 revision assets 用個 gulp-rev 好歹能給你吐出個 manifest 來給你做 map……當然畢竟 gulp 也就適合做那麼點事,主要還是對 webpack 萬物 require 的期望太高了……

說來說去,也就是處理靜態文件依賴的能力在 Server 端大打折扣了,只是編譯個 JSX/ES6 替代個 browserify 還是可以的,那 CSS 呢?老老實實當靜態文件搞吧,或者全部用 CSS in JS 就可以解決了……

哎呀我就是被坑了一晚上過來吐槽一下而已……以上


太多黑魔法,

過於複雜了,很多時候會覺得怎麼突然就跑通了,然後配置就不敢改了。當然願意折騰的話,也可以多踩踩坑吧。

配置多的嚇人,devtool就有多少個值?還@#前綴。

另外輸出的文件實在是太丑了。沒壓縮都沒法讀。

以上。配置工程師血與淚的感悟。


webpack的概念很牛逼,webpack的文檔很傻逼。

各plugin不管自帶的還是社區的文檔都不大好,看起來感覺你似乎應該是大師了,而且換個版本可能就出神秘bug,所以,摸出好使的配置之後,趕緊地,lock version,就用這個配置就用這些版本了,不要想太多,先搞個好使配置再說。


1、如果沒有 babel, webpack 對 ES2015+ 的語法是不接受的,會提示用指定 loader

這意味著,在支持部分 ES2015 語法的 firefox 與 chrome 瀏覽器中能直接跑的代碼,無法用 webpack 編譯。

2、因為 webpack 是靜態編譯,需要在打包時就掃描到所有可能的模塊,所以想用 require(expression) 在運行時獲取模塊目前並不支持。

from 評論:

聽臨 :第二條,簡單的expression是可以被接受了,比如 require("/tests/" + x), 它會把 tests/ 下面的所有東西都打包一遍。

3、由於 webpack 是為模塊化而生的工具,所以當你只想複製文件到另一個文件夾,順便對文件做一些文本補充、替換等工作,你用 webpack 不合適,用 gulp/grunt 更佳。這不算它的缺陷,而屬於 webpack 無法取代 gulp 的地方。

4、 webpack 的全局統籌使得你只改動一個文件里的一行代碼,也是整個項目全部重新分析與編譯,給各個模塊分配 webpack_id。

from 評論:

尤雨溪 : 模塊都是 cache 了的,只會重編譯改動的文件。

這意味著,隨著項目複雜度的增加,編譯時長也會不斷增加。所以才有 webpakc_dev_server 之類的東西,但配置繁瑣,用起來也不美。

……暫時想到這些。


最大的缺陷就是

配置過於複雜..

官網文檔混亂...

但是,

像Vue這樣的MVVM框架,

官網還是推薦使用webpack+vue進行開發

還是老老實實啃官網文檔吧


用一次感覺跟做了一場外科手術似的


占坑 晚點來回答。

=======我是漂亮的分割線==========

好吧,占坑一年,慚愧慚愧。

既然題主說缺陷,那我就只說說缺陷。

1.文檔缺失,尤其中文文檔

長期以來webpack官方文檔和example匱乏,提供的一些例子都是很簡單那種,經常發現完全按照例子來配置但就是跑不起來,中文文檔就更不用說了,少的可憐。這個問題也直接導致下面的第2點。

當然,最近新版本的文檔 https://webpack.js.org/ 發布之後,可讀性有很大的改觀。

2.配置難難調試

稍微複雜一點的項目,如果使用webpack編譯,不經過一段痛苦不堪的配置調試過程是沒法正常跑起來的。這還沒完,在自己機器上跑起來之後可能到了另一個同事哪兒又報錯了等等。總之正如下面有人回答那樣,配置文件一旦跑起來,是根本不敢去改的,生怕又出錯。

webpack的錯誤提示也非常難看懂,基本不可能從錯誤很直觀的找到原因,長期以來碰到問題只能靠猜,你沒看錯,就是靠猜!!

3.編譯慢

經驗不足的同學很容易碰到這個問題,當然可以通過一些手段做優化,比如配置module的resolve、root等,使用happypack加速、dll提前編譯等等。但是筆者曾經嘗試過happypack,對編譯速度有提升但效果不明顯,dll的話我有按照官方文檔的做法去做,但是最終編譯出來又報了一些莫名其妙的錯(也有可能是代碼寫的有問題),總之心累,後來直接改成externals方式,全局script引入第三方庫。

4.對server-render不友好

webpack本質上還是靜態打包,意思就是打包完成之後其實文件的載入順序已經固定,只是被載入的時間不定而已。所以使用webpack原則上不存在按需載入之類的說法,code split其實是人工分隔,但是真實的按需載入場景豈是人工能枚舉完的 (下劃線這句話不太好解釋,也不想過多解釋,熟悉前端工程的人應該都明白啥意思)。

這方面FIS的做法比webpack要先進多了,具體請移步我的另一個回答:我想問下fis3和webpack有什麼區別?

在這裡我要說的對server-render不友好其實是指html的處理,webpack其實是通過在js里用require標記資源然後載入任意資源(css、圖片、fonts等等),但其實html文件才是頁面真實的入口,最終編譯出的js還是需要引入到html里,為了防止css懶載入導致頁面抖動,編譯完的css還需要從js裡邊提取出來放到html外鏈。

目前一般都是通過html-webpack-plugin來做這個事情,先搜集某個html所引用的靜態資源最終自動插入到html。這種方式對於前端渲染的應用沒有問題,但是對於server-render的那就不行了,因為server-render下html是作為模板由後端語言吐出,而開發模式下(例如webpack-dev-server)webpack是不會輸出任何文件的(開發環境webpack是將文件放到內存然後在路由層自動serve了),所以這會導致開發環境模板無法引用靜態資源。當然,有一種解決方案就是靜態資源不改變文件名稱,預先寫好路徑,開發環境和生產環境同名(即覆蓋式發布)。


react 的項目用 webpack 還不錯,目前非react 項目 還是以gulp+webpack 來搞,webpack僅被用來是代替 browerify 來做JS的模塊化


1. 配置多入口時,沒有glob的方式,需要額外處理。

2. 目錄結構複雜時,file-loder裡面的path功能太弱,很多時候無法自定義構建後的目錄結構,只能放在一個目錄下。

3. 源碼比較複雜,遇到問題看源碼,要花很長時間。


對於一個菜鳥來說,學習這種一次性配置文件的成本太大,用腳手架生成的配置文件升級的時候一臉懵逼,雖然有官方提示,但有時候一個小的配置錯誤要找半天。


當然是它是針對bundle的解決方案啊,http/2的年代我不願意bundle啊。。


其實答主對 webpack 的理解也不深,簡單地答一下自己的看法。我覺得 webpack 存在的一些問題也許和編譯器差不多:使用不當(比如優化過度),會導致一些意料之外的問題。

就像用 gcc 編譯你寫的 c++ 代碼,你使用了 -O3 的優化。結果你的代碼跑著跑著掛了,但換成 -O1,也許你的程序卻毫無問題。

在我看來 webpack 很黑盒,用起來很方便,但背地裡暗搓搓地做了很多優化,有時候遇到啥問題時,把優化關了看看也許就沒問題了。

說說今天遇到的一個小坑吧:

有這樣一段用於居中的 Less 代碼片段:

.title {
margin-left: auto;
margin-right: auto;
.size(margin-top, 15px);
.size(margin-bottom, 15px);
}

稍微解釋一下,.size() 是個 mixin,可以把像素值翻譯成以 rem, vw, vh 為單位的數值,這樣就可以以 iPhone 5 的解析度來設計頁面,並適應其他的解析度。如果手機支持 vw, vh 則用這個單位,如果不支持,就退化成 rem 單位。

比如上面的代碼編譯成 CSS 的結果(可能)是這樣的:

.title {
margin-left: auto;
margin-right: auto;
margin-top: 1.5rem;
margin-top: 2.6408vh;
margin-bottom: 1.5rem;
margin-bottom: 2.6408vh;
}

結果在手機上測試了一下,發現 iPhone 顯示的效果還行,Android 的兩個測試機顯示出的效果都是 .title 不居中了。

來探究一下原因,通過 webpack 優化後的 CSS 會變成這樣:

.title {
margin: 2.6408vh auto 2.6408vh;
margin-top: 1.5rem;
margin-bottom: 1.5rem;
}

終於真相大白了,在安卓 4.3 及以下版本是不支持 vw, vh 單位的,所以在優化後的代碼中,第一條規則被忽略了;而用於居中的代碼也就一併被無視了。

所以使用一個工具的同時,也要花時間去了解它的原理。

(答主也屬於不夠了解的類型......?(? ???ω??? ?)?......)


如果說 webpack 有缺陷的話,就是需要持久的學習,不斷的去更新版本 配置(webpack本身一直在改進,優化)。

Webpack 打包優化之體積篇

Webpack 打包優化之速度篇


我最不喜歡的構建工具就是幫你包辦一切的。webpack就是這樣一種工具。

webpack我覺得最大的亮點就是require anything和code splitting。

require anything 我還比較喜歡,可以去用來實現組件化,css, html, js等資源以組件的級別分離,但是沒有webpack也可以做到。webpack幫你生成了模塊化管理的代碼來實現require anything,就是幫你引入了類似seajs這樣的模塊化管理框架,減少了很多編碼工作。但我覺得這種保姆工作真是多餘,而且限制了項目架構的靈活性

code splitting 說到底已經是老梗,其實就是按需載入,然而webpack這保姆又幫你省了事,我在使用的過程發現生成的chunk還會有代碼冗餘-_-|||。

webpack的初衷就是為了大型SPA服務的,這個作者說的很清楚。webpack作為grunt的一個插件來用比較合適。


可能要習慣一切都在js中require,包括css,image等。

大js果然通吃一切哈


項目大了首次編譯太慢……


1. 文檔爛。

2. 把所有的資源都 require 到 js 中,並不適合所有場景。

3. 1和2版本配置項不兼容,升級麻煩。

4. 沒有生成資源表,如果其他項目沒有用 webpack , 非同步載入模塊比較麻煩。

5. debug 依賴 source map, chrome devtool 首個斷點不能直接點,需要在代碼中加 debugger 關鍵字。


可以看 substack 的 gist browserify for webpack users 和它下面的評論

簡單來說,webpack 太複雜,是比較全面的解決方案(因此配置也比較複雜),而 browserify 只是一個核心,其本身也是由不同模塊組成的,更符合 unix 的干好一件事的哲學。用 webpack 的某些功能和 browserify 去比較是不太公平的,因為哲學不一樣。

browserify 核心代碼沒多少,都拆分成模塊了,你花一天時間大概過一篇,然後自己動手修改擴展需要的部分就好,這樣你能對你的項目有很強的把控。

而 webpack 是另一條路,相當於外包了前端構建這部分,雖然直接上手可能很方便,但是遇到坑的時候,或者需要自己實現一點什麼想法的時候,可能會比較困難和麻煩一點。


感覺在使用webpack配置多入口的項目工程時,會遇上一些問題,比如無法保存項目結構路徑,生成的文件往往在同一級目錄下,使用webpack-dev-server時候多入口時候還沒找到合適的方法進行自動頁面刷新。


推薦閱讀:

DocumentFragment真的能提高 JS 動態添加 DOM 的性能嗎?
如何優化vue的內存佔用?
能否用 JS 實現一個 CSS 解釋器?
如何理解 Facebook 的 flux 應用架構?
js中alert函數的實現原理是什麼?

TAG:前端開發 | JavaScript | 網頁應用 | Nodejs | webpack |