webpack 是一個現代 JavaScript 應用的靜态子產品打包器。那麼 webpack 是怎樣實作不同種類資源子產品加載的呢?
沒錯就是通過 loader。loader 用于對子產品的源代碼進行轉換。loader 可以使你在 import 或加載子產品時預處理檔案。
我們帶着下面幾個問題,徹底吃透 loader ~
webpack 是如何加載資源子產品的呢?我們先試着用 webpack 直接打包項目中的 css 檔案。
初始化一個 webpack 項目,目錄如下:

在 src 目錄下建立了一個 index.css 檔案,這裡建立這個檔案的目的就是以 css 檔案為入口,嘗試使用 webpack 單獨打包它。
調整下 webpack 配置,讓入口檔案路徑指定為 index.css 的路徑。
然後我們到終端運作 <code>npx webpack</code> 指令,你會發現指令行會提示 <code>Module parse failed: Unexpected token (1:5)</code> 子產品解析錯誤。
細心的同學會發現後面還緊跟着一句解決方案:<code>You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.</code>
大緻的意思就是說,您可能需要适當的 loader 來處理此檔案類型,目前沒有配置 loader 來處理此檔案。
這裡,loader 的重要性就凸顯出來了。
30.。0
還是接着剛才打包 index.css 報錯的問題。想加載 css 檔案,我們可以試試常用的 css-loader。
webpack 配置也同步改下:
webpack 配置中 module 屬性添加 rules 對象數組。這裡面的 test 屬性值為一個正規表達式,比對目前 loader 對應處理檔案的格式。use 屬性值為 loader 名稱。
再打包就不會報錯了。
如果想要 index.css 子產品在頁面中生效,隻需要額外添加一個 style-loader,樣式就 OK 了。
style-loader 的作用可以了解為:建立了一個 style 标簽,這個标簽裡面帶入了 css 樣式。标簽最後追加到頁面上。
注意配置多個 loader 時,執行順序是從後往前執行的:
最後的 loader 最早調用,将會傳入原始資源内容
第一個 loader 最後調用,期望值是傳出 JavaScript 和 source map(可選)
中間的 loader 執行時,會傳入前一個 loader 傳出的結果
是以 css-loader 放在最後。具體配置如下:
假如你還要用到 less-loader,同理可知 rules 中 use 屬性值應該為:<code>["style-loader", "css-loader", "less-loader"]</code>
想要實作的大緻流程:
接下來,我們嘗試實作上圖 css-loader 和 style-loader 的簡單版本。
我們在項目根目錄下建立好 css-loader.js 和 style-loader.js 檔案。
主要代碼如下:
每個 webpack 的 loader 都需要導出一個函數,這個函數就是我們這個 loader 對資源的處理過程,它的輸入就是加載到的資源檔案内容,輸出就是我們加工後的結果。我們通過 source 參數接收輸入,通過傳回值輸出。這裡我們先嘗試列印一下 source,然後在函數的内部直接傳回一個字元串 <code>hello webpack css-loader!</code>,具體代碼如下所示:
我們回到 webpack 配置檔案中調整一下加載器規則,調整之後使用的加載器就是我們剛剛編寫的這個 css-loader.js 子產品,具體代碼如下:
溫馨提示:這裡的 use 中不僅可以使用子產品名稱,還可以使用子產品檔案路徑,這點與 Node 中的 require 函數相同。
配置完成後,我們再次打開指令行終端運作打包指令,如下圖所示:
從報錯資訊可以看出,loader 函數的參數就是檔案的内容。
錯誤提示說: <code>You may need an additional loader to handle the result of these loaders.</code> (我們可能還需要一個額外的加載器來處理目前加載器的結果)
溫馨提示:其實 webpack 加載資源檔案的過程最後的結果必須是一段标準的 JS 代碼字元串。
正常流程:
我們現在應該想到是 css-loader 出了問題。
css-loader 主要作用就是将多個 css 子產品整合到一起。
大緻思路:
整個 css 代碼片段以 url(xxx) 類似結構為節點分成多個部分
url 裡的路徑改為 require 引入
用數組的形式将 css 代碼拼湊起來最後形成一個整體
loader 打包結果如下圖:
這是輸出的 bundle.js 的片段,就是把我們剛剛傳回的字元串直接拼接到了該子產品中。這裡也解釋了剛才打包文法報錯的問題(loader 處理完必須傳回 JS 代碼)。
style-loader 會把整合的 css 部分挂載到 head 标簽中。
代碼如下:
loader 就是一個函數,一旦有子產品被 import 或者 require 時它就會去攔截這些子產品的源碼,對其進行改造,然後輸出到另一個子產品中,循環往複,最終輸出到入口檔案中,形成最終的代碼。
也正是有了 loader 機制,我們才能通過 webpack 去加載任何我們想要加載的資源。