原文地址javascript
webpack loaders 從上手到理解系列
還有這些:vue
url-loader
會將引入的文件進行編碼,生成 DataURL
,至關於把文件翻譯成了一串字符串,再把這個字符串打包到 JavaScript
。java
通常來講,咱們會發請求來獲取圖片或者字體文件。若是圖片文件較多時(好比一些 icon
),會頻繁發送請求來回請求屢次,這是沒有必要的。此時,咱們能夠考慮將這些較小的圖片放在本地,而後使用 url-loader
將這些圖片經過 base64
的方式引入代碼中。這樣就節省了請求次數,從而提升頁面性能。webpack
url-loader
npm install url-loader --save-dev
複製代碼
webapck
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {},
},
],
},
],
},
};
複製代碼
import
(或 require
)import logo from '../assets/image/logo.png';
console.log('logo的值: ', logo); // 打印一下看看 logo 是什麼
複製代碼
簡單三步就搞定了。git
webpack
複製代碼
執行 webpack
以後,dist
目錄只生成了一個 bundle.js
。和 file-loader
不一樣的是,沒有生成咱們引入的那個圖片。上文說過,url-loader
是將圖片轉換成一個 DataURL
,而後打包到 JavaScript
代碼中。github
那咱們就看看 bundle.js
是否有咱們須要的 DataURL
:web
// bundle.js
(function(module, exports) {
module.exports = "data:image/jpeg;base64.........."; // 省略無數行
})
複製代碼
咱們能夠看到這個模塊導出的是一個標準的 DataURL
。npm
一個標準的DataURL:
data:[<mediatype>][;base64],<data>
json
經過這個 DataURL
,咱們就能夠從本地加載這張圖片了,也就不用將圖片文件打包到 dist
目錄下。bash
使用 base64
來加載圖片也是有兩面性的:
因此咱們得有取捨,只對部分小 size
的圖片進行 base64
編碼,其它的大圖片仍是發請求吧。
url-loader
天然是已經作了這個事情,咱們只要經過簡單配置便可實現上述需求。
limit
的時候使用 fallback
的 loader
來處理文件loader
來處理大於 limit
的文件,默認值是 file-loader
咱們來試試設一個 limit
:
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1000, // 大於 1000 bytes 的文件都走 fallback
},
},
],
},
複製代碼
從新執行 webpack
,因爲咱們引入的 logo.png
大於 1000
,因此使用的是 file-loader
來處理這個文件。圖片被打包到 dist
目錄下,而且返回的值是它的地址:
(function(module, exports, __webpack_require__) {
module.exports = __webpack_require__.p + "dab1fd6b179f2dd87254d6e0f9f8efab.png";
}),
複製代碼
更多關於 file-loader
file-loader
的代碼也很少,就直接複製過來經過註釋講解了:
import { getOptions } from 'loader-utils'; // loader 工具包
import validateOptions from 'schema-utils'; // schema 工具包
import mime from 'mime';
import normalizeFallback from './utils/normalizeFallback'; // fallback loader
import schema from './options.json'; // options schema
// 定義一個是否轉換的函數
/* *@method shouldTransform *@param {Number|Boolean|String} limit 文件大小閾值 *@param {Number} size 文件實際大小 *@return {Boolean} 是否須要轉換 */
function shouldTransform(limit, size) {
if (typeof limit === 'boolean') {
return limit;
}
if (typeof limit === 'number' || typeof limit === 'string') {
return size <= parseInt(limit, 10);
}
return true;
}
export default function loader(src) {
// 獲取 webpack 配置裏的 options
const options = getOptions(this) || {};
// 校驗 options
validateOptions(schema, options, {
name: 'URL Loader',
baseDataPath: 'options',
});
// 判斷是否要轉換,若是要就進入,不要就往下走
// src 是一個 Buffer,因此能夠經過 src.length 獲取大小
if (shouldTransform(options.limit, src.length)) {
const file = this.resourcePath;
// 獲取文件MIME類型,默認值是從文件取,好比 "image/jpeg"
const mimetype = options.mimetype || mime.getType(file);
// 若是 src 不是 Buffer,就變成 Buffer
if (typeof src === 'string') {
src = Buffer.from(src);
}
// 構造 DataURL 並導出
return `module.exports = ${JSON.stringify( `data:${mimetype || ''};base64,${src.toString('base64')}` )}`;
}
// 判斷結果是不須要經過 url-loader 轉換成 DataURL,則使用 fallback 的 loader
const {
loader: fallbackLoader,
options: fallbackOptions,
} = normalizeFallback(options.fallback, options);
// 引入 fallback loader
const fallback = require(fallbackLoader);
// fallback loader 執行環境
const fallbackLoaderContext = Object.assign({}, this, {
query: fallbackOptions,
});
// 執行 fallback loader 來處理 src
return fallback.call(fallbackLoaderContext, src);
}
// 默認狀況下 webpack 對文件進行 UTF8 編碼,當 loader 須要處理二進制數據的時候,須要設置 raw 爲 true
export const raw = true;
複製代碼