構建多頁面應用——靜態資源的處理
在之前的系列文章中,我已經介紹了如何用webpack實現多頁面應用
的js,html,css的處理。今天就主要介紹如何處理靜態資源,在web開發中最常見的靜態資源就是圖片。
圖片的引用方式
而因為在web中,圖片有兩種主要的引入方式,第一種是<img src="...">
,第二種是backgorund-image: url(...)
。前者在html中使用,後者在css中使用。
web開發中的圖片處理
圖片常見的類型有jp(e)g,png,gif,包括現在普遍使用的svg以及webp。svg作為矢量圖形,有一定的使用場景,而webp作為未來web開發的趨勢,有一定的使用場景,比如:愛奇藝中的輪播圖(carousel)中就是用webp,但其他的見到的不多。
現在,web開發中使用最多的還是jpg和png,處理他們,在構建工具中使用url-loader
和file-loader
就好了,其中file-loader負責圖片的拷貝和輸出,並會給圖片名添加一個hash值。
說到這裏,很多人會想到字體圖標
。以前處理web頁面中的圖標(icon),使用圖片來處理,這樣會帶來一個性能問題就是http請求的增多,這樣會造成服務器的負載壓力,同時會帶來用戶體驗的問題,因為會出現頁面的局部空白和頁面重繪的問題,當然一種解決方案使雪碧圖(sprite),但是如果圖片過大怎麽解決,如何對圖片進行分解(大變小的問題),圖片的拼接比較困難,最要命的是在引用雪碧圖時要進行計算,除此之外就是如何對雪碧圖的組成圖片進行自定義的刪減,而使用字體圖標這些問題,都會得到一定程度的解決,當然在構建工具中可以使用webpack-spritesmith
當然,有些特殊的情況,需要使用base64
,這裏使用url-loader
即可。
將圖片處理為base64有使用場景,將圖片轉換為雪碧圖亦有使用場景,單獨的圖片處理也有使用場景(這些使用場景的圖片大小從左到右依次增大)。
這些場景在一個web項目中都會涉及到。
雖然使用字體圖標可以替代雪碧圖,因為字體圖標有更小的尺寸,更自由的操作手法(如:圖標顏色的自定義),但是一個DIY的web項目還是有些圖標還是需要雪碧圖。
但是,這裏有一個問題,如何在一個項目中同時使用base64,雪碧圖,字體圖標,單獨的圖片。
在構建中如何使用多種圖片處理方式
在構建多頁面應用中,如何解決呢?
字體圖標
處理字體圖標很簡單,如:iconfont(阿裏巴巴字體圖標庫),就像引用css那麽簡單。
base64
base64的處理,使用url-loader
。
雪碧圖
雪碧圖的處理,可使用webpack-spritesmith
這個插件
單獨的圖片
使用file-loader
,它負責拷貝url-loader
的處理結果,並輸出。
上面就是我們常見的圖片處理,如果要處理svg可以參考svg-url-loader
,如果要處理webp可以參考webp-loader
如何對圖片進行優化
對圖片進行優化,會帶來良好的用戶體驗。
熟悉圖片優化的都知道漸進式(progressive),可參考nuwen.net
jp(e)g可以進行連續性
處理,這樣可保證圖片數據請求回來多少,就渲染多少,是自上而下的渲染,也是有模糊到清晰的狀態。
png可以進行交叉
處理,這樣也可保證圖片數據請求回來多少,就渲染多少,它是整體的顯示,而且是又模糊狀態到清晰的狀態。
gif圖片一般使用小圖,如果是大圖會記號瀏覽器性能,還不如使用視頻,或者用css動畫來代替。我個人整理了一個css 動畫集,有需要的可以看一下。
在構建多頁面應用中,會使用到image-webpack-loader
來做優化處理。
其中,配置項options
中的mozjpeg
處理jp(e)g圖片,pngquant
處理png圖片,gifsicle
處理gif圖片,webp
處理webp圖片。
多頁面應用中的圖片處理
首先,看一下多頁面應用中的目錄結構圖:
./src
│ aboutUs.js
│ contactUs.js
│ css.js
│ index.js
│ recruitment.js
│
├─assets
│ │ favicon.jpg
│ │
│ ├─css
│ │ │ index.scss
│ │ │
│ │ ├─commons
│ │ │ ├─container
│ │ │ │ index.scss
│ │ │ │
│ │ │ ├─footer
│ │ │ │ index.scss
│ │ │ │
│ │ │ └─header
│ │ │ index.scss
│ │ │
│ │ ├─productus
│ │ │ index.scss
│ │ │ productus-sprite.scss
│ │ │
│ │ └─utils
│ │ btn.scss
│ │ form.scss
│ │ inital.scss
│ │ list.scss
│ │ modeal.scss
│ │ normalize.scss
│ │ pagination.scss
│ │ popover.scss
│ │ table.scss
│ │ text.scss
│ │ tooltip.scss
│ │
│ └─imgs
│ ├─base64
│ │ fe.jpg
│ │
│ ├─other
│ │ float.jpg
│ │ productus-sprite.png
│ │
│ └─sprites
│ └─productus
│ product-us_01.png
│ product-us_02.png
│ product-us_03.png
│ product-us_04.png
│ product-us_05.png
│ product-us_06.png
│ product-us_07.png
│ product-us_08.png
│ product-us_09.png
│ product-us_10.png
│ product-us_11.png
│ product-us_12.png
│
├─pages
│ │ recruitment.pug
│ │ template.pug
│ │
│ └─components
│ ├─commons
│ │ ├─container
│ │ │ index.pug
│ │ │
│ │ ├─footer
│ │ │ index.pug
│ │ │
│ │ └─header
│ │ index.pug
│ │
│ └─productus
│ index.pug
│
└─utils
load.js
跟以前的實例代碼相比,這次的文件目錄結構變化較大,這裏將要處理的所有文件模塊都放在了src
目錄下。
可能有人會問,為什麽要要將目錄分的這麽細,下面我就說一下為什麽這麽分。
-
aboutUs.js
,contactUs.js
,index.js
,recruitment.js
是四個路由頁面,要用到的js代碼,css.js
處理各個路由頁面公用的css代碼; - 靜態資源目錄(assets)下,存放web項目常用的靜態資源;
- 靜態資源目錄下的css目錄統一存放整個web項目所用到的css樣式。其中commons存放公用的css模塊,每個公用模塊有創建一個目錄存放該公用模塊可以使用到的css模塊(提醒,不要分的過於細),而其他的如
productus
存放產品模塊代碼,根據開發的需要可以創建其他的模塊目錄,目錄結構類似於commons
中的header
模塊,其中utils
放置自己總結的工具模塊代碼,如table
,form
等。然後,指定style-loader
,css-loader
等樣式相關的loader處理css樣式文件,這樣可以減少遍歷,縮短構建時間。 - 靜態資源目錄下的imgs目錄,用來存放整個項目中,用到的圖片。在這裏,分為
base64
,sprite
,ohter
等,為什麽要這樣分?如果分的話file-loader
這個webapck的loader會復制並導出imgs
目下所有的圖片,者在構建中並不是我們需要的,這樣會增加構建的時間。如果讓url-loader
處理base64
目錄下的圖片,file-loader
處理ohter
目錄下的圖片,webpack-spritesmith
處理sprite
目錄下的圖片,並將生成的圖片放到ohter
目錄下,用file-loader
進行二次處理。這樣做,webpack處理更精確,可以減少不必要的遍歷,極大地減少構建的時間,同樣方便對圖片的管理,特別是對於需要改變sprite
的圖片的管理。 - 在
imgs
目錄下創建base64
目錄,sprite
目錄,使用file-loader
指定處理ohter
目錄,是為了避免file-loader將所有的圖片都拷貝一份並導出到dist
輸出目錄中,因為與base64
相關的文件已經在css
樣式文件中了,再拷貝一份,已經沒有意義,而sprite
相關的文件會被webpack-spritesmith
插件先處理生成一個文件,所以再拷貝它們也沒有意義,還會讓構建速度更慢。 - 在
page
目錄下,放置所有的html代碼塊(這裏使用pug編譯器生成相應的html代碼塊),它的目錄分類和css
相類似,它們是一一對應的關系。
註意:iamge-webpack-loader
,要先對所有的圖片進行優化處理,然後再用其他loader處理。loader的執行順序,如果你是style-loader!css-loader!sass-loader"
使用,它是從右到左方向先後執行,如果你是在配置文件中的rules: [...]
數組中,它也是從右到左的方向執行,如果你將所有的loader規則有回車符號隔開,那麽它就是自下而上的執行。
一類特殊的圖片引用
針對<img src="...">
的圖片使用,ul-loader
是不會處理html中的img引用,現在處理這樣情況的loader或插件,也並沒有一個比較出名的。現在通用的做法就是將圖片拷貝一份到生成目錄中,copy-webpack-plugin
。參考配置代碼如下:
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, ‘assets/imgs/other/‘),
to: path.resolve(__dirname, ‘dist/assets/imgs/other/‘),
ignore: [‘.*‘]
}
]),
但這樣,會帶來另一個問題就是圖片的優化問題,如何使用 image-webpack-loader
?本來的目的是對項目中使用到的所有的圖片進行優化,而現在只能對base64
和sprite
目錄下的圖片進行優化處理。不過,不要慌,可以通過創建一個新的npm腳本命令(本是裏使用的是npm run img
)來對圖片進行壓縮處理,新建了一個目錄static
用來保存優化前的圖片,ohter
用來保存優化後的圖片。
首先,需要安裝imagemin
, imagemin-mozjpeg
, imagemin-optipng
, imagemin-gifsicle
:
yarn add imagemin imagemin-mozjpeg imagemin-optipng imagemin-gifsicle --dev
然後,在項目的根目錄添加一個優化圖片的文件optzing-img.js
,代碼如下:
const path = require(‘path‘)
const imagemin = require(‘imagemin‘);
const imageminMozjpeg = require(‘imagemin-mozjpeg‘);
const imageminOptipng = require(‘imagemin-optipng‘);
const imageminGifsicle = require(‘imagemin-gifsicle‘);
(async () => {
await imagemin(
[
path.resolve(__dirname, ‘src/assets/imgs/static/*.jpg‘),
path.resolve(__dirname, ‘src/assets/imgs/static/*.png‘),
path.resolve(__dirname, ‘src/assets/imgs/static/*.gif‘)
],
path.resolve(__dirname, ‘src/assets/imgs/other/‘),
{
use: [
imageminMozjpeg(),
imageminOptipng(),
imageminGifsicle()
]
}
);
console.log(‘圖片優化完成!‘);
})();
最後,在package.json
文件中添加如下的npm命令:
...
"scripts": {
...
"img": "node optzing-img.js"
},
...
在控制輸入npm run img
,然後按下回車鍵就可以得到你所需要的。
註:既然重新定義了圖片優化的npm腳本命令,那麽,是否需要去掉之前在webpack.config.js
中的image-webpakc-loader
,當然不需要。主要有兩個原因,一個是sprite雪碧圖
它是用幾張小圖片合成了一張大圖片,這張合成的圖片還需要優化;另一個是因為本項目對於存放圖片的目錄進行了細化。
字體
在web開發中,自定義的字體也是比較常見的,在webpack中它的處理和圖片類似,都是使用的 url-loader
和 file-loader
。參考代碼如下:
...
{
include: path.resolve(__dirname, ‘assets/fonts/‘),
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: [{
loader: ‘url-loader‘,
options: {
limit: 10000,
name: isDev ? ‘[name].[ext]‘ : ‘[name].[hash].[ext]‘,
outputPath: ‘assets/fonts/‘
}
}]
},
...
新創建了一個fonts
目錄又來存放項目開發過程中使用的字體。
源代碼
webpack4.x multi-page
此後,webpack構建多頁面應用系列文章的源代碼,都在這個github項目中,webpack3.x multi-page不再維護。
構建多頁面應用系列文章
- 構建多頁面應用
- 構建多頁面應用——單個頁面的處理
- 構建多頁面應用——模板
- 構建多頁面應用——靜態資源
來源:https://segmentfault.com/a/1190000017579965
構建多頁面應用——靜態資源的處理