Webpack實戰(zhàn)——加載資源

加載圖片

使用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)化:

以上加載圖片的方法同樣適用于其它二進制類型的資源,例如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冒萄、inlinehidden橙数、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/目錄下的源碼了遭铺。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市恢准,隨后出現(xiàn)的幾起案子魂挂,更是在濱河造成了極大的恐慌,老刑警劉巖顷歌,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锰蓬,死亡現(xiàn)場離奇詭異,居然都是意外死亡眯漩,警方通過查閱死者的電腦和手機芹扭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赦抖,“玉大人舱卡,你說我怎么就攤上這事《佑” “怎么了轮锥?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長要尔。 經(jīng)常有香客問我舍杜,道長,這世上最難降的妖魔是什么赵辕? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任既绩,我火速辦了婚禮,結(jié)果婚禮上还惠,老公的妹妹穿的比我還像新娘饲握。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布救欧。 她就那樣靜靜地躺著衰粹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪笆怠。 梳的紋絲不亂的頭發(fā)上铝耻,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天,我揣著相機與錄音骑疆,去河邊找鬼田篇。 笑死箍铭,一個胖子當(dāng)著我的面吹牛诈火,可吹牛的內(nèi)容都是我干的状答。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼拍摇,長吁一口氣:“原來是場噩夢啊……” “哼馆截!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蜡娶,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤窖张,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后宿接,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡梢卸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年低剔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姻锁。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡猜欺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涧黄,到底是詐尸還是另有隱情,我是刑警寧澤笋妥,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布窄潭,位于F島的核電站,受9級特大地震影響月帝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嚷辅,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一簸搞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧攘乒,春花似錦惋鹅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽爽雄。三九已至沐鼠,卻和暖如春叹谁,著一層夾襖步出監(jiān)牢的瞬間乘盖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工析苫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留穿扳,地道東北人。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓茫死,卻偏偏與公主長得像泽谨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子吧雹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容

  • 版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載冯凹。 webpack介紹和使用 一、webpack介紹 1宇姚、由來 ...
    it筱竹閱讀 11,070評論 0 21
  • webpack 是什么浑劳? 本質(zhì)上,webpack 是一個現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包器(mo...
    IT老馬閱讀 3,310評論 2 27
  • 學(xué)習(xí)流程 參考文檔:入門Webpack魔熏,看這篇就夠了Webpack for React 一. 簡單使用webpac...
    Jason_Zeng閱讀 3,123評論 2 16
  • 前端將大型項目分成一個個單獨的模塊,一般封裝好的每個模塊都會實現(xiàn)一個目的明確的完成的功能镶骗。如何處理這些模塊以及模塊...
    pixels閱讀 3,419評論 1 14
  • 讓世界因我更閃亮此蜈,明光 20161021 今天的誦讀是在大課間舉行的,因為吃過早飯后課代表忘了發(fā)晨誦作業(yè)裆赵,我們沒有...
    河南麥子的書寫閱讀 578評論 0 1