ローダーは、関数をexportするJavaScriptモジュールです。loader runnerはこの関数を呼び出し、前のローダーの結果またはリソースファイルを渡します。関数のthis
コンテキストはwebpackとloader runnerによって、ローダーが(とりわけ)呼び出しスタイルを非同期に変更したり、クエリパラメータを取得したりできる便利なメソッドで埋められます。
最初のローダーには、リソースファイルの内容という1つの引数が渡されます。コンパイラは、最後のローダーからの結果を期待しています。結果は、モジュールのJavaScriptソースコードを表すString
またはBuffer
(文字列に変換されます)である必要があります。オプションで、SourceMapの結果(JSONオブジェクトとして)も渡すことができます。
単一の結果は、同期モードで返すことができます。複数の結果の場合、this.callback()
を呼び出す必要があります。非同期モードでは、loader runnerが非同期の結果を待機する必要があることを示すために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)
ローダー結果の依存関係としてディレクトリを追加します。
addDependency(file: string)
dependency(file: string) // shortcut
監視可能にするために、既存のファイルをローダー結果の依存関係として追加します。たとえば、sass-loader
、less-loader
は、インポートされたcss
ファイルが変更されるたびに再コンパイルするためにこれを使用します。
addMissingDependency(file: string)
監視可能にするために、存在しないファイルをローダー結果の依存関係として追加します。addDependency
に似ていますが、ウォッチャーが正しくアタッチされる前に、コンパイル中のファイルの作成を処理します。
loader-runnerに、ローダーが非同期でコールバックすることを通知します。this.callback
を返します。
キャッシュ可能フラグを設定する関数
cacheable(flag = true: boolean)
デフォルトでは、ローダーの結果はキャッシュ可能としてフラグが付けられます。このメソッドにfalse
を渡して呼び出すと、ローダーの結果がキャッシュ可能ではなくなります。
キャッシュ可能なローダーは、入力と依存関係が変更されていない場合、決定的な結果を持つ必要があります。つまり、ローダーは、this.addDependency
で指定されたもの以外の依存関係を持つべきではありません。
複数の結果を返すために同期または非同期で呼び出すことができる関数。予想される引数は次のとおりです
this.callback(
err: Error | null,
content: string | Buffer,
sourceMap?: SourceMap,
meta?: any
);
Error
またはnull
である必要がありますstring
またはBuffer
です。この関数が呼び出された場合は、あいまいなローダーの結果を避けるためにundefinedを返す必要があります。
clearDependencies();
ローダー結果のすべての依存関係(初期依存関係や他のローダーの依存関係も含む)を削除します。pitch
の使用を検討してください。
モジュールのディレクトリ。他のものを解決するためのコンテキストとして使用できます。
例では:resource.js
がこのディレクトリにあるため、/abc
ピッチフェーズと通常フェーズで共有されるデータオブジェクト。
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スキーマを引数として受け入れます。
getResolve(options: ResolveOptions): resolve
resolve(context: string, request: string, callback: function(err, result: string))
resolve(context: string, request: string): Promise<string>
this.resolve
と同様の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
: モジュールをロードするリクエスト文字列options
:layer
: このモジュールが配置/コンパイルされるレイヤーを指定します。publicPath
: ビルドされたモジュールに使用されるパブリックパスcallback
: モジュールのエクスポートまたはESMの名前空間オブジェクトを返すオプションのNode.jsスタイルのコールバック。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を設定します。つまり、元のリソースの代わりに、module.rules
と一致させるために、this.resourcePath + '.webpack[javascript/auto]'
を使用します。.webpack[javascript/auto]
は .webpack[type]
パターンの疑似拡張子です。他のモジュールタイプが指定されていない場合に、デフォルトのモジュールタイプを指定するために使用します。これは通常、!=!
構文と組み合わせて使用されます。上記の例は単純化されたものであることに注意してください。詳細な例はwebpackリポジトリのフルバージョンで確認できます。
現在のローダーのローダー配列におけるインデックス。
例では、loader1では 0
、loader2では 1
。
loadModule(request: string, callback: function(err, source, sourceMap, module))
指定されたリクエストをモジュールに解決し、設定されたすべてのローダーを適用し、生成されたソース、sourceMap、モジュールインスタンス(通常はNormalModule
のインスタンス)でコールバックします。結果を生成するために別のモジュールのソースコードを知る必要がある場合は、この関数を使用します。
ローダーコンテキストの this.loadModule
は、デフォルトで CommonJS の解決規則を使用します。異なるセマンティクスを使用する前に、適切な dependencyType
(例:'esm'
、'commonjs'
、またはカスタム)を指定して this.getResolve
を使用してください。
すべてのローダーの配列。ピッチフェーズでは書き込み可能です。
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;
};
ローダーAPIバージョン。 現在は 2
です。これは後方互換性を提供するのに役立ちます。バージョンを使用することで、カスタムロジックや破壊的な変更に対するフォールバックを指定できます。
これがwebpackによってコンパイルされると、このブール値はtrueに設定されます。
ローダーインターフェースはすべてのモジュール関連情報を提供します。ただし、まれに、コンパイラーAPI自体にアクセスする必要がある場合があります。
したがって、最終手段としてのみ使用する必要があります。これらを使用すると、ローダーの移植性が低下します。
webpackの現在のコンパイルオブジェクトへのアクセス。
webpackの現在のコンパイラーオブジェクトへのアクセス。
ブール値フラグ。デバッグモードの場合に設定されます。
最後のローダーから渡されます。入力引数をモジュールとして実行する場合は、ショートカット(パフォーマンスのため)としてこの変数を読み取ることを検討してください。
結果を最小化する必要があるかどうかを示します。
次のローダーに値を渡します。モジュールとして実行した場合の結果のエクスポートがわかっている場合は、ここにその値(単一要素の配列として)を設定します。
ロードされているモジュールオブジェクトへのハッキーなアクセス。
ローダー内からエラーを報告できます。
throw
(またはその他のキャッチされない例外) を使用する。ローダーの実行中にエラーをスローすると、現在のモジュールのコンパイルが失敗します。callback
(非同期モード) を使用する。コールバックにエラーを渡すと、モジュールのコンパイルも失敗します。例えば
./src/index.js
require('./loader!./lib');
ローダーからのエラーのスロー
./src/loader.js
module.exports = function (source) {
throw new Error('This is a Fatal Error!');
};
または非同期モードでコールバックにエラーを渡します
./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, インフラストラクチャ) で出力されるメッセージをログに記録できます。
compilation.getLogger()
のショートカットである this.getLogger()
をロギングに使用することを推奨します。この種のロギングは統計情報に保存され、適切にフォーマットされます。webpack ユーザーは、フィルタリングやエクスポートが可能です。this.getLogger('name')
を使用できます。ローダーのパスと処理されたファイルは依然として追加されます。this.getLogger ? this.getLogger() : console
を使用して、getLogger
メソッドをサポートしていない古い webpack バージョンが使用されている場合のフォールバックを提供できます。