背後靈魂 webpack (2) - 配置 CSS loader & plugin
上回講到了 webpack 基本配置,這回要從 webpack 的一些進化元素,loader
與 plugin
開始講起,而且方向是跟 CSS 編譯相關的!
在開頭會先提到一個檔名的優化配置。
目錄
- 優化配置 - 檔名變化
- plugin & loader 介紹
- CSS 編譯
- css-loader & style-loader
- mini-css-extract-plugin
- file-loader
- 圖片路徑錯誤
優化配置 - 檔名變化
回顧一下上回編譯的 webpack.config.js
配置:
當我們每次編譯後,都會出現一直名為 bundle.js
的 JS 檔,但…如果今天我的 entry
想要不只一個檔案的話該怎麼辦呢?
我們先來新增第二隻 utils.js
:
webpack-demo
|- /src
|- index.js
+ |- utils.js
內容隨便寫個:
const mutiply = (x, y) => x * y
接著我們在 webpack.config.js
裡調整一下:
我們把 entry
改寫為物件,filename
變為 [name].js
,這邊的 [name]
會對應到 entry
的 key
名稱,這時候我們再編譯一次:
就可以看到 entry
變為兩個而且編譯出兩個檔案了!
注意!
[name]
這個名稱標籤接下來會頻繁出現。
接下來我們直接進入 loader & plugin 吧。
loder & plugin 介紹
- loader
loader
存在的原因是為了讓 webpack 可以讀取不同的程式碼。 - plugin
plugin
則是豐富了 webpack 的功能
CSS 編譯
css-loader & style-loader
首先來小試身手,試著編譯 CSS 檔案。編譯 CSS 檔常伴隨著兩個 loader
,css-loader
做的是解析 CSS,style-loader
則是做編譯匯出的部分。
照著安裝步驟:
$ npm install --save-dev css-loader style-loader
接著一樣在 webpack.config.js
加上以下設定:
這邊要講一下其實
use
陣列裡是有順序的,從右至左,先使用css-loader
做 CSS 解析,再使用style-loader
編譯。
我們在資料夾下創一個 index.css
:
webpack-demo
|- /src
|- index.js
|- utils.js
+ |- /css
+ |- index.css
並且寫上一點 CSS:
body {
background: red;
}
在我們設定的 entry
,也就是 index.js
內引入 CSS:
const index = require('./css/index.css')
這樣我們就只需要做最後一步:
$ npm run build
打開 dist/bundle.js
,可以看到剛剛寫的 CSS 已經透過引入被編譯出來:
但…我寫的是 CSS 怎麼會被編譯到 JS 檔裡呢?
其實根據不同需求,可以選擇你要不要插在 JS 檔裡或是把 CSS 抽出來(那個…我懷疑你在開車,但我沒有證據
抽出的話網頁就會多請求一個檔案,沒抽出下 JS 檔就會比較肥大。當然,這時候要介紹個常伴隨 CSS 編譯的一個 plugin
。
mini-css-extract-plugin
這個 plugin
就是幫助我們在編譯時抽離 CSS,舊專案的話你可能會比較常看到 Extract Text Plugin 這個,兩個做的事情是一樣的,只是目前後者在慢慢淘汰。
直接來看安裝方法:
$ npm install --save-dev mini-css-extract-plugin
接著引入 webpack.config.js
,並且把 style-loader
替換掉:
再重新編譯一次,就可以看到 dist
資料夾內跑出 CSS 檔啦!
因為剛剛 output
的設置,檔案名稱會自動對應到我們在 entry
檔案的 key
,我們在 index.js
引入 CSS 的,所以名稱就對應到 index.css
。
file-loader
在講這個 loader
前,我們先在資料夾內新增圖片:
webpack-demo
|- /src
|- index.js
|- utils.js
|- /css
|- index.css
+ |- /assets
+ |- demo.png
並且在 CSS 內引入:
body {
background-image: url('/src/assets/demo.png')
}
並且下指令編譯後,可以看到我們成功編譯出 CSS,但路徑跟上面一樣還指著 src
開發用資料夾。
從上回看到這邊可以隱約發現一個通用習慣:
開發時都用src
資料夾來存放檔案,透過編譯才變成dist
一包。
所以…統整一下現在遇到的問題:
- CSS 路徑一樣是指向
src
開發用資料夾 - 就算改了路徑,圖片也依然存在於
src
資料夾裡
那如果把路徑改為相對路徑來編譯看看呢?
body {
background-image: url('../assets/demo.png')
}
這時後 webpack 就會噴紅字給你看了!
那剛剛的絕對路徑為啥沒有爆呢?原因在 css-loader
上,翻一下文件可以看到他是不會去解析絕對路徑或是路徑以 /
開頭的。
所以…為了讓 webpack 解析相對路徑,還記得文章一開始提到的 loader
嗎?
loader
存在的原因是為了讓 webpack 可以讀取不同的程式碼。
也就是說我們少了一個可以讓 webpack 讀取圖片的 loader
,接下來就是讓 file-loader
出場的時候了:
$ npm install file-loader --save-dev
webpack.config.js
設定檔:
這時候再編譯一次,會發現圖片成功透過 webpack 編譯並且搬進了 dist
資料夾,而且連 CSS 裡面的路徑都變了:
這邊來小總結一次:
- CSS 檔案先透過
css-loader
解析 CSS 語法 - 遇到相對路徑後交由
file-loader
來解析,並且把檔案搬到目標dist
資料夾 - 最後再由
mini-css-extract-plugin
去修正圖片的路徑。
圖片路徑錯誤
這邊要另外補充一點跟圖片有關的,如果在 mini-css-extract-plugin
內設定過 filename
,而且 CSS 不是編譯在 dist
根目錄的話:
路過一下,好奇
filename
與chunkFilename
可以參考延伸閱讀哦!
這時候打開的會是這樣:
會發現根本吃不到圖片,這也是在打包部署常出現的一件事!
因為默認情況下,圖片會是相對
dist
資料夾的根目錄,所以要去更改publicPath
這個屬性。
因為 CSS 檔案包在 CSS 資料夾裡面,需要在前面加上 ../
讓路徑先回到 dist
,再重新編譯一次就好了!
延伸閱讀
fileName & chunkFileName
filename
為一般列在entry
檔內打包出來的檔案。chunkFilename
為未被列在entry
檔內但也需要打包的檔案。
結論
這回我們總共講了:
- 使用
[name]
名稱標籤,來做多個entry
檔案 - css-loader & style-loader
- mini-css-extract-plugin
- file-loader
- CSS 圖片路徑錯誤
這次寫 webpack 發現好多關聯性實在太高了,有些又要排順序…對於不太會計畫的我實在是有點痛苦 XD
到目前我們還有一個不太優的配置是:
- 每次編譯都要手動改
index.html
的路徑連結
第三篇文章 「背後靈魂 webpack (3) — html-webpack-plugin & devServer 」會針對這個問題點來做優化!