多圖預警!!! 此篇博文共 5 張圖(託管在 GitHub
),國內使用者請移步>>>原文. 或者來我的小站哦
0. 課程原始碼和資料
本次課程的程式碼目錄(如下圖所示):
本節課會講述webpack4
中的圖片常用的基礎操作:
- 圖片處理 和
Base64
編碼 - 圖片壓縮
- 合成雪碧圖
1. 準備工作
如專案程式碼目錄展示的那樣,除了常見的app.js
作為入口檔案,我們將用到的 3 張圖片放在/src/assets/img/
目錄下,並在樣式檔案base.css
中引用這些圖片。
剩下的內容交給webpack
打包處理即可。樣式檔案和入口 js 檔案的程式碼分別如下所示:
/* base.css */
*, body {
margin: 0;
padding: 0;
}
.box {
height: 400px;
width: 400px;
border: 5px solid #000;
color: #000;
}
.box div {
width: 100px;
height: 100px;
float: left;
}
.box .ani1 {
background: url("./../assets/imgs/1.jpg") no-repeat;
}
.box .ani2 {
background: url("./../assets/imgs/2.jpg") no-repeat;
}
.box .ani3 {
background: url("./../assets/imgs/3.png") no-repeat;
}
// app.js
import "style-loader/lib/addStyles";
import "css-loader/lib/css-base";
import "./css/base.css";
在處理圖片和進行base64
編碼的時候,需要使用url-loader
。
在壓縮圖片的時候,要使用img-loader
外掛,並且針對不同的圖片型別啟用不同的子外掛。
而postcss-loader
和postcss-sprites
則用來合成雪碧圖,減少網路請求。
因此,在 npm 安裝完相關外掛後,package.json
的內容如下所示:
{
"devDependencies": {
"css-loader": "^1.0.0",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^1.1.11",
"imagemin": "^5.3.1",
"imagemin-pngquant": "^5.1.0",
"img-loader": "^3.0.0",
"postcss-loader": "^2.1.6",
"postcss-sprites": "^4.2.1",
"style-loader": "^0.21.0",
"url-loader": "^1.0.1",
"webpack": "^4.16.1"
}
}
同時,我們編寫如下index.html
(假設已經打包好了專案檔案,現在直接引入):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="./dist/app.min.css">
</head>
<body>
<div id="app">
<div class="box">
<div class="ani1"></div>
<div class="ani2"></div>
<div class="ani3"></div>
</div>
</div>
<script src="./dist/app.bundle.js"></script>
</body>
</html>
2. 圖片處理 和 Base64 編碼
2.1 webpack 配置
為了方便樣式提取,還是利用extract-text-webpack-plugin
來提取樣式檔案。
同時,在module.rules
選項中進行配置,以實現讓 loader 識別圖片字尾名,並且進行指定的處理操作。
程式碼如下:
// webpack.config.js
const path = require("path");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
let extractTextPlugin = new ExtractTextPlugin({
filename: "[name].min.css",
allChunks: false
});
module.exports = {
entry: {
app: "./src/app.js"
},
output: {
publicPath: __dirname + "/dist/",
path: path.resolve(__dirname, "dist"),
filename: "[name].bundle.js",
chunkFilename: "[name].chunk.js"
},
module: {
rules: [
{
test: /.css$/,
use: ExtractTextPlugin.extract({
fallback: {
loader: "style-loader"
},
use: [
{
loader: "css-loader"
}
]
})
},
{
test: /.(png|jpg|jpeg|gif)$/,
use: [
{
loader: "url-loader",
options: {
name: "[name]-[hash:5].min.[ext]",
limit: 20000, // size <= 20KB
publicPath: "static/",
outputPath: "static/"
}
}
]
}
]
},
plugins: [extractTextPlugin]
};
通過配置url-loader
的 limit 選項,可以根據圖片大小來決定是否進行base64
編碼。這次配置的是:小於 20kb 的圖片進行base64
編碼。
2.2 打包結果
之前提到過,在專案中引入了 3 張圖片,其中3.png
是小於 20kb 的圖片。在命令列中執行webpack
進行打包,size 小於 20kb 的圖片被編碼,只打包了 2 個 size 大於 20kb 的圖片檔案:
開啟瀏覽器的控制檯,我們的圖片已經被成功編碼:
3. 圖片壓縮
3.1 壓縮配置
圖片壓縮需要使用img-loader
,除此之外,針對不同的圖片型別,還要引用不同的外掛。比如,我們專案中使用的是 png 圖片,因此,需要引入imagemin-pngquant
,並且指定壓縮率。
我們只需要在上面的配置檔案中將下方程式碼:
// ...
{
test: /.(png|jpg|jpeg|gif)$/,
use: [
{
loader: "url-loader",
options: {
name: "[name]-[hash:5].min.[ext]",
limit: 20000, // size <= 20KB
publicPath: "static/",
outputPath: "static/"
}
}
]
}
// ...
替換為下方程式碼即可,因為執行順序問題,我們將 url-loader 的 limit 設定成 1kb,來防止壓縮後的 png 圖片被 base64 編碼:
// ...
{
test: /.(png|jpg|jpeg|gif)$/,
use: [
{
loader: "url-loader",
options: {
name: "[name]-[hash:5].min.[ext]",
limit: 1000, // size <= 1KB
publicPath: "static/",
outputPath: "static/"
}
},
// img-loader for zip img
{
loader: "img-loader",
options: {
plugins: [
require("imagemin-pngquant")({
quality: "80" // the quality of zip
})
]
}
}
]
}
// ...
3.2 打包結果
執行 webpack 打包,檢視打包結果:
是的,如你所見,10.5kb 大小的迅雷圖示,被壓縮到了 1.8kb。圖片資訊可以去 github 上檢視,在文章開頭有提及 github 地址。
3.3 遺留問題
並沒有解決jpg
格式圖片壓縮。根據img-loader
的官方文件,安裝了imagemin-mozjpeg
外掛。
但是這個外掛的最新版本是7.0.0
,然而配置後,webpack 啟動會用報錯。
檢視了 github 上的 issue,我將版本回退到6.0.0
。可以安裝,也可以配置執行,正常打包。但是打包後的 jpg 圖片大小並沒有變化,也就是說,並沒有被壓縮!!!
希望有大佬可以指點一下小生,萬分感謝
4. 合成雪碧圖
4.1 webpack 配置
在之前的基礎上,配置還是很簡單的,loader 的引入和環境變數都在註釋裡面了:
const path = require("path");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
let extractTextPlugin = new ExtractTextPlugin({
filename: "[name].min.css",
allChunks: false
});
/*********** sprites config ***************/
let spritesConfig = {
spritePath: "./dist/static"
};
/******************************************/
module.exports = {
entry: {
app: "./src/app.js"
},
output: {
publicPath: __dirname + "/dist/",
path: path.resolve(__dirname, "dist"),
filename: "[name].bundle.js",
chunkFilename: "[name].chunk.js"
},
module: {
rules: [
{
test: /.css$/,
use: ExtractTextPlugin.extract({
fallback: {
loader: "style-loader"
},
use: [
{
loader: "css-loader"
},
/*********** loader for sprites ***************/
{
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: [require("postcss-sprites")(spritesConfig)]
}
}
/*********************************************/
]
})
},
{
test: /.(png|jpg|jpeg|gif)$/,
use: [
{
loader: "url-loader",
options: {
name: "[name]-[hash:5].min.[ext]",
limit: 10000, // size <= 20KB
publicPath: "static/",
outputPath: "static/"
}
},
{
loader: "img-loader",
options: {
plugins: [
require("imagemin-pngquant")({
quality: "80"
})
]
}
}
]
}
]
},
plugins: [extractTextPlugin]
};
4.2 效果展示
按照我們的配置,打包好的雪碧圖被放入了/dist/static/
目錄下,如下圖所示:
4.3 雪碧圖的實際應用
雪碧圖是為了減少網路請求,所以被處理雪碧圖的圖片多為各式各樣的 logo 或者大小相等的小圖片。而對於大圖片,還是不推薦使用雪碧圖。
除此之外,雪碧圖要配合 css 程式碼進行定製化使用。要通過 css 程式碼在雪碧圖上精準定位需要的圖片(可以理解成從雪碧圖上裁取需要的圖片),更多可以百度或者 google。