webpack 為什么這么難用?

我從多年前的 webpack 1.0 時(shí)代就一直在用它,現(xiàn)在也不能說(shuō)完全掌握了它,很多時(shí)候真的讓我產(chǎn)生了懷疑,究竟是因?yàn)槲业哪芰Σ蛔?,還是因?yàn)?webpack 自身的設(shè)計(jì)就太難用?隨著我接觸到越來(lái)越多的前端項(xiàng)目,聽(tīng)到越來(lái)越多的吐槽,我也越發(fā)地相信,是 webpack 自身的問(wèn)題,導(dǎo)致它變得如此復(fù)雜又難用。
舉個(gè)簡(jiǎn)單的例子,一個(gè) vue-cli 生成的最簡(jiǎn)單的腳手架項(xiàng)目,開(kāi)發(fā)、構(gòu)建相關(guān)的文件就有 14 個(gè)之多,代碼超過(guò) 800 行,而真實(shí)的項(xiàng)目只會(huì)比這個(gè)更多:
所以,既然這篇文章的標(biāo)題是《webpack 為什么這么難用?》,那我們就好好在這里分析一下,webpack 難用的根本原因。
一、文檔極其不完善
是的,這就是第一位的原因。
真的想說(shuō) webpack 即使經(jīng)過(guò)了這么多年的不斷迭代,如今的文檔依然還是是一坨那啥。作為一個(gè)開(kāi)源項(xiàng)目,設(shè)計(jì)好不好、易用性怎么樣、擴(kuò)展性怎么樣這些問(wèn)題都是仁者見(jiàn)仁智者見(jiàn)智的,但文檔寫(xiě)得很爛這一點(diǎn)上,真的沒(méi)有任何可以開(kāi)脫的理由。
對(duì)于使用者的不友好
比如,webpack 的插件體系可以說(shuō)是 webpack 最核心的一部分功能了,基本上一個(gè)項(xiàng)目的構(gòu)建中,大部分任務(wù)都是由各種插件完成的。然而,官方文檔上對(duì)于插件的介紹只有寥寥幾句話(huà):webpack · Plugins,甚至推薦你直接去看 webpack 的源碼:
更糟的是,現(xiàn)有的文檔里(包括 webpack 一些插件的文檔也是),大部分內(nèi)容都是在告訴你 “你這樣做就可以了”,而沒(méi)有解釋 “你為什么需要這么做” 以及 “你這么做了會(huì)有哪些后果”。
比如,在 target 配置上,官方文檔里列舉了你可以構(gòu)建到哪些 target,如 node、node-webkit、electron-main,但都只是簡(jiǎn)單的一句話(huà)帶過(guò):
想知道 target 為 electron-main 時(shí),和瀏覽器環(huán)境的打包有什么不同?對(duì)不起,官方文檔不想告訴你,看源碼或者去 stackoverflow 上搜吧。
官方文檔語(yǔ)焉不詳?shù)闹苯雍蠊褪?,?dāng)你遇到了任何問(wèn)題,你都沒(méi)辦法在文檔里得到直接的回答,而是需要看無(wú)數(shù)的代碼、github issue、stackoverflow、博客文章,然后在自己的項(xiàng)目里反反復(fù)復(fù)試了好多次,才能大致解決問(wèn)題。而這種所謂的“解決問(wèn)題”,一般都是個(gè)人經(jīng)驗(yàn)性的,意味著其它任何一個(gè)人想要解決這個(gè)問(wèn)題,都要重復(fù)一遍這個(gè)流程,時(shí)間成本大量上升。
對(duì)于開(kāi)發(fā)者的不友好
我們要如何開(kāi)發(fā)一個(gè) webpack 的插件?
官方文檔里確實(shí)寫(xiě)了一些關(guān)于如何開(kāi)發(fā)插件的指南。但這份指南也只有 60 分剛及格的水平,它確實(shí)向你介紹了 webpack 插件的基礎(chǔ)范例、基本概念以及一些 API,但當(dāng)你讀完這份簡(jiǎn)短的文檔后想自己真的去開(kāi)發(fā)一個(gè)插件時(shí),你會(huì)發(fā)現(xiàn)文檔里講的東西真的遠(yuǎn)遠(yuǎn)不夠。
我們不妨來(lái)看看現(xiàn)在 webpack 生態(tài)里那些成熟的插件是怎么寫(xiě)的,以 html-webpack-plugin 為例,這是一個(gè)廣泛用于生成 html 文件的插件。在它的源碼里你會(huì)發(fā)現(xiàn),它引用了五個(gè) webpack 內(nèi)部自帶的插件(源碼在這里):
var NodeTemplatePlugin = require('webpack/lib/node/NodeTemplatePlugin');var NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');var LoaderTargetPlugin = require('webpack/lib/LoaderTargetPlugin');var LibraryTemplatePlugin = require('webpack/lib/LibraryTemplatePlugin');var SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
嗯哼?這五個(gè)插件都是用來(lái)干什么的?
官方文檔上對(duì)內(nèi)置的插件一個(gè)字都沒(méi)有提及,是的,甚至連 Plugins 這里都沒(méi)有。官方的 wiki 上倒是寫(xiě)了,但真的真的太簡(jiǎn)略了,而且看起來(lái)很久沒(méi)更新了。
import RequestShortener from 'webpack/lib/RequestShortener';import ModuleFilenameHelpers from 'webpack/lib/ModuleFilenameHelpers';
文檔里同樣沒(méi)有對(duì)這兩個(gè)文件做任何介紹。令人欣慰(?)的是,這兩個(gè)文件從文件名上看,起碼是方法庫(kù)(實(shí)際上也確實(shí)是),使用起來(lái)不會(huì)太復(fù)雜。
換句話(huà)說(shuō),如果你想給 webpack 寫(xiě)一個(gè)廣為人知的插件,你就必須深入了解 webpack 的全部,這一點(diǎn)我不反對(duì),畢竟 webpack 開(kāi)發(fā)者和 webpack 使用者在能力的要求上有高低之分。但即使是有經(jīng)驗(yàn)的開(kāi)發(fā)者,遇到一個(gè)文檔如此不完善的開(kāi)源項(xiàng)目,也是很吃力的。很多能幫助開(kāi)發(fā)者的東西本應(yīng)該正大光明地寫(xiě)在文檔和指南里,而不是隱藏在源代碼里。
