前言
上一次在介紹 mini-css-extract-plugin 時,有提到關於使用 background-image:url() 以相對路徑參考本地圖片時所發生的錯誤,最後是使用 file-loader 解決此問題;簡單來說,file-loader 就是用來處理一般開發網頁時所使用的靜態資源,例如:字形、圖片等等,將所有資源載入到 Webpack 內,並且解析資源的相互依賴,最後以配置的選項生成對應的結果;而 url-loader 則類似於 file-loader,可依資源的大小做對應的處理。此篇將介紹 file-loader 與 url-loader 的使用方法,以及兩者在應用時最大的差別為何。
筆記重點
- url-loader 與 file-loader 安裝
- url-loader 與 file-loader 基本使用
- url-loader 與 file-loader 可傳遞選項
- 補充:url-loader 與 file-loader 實際應用
- 補充:file-loader 載入本地字體
url-loader 與 file-loader 安裝
套件連結:url-loader、file-loader
主要的套件:
1 | npm install url-loader file-loader -D |
package.json:
1 | { |
在前面章節,我們會先以 file-loader 做示範,直到關於 base64
一詞的出現,才會使用到 url-loader,請先將兩個 loader 進行安裝。
file-loader 與 url-loader 基本使用
初始專案結構:
1 | webpack-demo/ |
配置 webpack.config.js
檔案:
1 | const path = require('path'); |
配置 file-loader 相對簡單,這邊要注意的是,目前我們的 Regex 只有單純篩選圖片的相關檔案,並未包含其他靜態資源。
entry 入口處 (src/main.js
) 引入圖片檔案:
1 | import './img/test.png'; |
執行編譯指令:
1 | npm run build |
此時會生成名稱為 hash 值的圖片檔案:
1 | webpack-demo/ |
相信有閱讀過以前 Webpack 文章的朋友已經發現其中的問題,那就是我們還沒有配置 filename
,導致預設名稱為 hash 值,這邊要注意,file-loader 並沒有 filename
這個屬性,取而代之的是 name
屬性,讓我們趕緊來配置它:
1 | module.exports = { |
在 file-loader 中的 name
屬性就類似於其他 loader 或 plugin 的 filename
屬性,不同的地方在於,name
屬性得依照官方文件中的 Placeholders 配置才行,上面這個配置就是最基本的依照 entry 檔案的名稱以及附檔名進行 output。
再次執行編譯指令:
1 | npm run build |
此時會生成與 entry 檔案名稱相同的圖片檔案:
1 | webpack-demo/ |
以上就是 file-loader 的基本使用,可能有人會問,那 url-loader 呢?神奇的事情要發生了!讓我們直接將上面的 webpack.config.js
中的 file-loader 更改為 url-loader,如下所示:
1 | module.exports = { |
此時如果你執行 npm run build
進行編譯,結果會與 file-loader 一模一樣,有沒有很神奇?事實上,url-loader 預設提供了一個名為 fallback
的選項,用以調用超過文件大小的程序,如下所示:
1 | module.exports = { |
而 url-loader 中的 options 選項是與 file-loader 共用的,差別在於 url-loader 新增了 limit
選項,用以設置可轉為 base64 的文件大小上限,如下所示:
1 | module.exports = { |
url-loader 唯一的功能就在於將資源轉換為 base64
的格式,主要依靠 limit
控制需轉換的文件,轉為 base64
的好處就在於,往後網頁在渲染圖片時,不需要以 request 的方式加載圖片,直接向 JavaScript 檔案拿取即可,這樣子以效能來說,會提高許多,但你也不能把大小的上限設定太高,由於 base64
是存在於 bundle.js 內,這樣子的做法會導致 JavaScript 異常的肥大,對於效能來說反而會下降,衡量並設置適當的大小才是正確的作法。
再次執行編譯指令:
1 | npm run build |
通過 url-loader 的文件將轉成 base64
存在於 bundle.js 內:
1 | webpack-demo/ |
關於 base64
的實際應用將在下面補充,讓我們來做個總結:
url-loader 與 file-loader 可傳遞選項
可參考 url-loader Options 可傳遞參數列表,以下為常用的參數配置:
limit:
Number
|Boolean
|String
限制可轉為 base64 的檔案大小上限,單位為 byte,默認為underfined
fallback:
String
指定當文件大小超過 limit 限制時,需轉向的加載程序,默認為fiel-loader
範例:
1 | module.exports = { |
可參考 file-loader Options 可傳遞參數列表,以下為常用的參數配置:
name:
String
|Function
設置 output 時的文件名稱,相關參數可參考 Placeholders,默認為[contenthash].[ext]
outputPath:
String
|Function
指定目標文件的公共路徑,在 mini-css-extract-plugin 文章有介紹到,默認為underfined
範例:
1 | module.exports = { |
補充:url-loader 與 file-loader 實際應用
前面講解到了 url-loader 與 file-loader 的基本使用方式,這次讓我們帶入到實際應用內,加深各位對這兩個 loader 的印象。
套件連結:url-loader、file-loader、css-loader、mini-css-extract-plugin
主要的套件:
1 | npm install url-loader file-loader -D |
過程會使用的套件:
1 | npm install css-loader mini-css-extract-plugin -D |
初始專案結構:
1 | webpack-demo/ |
撰寫 CSS 範例:
1 | .w-100-h-100 { |
配置 webpack.config.js
檔案:
1 | const path = require('path'); |
這邊要特別注意!並不是 file-loader 與 url-loader 都要進行配置,直接配置 url-loader 就等同於配置了 file-loader,limit
內的會交由 url-loader 處理,超過 limit
的資源則會 fallback 給 file-loader 進行處理。
entry 入口處 (src/main.js
) 引入 CSS 檔案:
1 | import './css/all.css'; |
至 package.json
新增編譯指令:
1 | { |
執行編譯指令:
1 | npm run build |
至 ./index.html
引入打包而成的 bundle.js
與 main.css
檔案:
1 | <!-- 其他省略 --> |
查看結果:
從上面結果可以得知,logo.png 圖檔已被轉換成 base64 格式,而 banner.png 這張較大的圖檔,被 url-loader fallback 給 file-loader 處理,最後就只是在配置的指定位置生成而已。
補充:file-loader 載入本地字體
有時我們在開發網頁時,會需要使用一些特殊字體,像我本身就很常到 Google Fonts 拉一些字體出來用,不僅可以增加網頁整體的質感,還可以擺脫傳統字體的呆板樣式。
而外部字體的載入方式有很多種,包含一般最為常見的 CSS link,或是使用 @import
方式載入字體,我個人是偏好使用 @font-face
來載入字體,將字體給下載下來,提供較為穩定的載入字體方法。
先前介紹了以 file-loader 或 url-loader 來處理圖片等靜態資源,此章節將介紹如何以 file-loader 處理 .ttf
、.otf
等字體資源,讓我們直接開始吧!
請先至 Google Fonts 隨意下載字體,並放置在
src/font
內
1 | webpack-demo/ |
以 @font-face
載入本地字體:
1 | @font-face { |
配置 webpack.config.js
檔案:
1 | const path = require('path'); |
這邊要注意,如果你打算將圖片、文字打包後放置在同一個路徑下,可以不必另外寫一個 Regex 去處理,上面這種寫法,主要是將圖片與文字放置在不同的資料夾,千萬要記得,Webpack 會將 CSS 內的相關路徑參考語法轉換為 require
的方式進行處理,並不是說 file-loader 的配置只能在 url-loader 區塊內配置,Webpack 是以 Regex 配對相關的 use,千萬不要搞混了!
執行編譯:
1 | npm run build |
此時 src
資料夾內的 font
也通通打包進來了,以下為打包後的 dist
資料夾專案結構:
1 | webpack-demo/ |
觀察打包生成的 CSS 檔案:
1 | @font-face { |
從上面結果可以得知,CSS 內的 @font-face
連結也是正確的,直接打開網頁即可看到字體已被更改,此時我們打包字體的目的也就成功了。
有人可能會問,font 字體可以使用 url-loader 處理嗎?答案是可以的,但非常不建議這樣做,英文字體少說 150 KB 起跳,而中文字體則是 5MB 起跳,對於網頁的效能來說,會有非常大的影響,這也是之前提到的 url-loader 中 limit 選項需要自己去衡量的原因,一般來說 8KB 左右就是極限了,超過的檔案就都建議以 file-loader 進行處理,各位可以自己試試看。