載入器是一個匯出函式的 JavaScript 模組。載入器執行器 呼叫此函式,並將前一個載入器或資源檔案的結果傳遞給它。函式的 this
內容由 webpack 和 載入器執行器 填入一些有用的方法,讓載入器(在其他事物中)可以將其呼叫樣式變更為非同步,或取得查詢參數。
第一個載入器傳遞一個引數:資源檔案的內容。編譯器預期最後一個載入器的結果。結果應該是表示模組 JavaScript 原始碼的 String
或 Buffer
(轉換為字串)。也可以傳遞一個選用的 SourceMap 結果(作為 JSON 物件)。
可以在 同步模式 中傳回單一結果。對於多個結果,必須呼叫 this.callback()
。在 非同步模式 中,必須呼叫 this.async()
以指示 載入器執行器 應該等待非同步結果。它傳回 this.callback()
。然後載入器必須傳回 undefined
並呼叫該回呼。
/**
*
* @param {string|Buffer} content Content of the resource file
* @param {object} [map] SourceMap data consumable by https://github.com/mozilla/source-map
* @param {any} [meta] Meta data, could be anything
*/
function webpackLoader(content, map, meta) {
// code of your webpack loader
}
以下各節提供不同類型的載入器的一些基本範例。請注意,map
和 meta
參數是選用的,請參閱以下 this.callback
。
可以使用 return
或 this.callback
同步傳回轉換後的 content
sync-loader.js
module.exports = function (content, map, meta) {
return someSyncOperation(content);
};
this.callback
方法較為靈活,因為您可以傳遞多個參數,而不用只使用 content
。
sync-loader-with-multiple-results.js
module.exports = function (content, map, meta) {
this.callback(null, someSyncOperation(content), map, meta);
return; // always return undefined when calling callback()
};
對於非同步載入器,this.async
用於擷取 callback
函數
async-loader.js
module.exports = function (content, map, meta) {
var callback = this.async();
someAsyncOperation(content, function (err, result) {
if (err) return callback(err);
callback(null, result, map, meta);
});
};
async-loader-with-multiple-results.js
module.exports = function (content, map, meta) {
var callback = this.async();
someAsyncOperation(content, function (err, result, sourceMaps, meta) {
if (err) return callback(err);
callback(null, result, sourceMaps, meta);
});
};
預設情況下,資源檔案會轉換成 UTF-8 字串,並傳遞給載入器。透過將 raw
標記設定為 true
,載入器將會收到原始 Buffer
。每個載入器都可以將其結果傳遞為 String
或 Buffer
。編譯器會在載入器之間轉換它們。
raw-loader.js
module.exports = function (content) {
assert(content instanceof Buffer);
return someSyncOperation(content);
// return value can be a `Buffer` too
// This is also allowed if loader is not "raw"
};
module.exports.raw = true;
載入器總是從右到左呼叫。有些情況下,載入器只關心請求背後的元資料,而可以忽略前一個載入器的結果。載入器上的 pitch
方法在載入器實際執行之前(從右到左)從左到右呼叫。
對於 use
的下列組態
module.exports = {
//...
module: {
rules: [
{
//...
use: ['a-loader', 'b-loader', 'c-loader'],
},
],
},
};
會發生這些步驟
|- a-loader `pitch`
|- b-loader `pitch`
|- c-loader `pitch`
|- requested module is picked up as a dependency
|- c-loader normal execution
|- b-loader normal execution
|- a-loader normal execution
那麼,為什麼載入器可能會利用「投擲」階段?
首先,傳遞給 pitch
方法的 data
也會在執行階段以 this.data
顯示,且可用於擷取和分享循環中較早階段的資訊。
module.exports = function (content) {
return someSyncOperation(content, this.data.value);
};
module.exports.pitch = function (remainingRequest, precedingRequest, data) {
data.value = 42;
};
其次,如果載入器在 pitch
方法中傳遞結果,則處理程序會轉身並略過其餘載入器。在上述範例中,如果 b-loader
的 pitch
方法回傳某個項目
module.exports = function (content) {
return someSyncOperation(content);
};
module.exports.pitch = function (remainingRequest, precedingRequest, data) {
if (someCondition()) {
return (
'module.exports = require(' +
JSON.stringify('-!' + remainingRequest) +
');'
);
}
};
上述步驟會縮短為
|- a-loader `pitch`
|- b-loader `pitch` returns a module
|- a-loader normal execution
載入器內容表示指派給 this
屬性的載入器內部可用的屬性。
根據下列範例,使用此 require 呼叫
在 /abc/file.js
中
require('./loader1?xyz!loader2!./resource?rrr');
addContextDependency(directory: string)
將目錄新增為 loader 結果的依賴項。
addDependency(file: string)
dependency(file: string) // shortcut
將現有檔案新增為 loader 結果的依賴項,以便讓它們可被監控。例如,sass-loader
、less-loader
會使用此功能,以便在任何匯入的 css
檔案變更時重新編譯。
addMissingDependency(file: string)
將非現有檔案新增為 loader 結果的依賴項,以便讓它們可被監控。與 addDependency
類似,但會在編譯期間處理檔案的建立,然後再正確附加監控程式。
告知 loader-runner,loader 打算非同步呼叫回傳。傳回 this.callback
。
設定快取標記的函式
cacheable(flag = true: boolean)
預設情況下,loader 結果會標記為可快取。呼叫此方法並傳遞 false
,即可讓 loader 的結果不可快取。
可快取的 loader 在輸入和依賴項未變更時,必須有確定性的結果。這表示 loader 不應有 this.addDependency
指定以外的依賴項。
可同步或非同步呼叫的函式,用於傳回多個結果。預期的引數為
this.callback(
err: Error | null,
content: string | Buffer,
sourceMap?: SourceMap,
meta?: any
);
Error
或 null
string
或 Buffer
。如果呼叫此函數,您應傳回未定義以避免載入器結果不明確。
clearDependencies();
移除載入器結果的所有依賴項,甚至包括初始依賴項和其他載入器的依賴項。考慮使用 pitch
。
模組的目錄。可用作解析其他項目的背景。
在 範例 中:/abc
,因為 resource.js
在此目錄中
在 pitch 和一般階段之間共用的資料物件。
emitError(error: Error)
發出錯誤,也可以在輸出中顯示。
ERROR in ./src/lib.js (./src/loader.js!./src/lib.js)
Module Error (from ./src/loader.js):
Here is an Error!
@ ./src/index.js 1:0-25
emitFile(name: string, content: Buffer|string, sourceMap: {...})
發出檔案。這是 Webpack 專有的。
emitWarning(warning: Error)
發出警告,將會在輸出中顯示,如下所示
WARNING in ./src/lib.js (./src/loader.js!./src/lib.js)
Module Warning (from ./src/loader.js):
Here is a Warning!
@ ./src/index.js 1:0-25
檢查在產生的執行時期程式碼中可以使用哪種 ES 功能。
例如,
{
// The environment supports arrow functions ('() => { ... }').
"arrowFunction": true,
// The environment supports BigInt as literal (123n).
"bigIntLiteral": false,
// The environment supports const and let for variable declarations.
"const": true,
// The environment supports destructuring ('{ a, b } = obj').
"destructuring": true,
// The environment supports an async import() function to import EcmaScript modules.
"dynamicImport": false,
// The environment supports an async import() when creating a worker, only for web targets at the moment.
"dynamicImportInWorker": false,
// The environment supports 'for of' iteration ('for (const x of array) { ... }').
"forOf": true,
// The environment supports 'globalThis'.
"globalThis": true,
// The environment supports ECMAScript Module syntax to import ECMAScript modules (import ... from '...').
"module": false,
// The environment supports optional chaining ('obj?.a' or 'obj?.()').
"optionalChaining": true,
// The environment supports template literals.
"templateLiteral": true
}
存取 compilation
的 inputFileSystem
屬性。
萃取指定的載入器選項。選擇性地接受 JSON schema 作為引數。
getResolve(options: ResolveOptions): resolve
resolve(context: string, request: string, callback: function(err, result: string))
resolve(context: string, request: string): Promise<string>
建立類似於 this.resolve
的解析函數。
webpack resolve
選項 下的任何選項都是可能的。它們與已設定的 resolve
選項合併。請注意,"..."
可用於陣列中,以延伸 resolve
選項中的值,例如 { extensions: [".sass", "..."] }
。
options.dependencyType
是額外的選項。它允許我們指定相依性的類型,用於從 resolve
選項中解析 byDependency
。
解析作業的所有相依性會自動新增為目前模組的相依性。
載入器的 HMR 資訊。
module.exports = function (source) {
console.log(this.hot); // true if HMR is enabled via --hot flag or webpack configuration
return source;
};
this.importModule(request, options, [callback]): Promise
一個替代的輕量級解決方案,供子編譯器在建置時間編譯並執行請求。
request
:用於載入模組的請求字串選項
:layer
:指定放置/編譯此模組的層級publicPath
:用於建置模組的公開路徑callback
:一個選用的 Node.js 樣式回呼,傳回模組的匯出或 ESM 的命名空間物件。如果未提供回呼,importModule
將傳回 Promise。webpack.config.js
module.exports = {
module: {
rules: [
{
test: /stylesheet\.js$/i,
use: ['./a-pitching-loader.js'],
type: 'asset/source', // we set type to 'asset/source' as the loader will return a string
},
],
},
};
a-pitching-loader.js
exports.pitch = async function (remaining) {
const result = await this.importModule(
this.resourcePath + '.webpack[javascript/auto]' + '!=!' + remaining
);
return result.default || result;
};
src/stylesheet.js
import { green, red } from './colors.js';
export default `body { background: ${red}; color: ${green}; }`;
src/colors.js
export const red = '#f00';
export const green = '#0f0';
src/index.js
import stylesheet from './stylesheet.js';
// stylesheet will be a string `body { background: #f00; color: #0f0; }` at build time
您可能會注意到上述範例中的某些內容
!=!
語法來設定請求的 matchResource,亦即我們將使用 this.resourcePath + '.webpack[javascript/auto]'
與 module.rules
進行比對,而不是原始資源,.webpack[javascript/auto]
是 .webpack[type]
模式的偽延伸,我們使用它來指定在未指定其他模組類型時預設的 模組類型。它通常與 !=!
語法一起使用。請注意,上述範例是一個簡化的範例,您可以查看 webpack 儲存庫中的完整範例。
目前 loader 在 loaders 陣列中的索引。
在 範例 中:在 loader1 中:0
,在 loader2 中:1
loadModule(request: string, callback: function(err, source, sourceMap, module))
將給定的請求解析為模組,套用所有已設定的載入器,並使用已產生的來源、來源地圖和模組實例 (通常是 NormalModule
的實例) 回呼。如果您需要知道其他模組的原始碼才能產生結果,請使用此函數。
在載入器內容中,this.loadModule
預設使用 CommonJS 解析規則。在使用不同的語意之前,請使用適當的 dependencyType
(例如 'esm'
、'commonjs'
或自訂的) 搭配 this.getResolve
。
所有載入器的陣列。它可以在 pitch 階段寫入。
loaders = [{request: string, path: string, query: string, module: function}]
在 範例 中
[
{
request: '/abc/loader1.js?xyz',
path: '/abc/loader1.js',
query: '?xyz',
module: [Function],
},
{
request: '/abc/node_modules/loader2/index.js',
path: '/abc/node_modules/loader2/index.js',
query: '',
module: [Function],
},
];
讀取 webpack 執行的 mode
。
可能的值:'production'
、'development'
、'none'
options
物件設定,這將指向該物件。options
,但已使用查詢字串呼叫,這將會是一個以 ?
開頭的字串。已解析的請求字串。
在 範例 中:'/abc/loader1.js?xyz!/abc/node_modules/loader2/index.js!/abc/resource.js?rrr'
resolve(context: string, request: string, callback: function(err, result: string))
解析一個請求,就像一個 require 表達式。
context
必須是目錄的絕對路徑。此目錄用作解析的起始位置。request
是要解析的請求。通常使用相對請求,例如 ./relative
,或模組請求,例如 module/path
,但絕對路徑,例如 /some/path
,也可以作為請求。callback
是提供已解析路徑的正常 Node.js 風格的回呼函式。解析作業的所有相依性會自動新增為目前模組的相依性。
請求的資源部分,包括查詢。
在 範例 中:'/abc/resource.js?rrr'
資源檔案。
在 範例 中:'/abc/resource.js'
資源的查詢。
在 範例 中:'?rrr'
自 webpack 4 以來,以前的 this.options.context
提供為 this.rootContext
。
說明是否應產生原始碼對應。由於產生原始碼對應可能是一項昂貴的任務,因此您應該檢查是否實際要求原始碼對應。
編譯目標。從組態選項傳遞。
範例值:'web'
、'node'
存取 contextify
和 absolutify
工具程式。
contextify
:回傳一個新的請求字串,在可能的情況下避免絕對路徑。absolutify
:回傳一個新的請求字串,在可能的情況下使用絕對路徑。my-sync-loader.js
module.exports = function (content) {
this.utils.contextify(
this.context,
this.utils.absolutify(this.context, './index.js')
);
this.utils.absolutify(this.context, this.resourcePath);
// …
return content;
};
Loader API 版本。目前為 2
。這有助於提供向下相容性。使用版本,您可以指定自訂邏輯或因中斷變更而產生的替代方案。
當 webpack 編譯時,此布林值設為 true。
Loader 介面提供所有模組相關資訊。不過在少數情況下,您可能需要存取編譯器 API 本身。
因此,您應僅將它們作為最後的手段。使用它們會降低 loader 的可攜性。
存取 webpack 的目前 Compilation 物件。
存取 webpack 的目前 Compiler 物件。
布林旗標。在偵錯模式中設定。
從最後一個載入器傳遞。如果您要執行輸入參數作為模組,請考慮讀取此變數以取得捷徑(以提升效能)。
指示是否應將結果最小化。
傳遞值至下一個載入器。如果您知道如果將結果執行為模組時會匯出什麼,請在此處設定此值(作為唯一的元素陣列)。
駭入存取正在載入的模組物件。
您可以透過以下方式從載入器內部回報錯誤
throw
(或其他未捕捉的例外狀況)。在載入器執行期間擲回錯誤,將導致目前的模組編譯失敗。callback
(在非同步模式中)。傳遞錯誤至 callback 也會導致模組編譯失敗。例如
./src/index.js
require('./loader!./lib');
從載入器擲回錯誤
./src/loader.js
module.exports = function (source) {
throw new Error('This is a Fatal Error!');
};
或在非同步模式中傳遞錯誤至 callback
./src/loader.js
module.exports = function (source) {
const callback = this.async();
//...
callback(new Error('This is a Fatal Error!'), source);
};
模組將會像這樣打包
/***/ "./src/loader.js!./src/lib.js":
/*!************************************!*\
!*** ./src/loader.js!./src/lib.js ***!
\************************************/
/*! no static exports found */
/***/ (function(module, exports) {
throw new Error("Module build failed (from ./src/loader.js):\nError: This is a Fatal Error!\n at Object.module.exports (/workspace/src/loader.js:3:9)");
/***/ })
然後建置輸出也會顯示錯誤(類似於 this.emitError
)
ERROR in ./src/lib.js (./src/loader.js!./src/lib.js)
Module build failed (from ./src/loader.js):
Error: This is a Fatal Error!
at Object.module.exports (/workspace/src/loader.js:2:9)
@ ./src/index.js 1:0-25
如下方所示,不僅是錯誤訊息,還包含了哪些載入器和模組相關的詳細資訊
ERROR in ./src/lib.js
(./src/loader.js!./src/lib.js)
(from ./src/loader.js)
@ ./src/index.js 1:0-25
webpack v4 中引入了新的內嵌請求語法。在請求之前加上 <match-resource>!=!
將會設定此請求的 matchResource
。
設定 matchResource
時,它將會用於與 module.rules
進行比對,而不是原始資源。如果需要對資源套用進一步的載入器,或如果需要變更模組類型,這將很有用。它也會顯示在統計資料中,並用於比對 Rule.issuer
和 splitChunks
中的 test
。
範例
file.js
/* STYLE: body { background: red; } */
console.log('yep');
載入器可以將檔案轉換成下列檔案並使用 matchResource
套用使用者指定的 CSS 處理規則
file.js (由載入器轉換)
import './file.js.css!=!extract-style-loader/getStyles!./file.js';
console.log('yep');
這將新增一個對 extract-style-loader/getStyles!./file.js
的依賴項,並將結果視為 file.js.css
。因為 module.rules
有個規則符合 /\.css$/
,且將套用至這個依賴項。
載入器可以像這樣
extract-style-loader/index.js
const getStylesLoader = require.resolve('./getStyles');
module.exports = function (source) {
if (STYLES_REGEXP.test(source)) {
source = source.replace(STYLES_REGEXP, '');
return `import ${JSON.stringify(
this.utils.contextify(
this.context || this.rootContext,
`${this.resource}.css!=!${getStylesLoader}!${this.remainingRequest}`
)
)};${source}`;
}
return source;
};
extract-style-loader/getStyles.js
module.exports = function (source) {
const match = source.match(STYLES_REGEXP);
return match[0];
};
記錄 API 自 webpack 4.37 版本開始提供。當在 stats 設定
中啟用 logging
,和/或當 基礎架構記錄
啟用時,載入器可以記錄訊息,這些訊息將以各自的記錄器格式列印出來(stats、基礎架構)。
this.getLogger()
來記錄,這是 compilation.getLogger()
的捷徑,包含載入器路徑和已處理檔案。這類型的記錄會儲存在 Stats 中並適當地格式化。它可以由 webpack 使用者過濾和匯出。this.getLogger('name')
來取得一個具有子名稱的獨立記錄器。載入器路徑和已處理檔案仍會加入。this.getLogger ? this.getLogger() : console
,以在使用不支援 getLogger
方法的舊版 webpack 時提供後備。