url-loader
、
file-loader
主要的套件:
1
|
npm install url-loader file-loader -D
|
package.json:
1 2 3 4 5 6 7 8
|
{ "devDependencies": { "file-loader": "^6.0.0", "url-loader": "^4.0.0", "webpack": "^4.42.1", "webpack-cli": "^3.3.11" } }
|
在前面章節,我們會先以 file-loader 做示範,直到關於
base64
一詞的出現,才會使用到 url-loader,請先將兩個 loader 進行安裝。
Placeholders
配置才行,上面這個配置就是最基本的依照 entry 檔案的名稱以及附檔名進行 output。
切記先將 dist 資料夾完全刪除,以保證最新的編譯結果如同預期,之後也會介紹使用 clean-webpack-plugin 解決此問題
再次執行編譯指令:
此時會生成與 entry 檔案名稱相同的圖片檔案:
1 2 3 4 5 6
|
webpack-demo/ │ ├─── dist/ │ │ +│ ├─── test.png │ └─── bundle.js
|
以上就是 file-loader 的基本使用,可能有人會問,那 url-loader 呢?神奇的事情要發生了!讓我們直接將上面的
webpack.config.js
中的 file-loader 更改為 url-loader,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
module.exports = { module: { rules: [ { test: /\.(png|jpe?g|gif)$/i, use: [ { loader: 'url-loader', options: { name: '[name].[ext]', }, }, ], }, ], }, };
|
此時如果你執行
npm run build
進行編譯,結果會與 file-loader 一模一樣,有沒有很神奇?事實上,url-loader 預設提供了一個名為
fallback
的選項,用以調用超過文件大小的程序,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
module.exports = { module: { rules: [ { test: /\.(png|jpg|gif)$/i, use: [ { loader: 'url-loader', options: { fallback: require.resolve('file-loader'), }, }, ], }, ], }, };
|
而
url-loader 中的 options 選項是與 file-loader 共用的
,差別在於 url-loader 新增了
limit
選項,用以設置可轉為 base64 的文件大小上限,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
module.exports = { module: { rules: [ { test: /\.(png|jpe?g|gif)$/i, use: [ { loader: 'url-loader', options: { name: '[name].[ext]', limit: 8192
, }, }, ], }, ], }, };
|
url-loader 唯一的功能就在於將資源轉換為
base64
的格式,主要依靠
limit
控制需轉換的文件,轉為
base64
的好處就在於,往後網頁在渲染圖片時,不需要以 request 的方式加載圖片,直接向 JavaScript 檔案拿取即可,這樣子以效能來說,會提高許多,但你也不能把大小的上限設定太高,由於
base64
是存在於 bundle.js 內,這樣子的做法會導致 JavaScript 異常的肥大,對於效能來說反而會下降,衡量並設置適當的大小才是正確的作法。
再次執行編譯指令:
通過 url-loader 的文件將轉成
base64
存在於 bundle.js 內:
1 2 3 4 5
|
webpack-demo/ │ ├─── dist/ │ │ │ └─── bundle.js # 圖片轉為 base64 存在於 JavaScript 檔案內
|
關於
base64
的實際應用將在下面補充,讓我們來做個總結:
file-loader 用以將靜態資源載入到 Webpack 內,並且解析資源的相互依賴關係,最後 output 到指定的位置,而 url-loader 用以將指定大小上限內的圖片資源轉換為 base64 格式,如遇到超過上限的資源,將 fallback 給 file-loader 做處理,兩者功能並沒有衝突,由於處理對象相同,導致很多人會搞混,通常兩個 loader 都是一起使用居多,並且直接設置 url-loader 即可
url-loader Options
可傳遞參數列表,以下為常用的參數配置:
limit:
Number
|
Boolean
|
String
限制可轉為 base64 的檔案大小上限,單位為 byte,默認為
underfined
fallback:
String
指定當文件大小超過 limit 限制時,需轉向的加載程序,默認為
fiel-loader
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
module.exports = { module: { rules: [ { test: /\.(png|jpg|gif)$/i, use: [ { loader: 'url-loader', options: { limit: 8192, fallback: require.resolve('file-loader'), }, }, ], }, ], }, };
|
可參考
file-loader Options
可傳遞參數列表,以下為常用的參數配置:
name:
String
|
Function
設置 output 時的文件名稱,相關參數可參考
Placeholders
,默認為
[contenthash].[ext]
outputPath:
String
|
Function
指定目標文件的公共路徑,在
mini-css-extract-plugin
文章有介紹到,默認為
underfined
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
module.exports = { module: { rules: [ { test: /\.(png|jpg|gif)$/i, use: [ { loader: 'file-loader', options: { name: 'img/[name].[ext]', publicPath: '../', }, }, ], }, ], }, };
|
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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
webpack-demo/ │ ├─── node_modules/ ├─── src/ │ │ │ └─── img/ │ │ │ ├─── banner.jpg # Size >= 10 KB │ └─── logo.jpg # Size < 10 KB │ │ │ └─── css/ │ │ │ └─── all.css # CSS 主檔案 │ │ │ └─── main.js # entry 入口檔案 │ ├─── index.html # 引入 bundle.js 與 main.css 測試用檔案 ├─── webpack.config.js # Webpack 配置檔案 ├─── package-lock.json └─── package.json
|
撰寫 CSS 範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
.w-100-h-100 { width: 100px; height: 100px; }
.bg-cover { background-position: center center; background-repeat: no-repeat; background-size: cover; }
.banner { background-image: url('../img/banner.jpg'); }
.logo { background-image: url('../img/logo.png'); }
|
配置
webpack.config.js
檔案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
const path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = { entry: './src/main.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'js/bundle.js', }, module: { rules: [ { test: /\.css$/i, use: [ { loader: MiniCssExtractPlugin.loader, options: { publicPath: '../', }, }, 'css-loader', ], }, { test: /\.(png|jpe?g|gif)$/i, use: [ { loader: 'url-loader', options: { name: 'img/[name].[ext]', limit: 10000, }, }, ], }, ], }, plugins: [ new MiniCssExtractPlugin({ filename: 'css/[name].css', }), ], };
|
這邊要特別注意!並不是 file-loader 與 url-loader 都要進行配置,直接配置 url-loader 就等同於配置了 file-loader,
limit
內的會交由 url-loader 處理,超過
limit
的資源則會 fallback 給 file-loader 進行處理。
Webpack 會自動解析 CSS 內的參考圖檔,將它抓出來以 require 的方式處理,除非有特定資源需要透過 file-loader 處理,不然不需要另外的 import 這些 CSS 所用的圖檔
entry 入口處 (
src/main.js
) 引入 CSS 檔案:
1
|
import './css/all.css';
|
至
package.json
新增編譯指令:
1 2 3 4 5
|
{ "scripts": { "build": "webpack --mode development" } }
|
執行編譯指令:
至
./index.html
引入打包而成的
bundle.js
與
main.css
檔案:
1 2 3 4 5 6 7 8 9 10 11
|
<head> <link rel="stylesheet" href="dist/css/main.css" /> </head> <body> <div class="banner w-100-h-100 bg-cover"></div> <div class="logo w-100-h-100 bg-cover"></div> <script src="dist/js/bundle.js"></script> </body>
|
查看結果:
從上面結果可以得知,logo.png 圖檔已被轉換成 base64 格式,而 banner.png 這張較大的圖檔,被 url-loader fallback 給 file-loader 處理,最後就只是在配置的指定位置生成而已。
Google Fonts
拉一些字體出來用,不僅可以增加網頁整體的質感,還可以擺脫傳統字體的呆板樣式。
而外部字體的載入方式有很多種,包含一般最為常見的 CSS link,或是使用
@import
方式載入字體,我個人是偏好使用
@font-face
來載入字體,將字體給下載下來,提供較為穩定的載入字體方法。
先前介紹了以 file-loader 或 url-loader 來處理圖片等靜態資源,此章節將介紹如何以 file-loader 處理
.ttf
、
.otf
等字體資源,讓我們直接開始吧!
請先至
Google Fonts
隨意下載字體,並放置在
src/font
內
1 2 3 4 5 6 7
|
webpack-demo/ │ ├─── src/ │ │ +│ └─── font/ +│ │ +│ └─── NotoSansTC-Regular.otf
|
以
@font-face
載入本地字體:
1 2 3 4 5 6 7 8 9
|
@font-face { font-family: 'NotoSansTC'; src: url('../font/NotoSansTC-Regular.otf') format('opentype'); }
p { font-family: 'NotoSansTC'; font-size: 40px; }
|
配置
webpack.config.js
檔案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
const path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = { entry: './src/main.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'js/bundle.js', }, module: { rules: [ { test: /\.css$/i, use: [ { loader: MiniCssExtractPlugin.loader, options: { publicPath: '../', }, }, 'css-loader', ], }, { test: /\.(woff|woff2|eot|ttf|otf|)$/, use: [ { loader: 'file-loader', options: { name: 'font/[name].[ext]', }, }, ], }, { test: /\.(png|jpe?g|gif)$/i, use: [ { loader: 'url-loader', options: { name: 'img/[name].[ext]', limit: 10000, }, }, ], }, ], }, plugins: [ new MiniCssExtractPlugin({ filename: 'css/[name].css', }), ], };
|
這邊要注意,如果你打算將圖片、文字打包後放置在同一個路徑下,可以不必另外寫一個 Regex 去處理,
上面這種寫法,主要是將圖片與文字放置在不同的資料夾
,千萬要記得,Webpack 會將 CSS 內的相關路徑參考語法轉換為
require
的方式進行處理,並不是說 file-loader 的配置只能在 url-loader 區塊內配置,Webpack 是以 Regex 配對相關的 use,千萬不要搞混了!
執行編譯:
此時
src
資料夾內的
font
也通通打包進來了,以下為打包後的
dist
資料夾專案結構:
1 2 3 4 5 6 7 8
|
webpack-demo/ │ ├─── dist/ │ │ │ └─── font/ │ │ │ └─── NotoSansTC-Regular.otf // 其他省略
|
觀察打包生成的 CSS 檔案:
1 2 3 4 5 6 7 8 9
|
@font-face { font-family: 'NotoSansTC'; src: url(../font/NotoSansTC-Regular.otf) format('opentype'); }
p { font-family: 'NotoSansTC'; font-size: 40px; }
|
從上面結果可以得知,CSS 內的
@font-face
連結也是正確的,直接打開網頁即可看到字體已被更改,此時我們打包字體的目的也就成功了。
有人可能會問,font 字體可以使用 url-loader 處理嗎?答案是可以的,但非常不建議這樣做,英文字體少說 150 KB 起跳,而中文字體則是 5MB 起跳,對於網頁的效能來說,會有非常大的影響,這也是之前提到的 url-loader 中 limit 選項需要自己去衡量的原因,一般來說 8KB 左右就是極限了,超過的檔案就都建議以 file-loader 進行處理,各位可以自己試試看。