加載圖片
使用file-loader
file-loader
可以把JavaScript和CSS中導(dǎo)入圖片的語句替換成正確的地址,并同時把文件輸出到對應(yīng)的位置。例如CSS源碼是這樣寫的:
#app {
background-image: url(./imgs/a.png);
}
被file-loader
轉(zhuǎn)換后輸出的CSS會變成這樣:
#app {
background-image: url(5556e1251a78c5afda9ee7dd06ad109b.png);
}
并且在輸出目錄dist
中也多出./imgs/a.png
對應(yīng)的圖片文件5556e1251a78c5afda9ee7dd06ad109b.png
硝岗,輸出的文件名是根據(jù)文件內(nèi)容的計算出的Hash值可都。
同理在JavaScript中導(dǎo)入圖片的源碼如下:
import imgB from './imgs/b.png';
window.document.getElementById('app').innerHTML = `
<img src="${imgB}"/>
`;
經(jīng)過file-loader
處理后輸出的JavaScript代碼如下:
module.exports = __webpack_require__.p + "0bcc1f8d385f78e1271ebfca50668429.png";
也就是說imgB
的值就是圖片對應(yīng)的URL地址胳岂。
在Webpack中使用file-loader
非常簡單高帖,相關(guān)配置如下:
module.exports = {
module: {
rules: [
{
test: /\.png$/,
use: ['file-loader']
}
]
}
};
使用 url-loader
url-loader 可以把文件的內(nèi)容經(jīng)過base64編碼后注入到JavaScript或者CSS中去。
例如CSS源碼是這樣寫的:
#app {
background-image: url(./imgs/a.png);
}
被url-loader
轉(zhuǎn)換后輸出的CSS會變成這樣:
#app {
background-image: url(data:image/png;base64,iVBORw01afer...); /* 結(jié)尾省略了剩下的 base64 編碼后的數(shù)據(jù) */
}
同理在JavaScript中效果也類似锦秒。
從上面的例子中可以看出url-loader
會把根據(jù)圖片內(nèi)容計算出的 base64 編碼的字符串直接注入到代碼中露泊,由于一般的圖片數(shù)據(jù)量巨大, 這會導(dǎo)致JavaScript旅择、CSS文件也跟著變大惭笑。 所以在使用url-loader
時一定要注意圖片體積不能太大,不然會導(dǎo)致JavaScript生真、CSS文件過大而帶來的網(wǎng)頁加載緩慢問題沉噩。
一般利用url-loader
把網(wǎng)頁需要用到的小圖片資源注入到代碼中去,以減少加載次數(shù)柱蟀。因為在HTTP/1協(xié)議中川蒙,每加載一個資源都需要建立一次HTTP鏈接, 為了一個很小的圖片而新建一次HTTP連接是不劃算的长已。
url-loader
考慮到了以上問題畜眨,并提供了一個方便的選擇limit
,該選項用于控制當(dāng)文件大小小于limit
時才使用url-loader
痰哨,否則使用fallback
選項中配置的loader
胶果。 相關(guān)Webpack配置如下:
module.exports = {
module: {
rules: [
{
test: /\.png$/,
use: [{
loader: 'url-loader',
options: {
// 30KB 以下的文件采用 url-loader
limit: 1024 * 30,
// 否則采用 file-loader,默認值就是 file-loader
fallback: 'file-loader',
}
}]
}
]
},
};
除此之外斤斧,你還可以做以下優(yōu)化:
- 通過 imagemin-webpack-plugin 壓縮圖片;
- 通過 webpack-spritesmith 插件制作雪碧圖霎烙。
以上加載圖片的方法同樣適用于其它二進制類型的資源,例如PDF智绸、SWF等等深滚。
加載 SVG
SVG 作為矢量圖的一種標準格式,已經(jīng)得到了各大瀏覽器的支持甘苍,它也成為了Web中矢量圖的代名詞。 在網(wǎng)頁中采用SVG代替位圖有如下好處:
- SVG相對于位圖更清晰烘豌,在任意縮放的情況下后不會破壞圖形的清晰度载庭,SVG能方便地解決高分辨率屏幕下圖像顯示不清楚的問題。
- 在圖形線條比較簡單的情況下廊佩,SVG文件的大小要小于位圖囚聚,在扁平化UI流行的今天,多數(shù)情況下SVG會更小标锄。
- 圖形相同的SVG比對應(yīng)的高清圖有更好的渲染性能顽铸。
- SVG采用和HTML一致的XML語法描述,靈活性很高料皇。
畫圖工具能導(dǎo)出一個個.svg
文件谓松,SVG的導(dǎo)入方法和圖片類似,既可以像下面這樣在CSS中直接使用:
body {
background-image: url(./svgs/activity.svg);
}
也可以在HTML中使用:
<img src="./svgs/activity.svg"/>
也就是說可以直接把SVG文件當(dāng)成一張圖片來使用践剂,方法和使用圖片時完全一樣鬼譬。 所以使用file-loader
和使用url-loader
對SVG來說同樣有效,只需要把Loader test
配置中的文件后綴改成.svg
逊脯,代碼如下:
module.exports = {
module: {
rules: [
{
test: /\.svg/,
use: ['file-loader']
}
]
},
};
由于SVG是文本格式的文件优质,除了以上兩種方法外還有其它方法,下面來一一說明男窟。
使用 raw-loader
raw-loader 可以把文本文件的內(nèi)容讀取出來盆赤,注入到JavaScript或CSS中去。
例如在JavaScript中這樣寫:
import svgContent from './svgs/alert.svg';
經(jīng)過raw-loader
處理后輸出的代碼如下:
module.exports = "<svg xmlns=\"http://www.w3.org/2000/svg\"... </svg>" // 末尾省略 SVG 內(nèi)容
也就是說 svgContent
的內(nèi)容就等于字符串形式的SVG歉眷,由于SVG 本身就是HTML元素牺六,在獲取到SVG內(nèi)容后,可以直接通過以下代碼將SVG插入到網(wǎng)頁中:
window.document.getElementById('app').innerHTML = svgContent;
使用raw-loader
時相關(guān)的Webpack配置如下:
module.exports = {
module: {
rules: [
{
test: /\.svg$/,
use: ['raw-loader']
}
]
}
};
由于raw-loader
會直接返回SVG的文本內(nèi)容汗捡,并且無法通過CSS去展示SVG的文本內(nèi)容淑际,因此采用本方法后無法在CSS中導(dǎo)入SVG。 也就是說在 CSS 中不可以出現(xiàn)background-image: url(./svgs/activity.svg)
這樣的代碼扇住,因為background-image: url(<svg>...</svg>)
是不合法的春缕。
使用 svg-inline-loader
svg-inline-loader 和上面提到的raw-loader
非常相似, 不同在于svg-inline-loader
會分析SVG的內(nèi)容艘蹋,去除其中不必要的部分代碼锄贼,以減少SVG的文件大小。
在使用畫圖工具如Adobe Illustrator女阀、Sketch制作SVG后宅荤,在導(dǎo)出時這些工具會生成對網(wǎng)頁運行來說不必要的代碼屑迂。 舉個例子,以下是Sketch導(dǎo)出的SVG的代碼:
<svg class="icon" verison="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
stroke="#000">
<circle cx="12" cy="12" r="10"/>
</svg>
被svg-inline-loader
處理后會精簡成如下:
<svg viewBox="0 0 24 24" stroke="#000"><circle cx="12" cy="12" r="10"/></svg>
也就是說svg-inline-loader
增加了對SVG的壓縮功能冯键。
使用svg-inline-loader
時相關(guān)的Webpack配置如下:
module.exports = {
module: {
rules: [
{
test: /\.svg$/,
use: ['svg-inline-loader']
}
]
}
};
加載 Source Map
由于在開發(fā)過程中經(jīng)常會使用新語言去開發(fā)項目惹盼,最后會把源碼轉(zhuǎn)換成能在瀏覽器中直接運行的 JavaScript 代碼。 這樣做雖能提升開發(fā)效率惫确,在調(diào)試代碼的過程中你會發(fā)現(xiàn)生成的代碼可讀性非常差手报,這給代碼調(diào)試帶來了不便。
Webpack支持為轉(zhuǎn)換生成的代碼輸出對應(yīng)的Source Map文件改化,以方便在瀏覽器中能通過源碼調(diào)試掩蛤。 控制Source Map輸出的Webpack 配置項是devtool
,它有很多選項所袁。
devtool | 含義 |
---|---|
空 | 不生成 Source Map |
eval |
每個 module 會封裝到 eval 里包裹起來執(zhí)行盏档,并且會在每個eval 語句的末尾追加注釋 //# sourceURL=webpack:///./main.js
|
source-map |
會額外生成一個單獨Source Map文件,并且會在JavaScript文件末尾追加 //# sourceMappingURL=bundle.js.map
|
hidden-source-map |
和source-map 類似燥爷,但不會在JavaScript文件末尾追加 //# sourceMappingURL=bundle.js.map
|
inline-source-map |
和 source-map 類似蜈亩,但不會額外生成一個單獨Source Map文件,而是把Source Map轉(zhuǎn)換成base64編碼內(nèi)嵌到JavaScript中 |
eval-source-map |
和 eval 類似前翎,但會把每個模塊的Source Map轉(zhuǎn)換成base64編碼內(nèi)嵌到eval 語句的末尾稚配,例如 //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW...
|
cheap-source-map |
和source-map 類似,但生成的Source Map文件中沒有列信息港华,因此生成速度更快 |
cheap-module-source-map |
和cheap-source-map 類似道川,但會包含Loader 生成的Source Map |
其實以上表格只是列舉了devtool
可能取值的一部分, 它的取值其實可以由source-map
立宜、eval
冒萄、inline
、hidden
橙数、cheap
尊流、module
這六個關(guān)鍵字隨意組合而成。 這六個關(guān)鍵字每個都代表一種特性灯帮,它們的含義分別是:
-
eval
:用eval
語句包裹需要安裝的模塊崖技; -
source-map
:生成獨立的Source Map文件; -
hidden
:不在JavaScript文件中指出Source Map文件所在钟哥,這樣瀏覽器就不會自動加載Source Map迎献; -
inline
:把生成的Source Map轉(zhuǎn)換成base64格式內(nèi)嵌在JavaScript文件中; -
cheap
:生成的Source Map中不會包含列信息腻贰,這樣計算量更小吁恍,輸出的Source Map文件更小;同時Loader
輸出的Source Map不會被采用践盼; -
module
:來自Loader
的Source Map被簡單處理成每行一個模塊鸦采;
該如何選擇
Devtool配置項提供的這么多選項看似簡單宾巍,但很多人搞不清楚它們之間的差別和應(yīng)用場景咕幻。
如果你不關(guān)心細節(jié)和性能,只是想在不出任何差錯的情況下調(diào)試源碼顶霞,可以直接設(shè)置成 source-map
肄程,但這樣會造成兩個問題:
-
source-map
模式下會輸出質(zhì)量最高最詳細的Source Map,這會造成構(gòu)建速度緩慢选浑,特別是在開發(fā)過程需要頻繁修改的時候會增加等待時間蓝厌; -
source-map
模式下會把 Source Map 暴露出去,如果構(gòu)建發(fā)布到線上的代碼的Source Map暴露出去就等于源碼被泄露古徒;
為了解決以上兩個問題拓提,可以這樣做:
- 在開發(fā)環(huán)境下把
devtool
設(shè)置成cheap-module-eval-source-map
,因為生成這種 Source Map 的速度最快隧膘,能加速構(gòu)建代态。由于在開發(fā)環(huán)境下不會做代碼壓縮,Source Map 中即使沒有列信息也不會影響斷點調(diào)試疹吃; - 在生產(chǎn)環(huán)境下把
devtool
設(shè)置成hidden-source-map
蹦疑,意思是生成最詳細的 Source Map,但不會把 Source Map 暴露出去萨驶。由于在生產(chǎn)環(huán)境下會做代碼壓縮歉摧,一個 JavaScript 文件只有一行,所以需要列信息腔呜。
在生產(chǎn)環(huán)境下通常不會把Source Map上傳到HTTP服務(wù)器讓用戶獲取,而是上傳到JavaScript錯誤收集系統(tǒng)核畴,在錯誤收集系統(tǒng)上根據(jù)Source Map和收集到的JavaScript運行錯誤堆棧計算出錯誤所在源碼的位置膝但。
不要在生產(chǎn)環(huán)境下使用inline
模式的Source Map膛檀, 因為這會使JavaScript文件變得很大,而且會泄露源碼咖刃。
加載現(xiàn)有的 Source Map
有些從Npm安裝的第三方模塊是采用ES6或者TypeScript編寫的,它們在發(fā)布時會同時帶上編譯出來的JavaScript文件和對應(yīng)的Source Map文件嚎杨,以方便你在使用它們出問題的時候調(diào)試它們;
默認情況下Webpack是不會去加載這些附加的Source Map文件的枫浙,Webpack只會在轉(zhuǎn)換過程中生成 Source Map刨肃。 為了讓W(xué)ebpack加載這些附加的Source Map文件,需要安裝 source-map-loader 真友。 使用方法如下:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
// 只加載你關(guān)心的目錄下的 Source Map,以提升構(gòu)建速度
include: [path.resolve(root, 'node_modules/some-components/')],
use: ['source-map-loader'],
// 要把source-map-loader的執(zhí)行順序放到最前面盔然,
// 如果在source-map-loader之前有Loader轉(zhuǎn)換了該 JavaScript文件桅打,會導(dǎo)致Source Map映射錯誤
enforce: 'pre'
}
]
}
};
由于source-map-loader
在加載Source Map時計算量很大,因此要避免讓該Loader
處理過多的文件愈案,不然會導(dǎo)致構(gòu)建速度緩慢挺尾。通常會采用include
去命中只關(guān)心的文件。
再安裝新引入的依賴:
npm i -D source-map-loader
重啟Webpack后站绪,你就能在瀏覽器中調(diào)試node_modules/some-components/
目錄下的源碼了遭铺。