ローダーインターフェース

ローダーは、関数を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);
  });
};

「Raw」ローダー

デフォルトでは、リソースファイルは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-loaderpitchメソッドが何かを返した場合

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');

this.addContextDependency

addContextDependency(directory: string)

ローダー結果の依存関係としてディレクトリを追加します。

this.addDependency

addDependency(file: string)
dependency(file: string) // shortcut

監視可能にするために、既存のファイルをローダー結果の依存関係として追加します。たとえば、sass-loaderless-loaderは、インポートされたcssファイルが変更されるたびに再コンパイルするためにこれを使用します。

this.addMissingDependency

addMissingDependency(file: string)

監視可能にするために、存在しないファイルをローダー結果の依存関係として追加します。addDependencyに似ていますが、ウォッチャーが正しくアタッチされる前に、コンパイル中のファイルの作成を処理します。

this.async

loader-runnerに、ローダーが非同期でコールバックすることを通知します。this.callbackを返します。

this.cacheable

キャッシュ可能フラグを設定する関数

cacheable(flag = true: boolean)

デフォルトでは、ローダーの結果はキャッシュ可能としてフラグが付けられます。このメソッドにfalseを渡して呼び出すと、ローダーの結果がキャッシュ可能ではなくなります。

キャッシュ可能なローダーは、入力と依存関係が変更されていない場合、決定的な結果を持つ必要があります。つまり、ローダーは、this.addDependencyで指定されたもの以外の依存関係を持つべきではありません。

this.callback

複数の結果を返すために同期または非同期で呼び出すことができる関数。予想される引数は次のとおりです

this.callback(
  err: Error | null,
  content: string | Buffer,
  sourceMap?: SourceMap,
  meta?: any
);
  1. 最初の引数は、Errorまたはnullである必要があります
  2. 2番目の引数は、stringまたはBufferです。
  3. オプション:3番目の引数は、このモジュールで解析可能なソースマップである必要があります。
  4. オプション:4番目のオプションは、webpackで無視され、何でもかまいません(例:一部のメタデータ)。

この関数が呼び出された場合は、あいまいなローダーの結果を避けるためにundefinedを返す必要があります。

this.clearDependencies

clearDependencies();

ローダー結果のすべての依存関係(初期依存関係や他のローダーの依存関係も含む)を削除します。pitchの使用を検討してください。

this.context

モジュールのディレクトリ。他のものを解決するためのコンテキストとして使用できます。

では:resource.jsがこのディレクトリにあるため、/abc

this.data

ピッチフェーズと通常フェーズで共有されるデータオブジェクト。

this.emitError

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

this.emitFile

emitFile(name: string, content: Buffer|string, sourceMap: {...})

ファイルを生成します。これはwebpack固有のものです。

this.emitWarning

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

this.environment

生成されたランタイムコードで使用できる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
}

this.fs

compilationinputFileSystemプロパティへのアクセス。

this.getOptions(schema)

指定されたローダーオプションを抽出します。オプションで、JSONスキーマを引数として受け入れます。

this.getResolve

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 を解決するために使用されます。

解決操作のすべての依存関係は、自動的に現在のモジュールの依存関係として追加されます。

this.hot

ローダーのHMRに関する情報。

module.exports = function (source) {
  console.log(this.hot); // true if HMR is enabled via --hot flag or webpack configuration
  return source;
};

this.importModule

5.32.0+

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

上記の例で何かに気づくかもしれません。

  1. ピッチングローダーがあります。
  2. そのピッチングローダーで、!=!構文を使用して、リクエストのmatchResourceを設定します。つまり、元のリソースの代わりに、module.rulesと一致させるために、this.resourcePath + '.webpack[javascript/auto]'を使用します。
  3. .webpack[javascript/auto].webpack[type] パターンの疑似拡張子です。他のモジュールタイプが指定されていない場合に、デフォルトのモジュールタイプを指定するために使用します。これは通常、!=!構文と組み合わせて使用されます。

上記の例は単純化されたものであることに注意してください。詳細な例はwebpackリポジトリのフルバージョンで確認できます。

this.loaderIndex

現在のローダーのローダー配列におけるインデックス。

では、loader1では 0、loader2では 1

this.loadModule

loadModule(request: string, callback: function(err, source, sourceMap, module))

指定されたリクエストをモジュールに解決し、設定されたすべてのローダーを適用し、生成されたソース、sourceMap、モジュールインスタンス(通常はNormalModuleのインスタンス)でコールバックします。結果を生成するために別のモジュールのソースコードを知る必要がある場合は、この関数を使用します。

ローダーコンテキストの this.loadModule は、デフォルトで CommonJS の解決規則を使用します。異なるセマンティクスを使用する前に、適切な dependencyType (例:'esm''commonjs'、またはカスタム)を指定して this.getResolve を使用してください。

this.loaders

すべてのローダーの配列。ピッチフェーズでは書き込み可能です。

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],
  },
];

this.mode

webpackがどのmodeで実行されているかを読み取ります。

可能な値: 'production''development''none'

this.query

  1. ローダーがoptionsオブジェクトで設定されている場合、これはそのオブジェクトを指します。
  2. ローダーにoptionsがないが、クエリ文字列で呼び出された場合、これは?で始まる文字列になります。

this.request

解決されたリクエスト文字列。

では: '/abc/loader1.js?xyz!/abc/node_modules/loader2/index.js!/abc/resource.js?rrr'

this.resolve

resolve(context: string, request: string, callback: function(err, result: string))

require式のようにリクエストを解決します。

  • context はディレクトリへの絶対パスである必要があります。このディレクトリは、解決の開始場所として使用されます。
  • request は解決されるリクエストです。通常、./relative のような相対リクエストや、module/path のようなモジュールリクエストが使用されますが、/some/path のような絶対パスもリクエストとして可能です。
  • callback は解決されたパスを与える通常のNode.jsスタイルのコールバック関数です。

解決操作のすべての依存関係は、自動的に現在のモジュールの依存関係として追加されます。

this.resource

クエリを含むリクエストのリソース部分。

では: '/abc/resource.js?rrr'

this.resourcePath

リソースファイル。

では: '/abc/resource.js'

this.resourceQuery

リソースのクエリ。

では: '?rrr'

this.rootContext

webpack 4以降、以前の this.options.contextthis.rootContext として提供されます。

this.sourceMap

ソースマップを生成する必要があるかどうかを示します。ソースマップの生成はコストのかかるタスクになる可能性があるため、実際にソースマップが要求されているかどうかを確認する必要があります。

this.target

コンパイルのターゲット。設定オプションから渡されます。

例の値: 'web', 'node'

this.utils

5.27.0+

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;
};

this.version

ローダーAPIバージョン。 現在は 2 です。これは後方互換性を提供するのに役立ちます。バージョンを使用することで、カスタムロジックや破壊的な変更に対するフォールバックを指定できます。

this.webpack

これがwebpackによってコンパイルされると、このブール値はtrueに設定されます。

Webpack固有のプロパティ

ローダーインターフェースはすべてのモジュール関連情報を提供します。ただし、まれに、コンパイラーAPI自体にアクセスする必要がある場合があります。

したがって、最終手段としてのみ使用する必要があります。これらを使用すると、ローダーの移植性が低下します。

this._compilation

webpackの現在のコンパイルオブジェクトへのアクセス。

this._compiler

webpackの現在のコンパイラーオブジェクトへのアクセス。

非推奨のコンテキストプロパティ

this.debug

ブール値フラグ。デバッグモードの場合に設定されます。

this.inputValue

最後のローダーから渡されます。入力引数をモジュールとして実行する場合は、ショートカット(パフォーマンスのため)としてこの変数を読み取ることを検討してください。

this.minimize

結果を最小化する必要があるかどうかを示します。

this.value

次のローダーに値を渡します。モジュールとして実行した場合の結果のエクスポートがわかっている場合は、ここにその値(単一要素の配列として)を設定します。

this._module

ロードされているモジュールオブジェクトへのハッキーなアクセス。

エラーレポート

ローダー内からエラーを報告できます。

  • this.emitErrorを使用する。モジュールのコンパイルを中断することなくエラーを報告します。
  • 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

インライン matchResource

webpack v4で新しいインラインリクエスト構文が導入されました。リクエストに<match-resource>!=! を接頭辞として付けると、このリクエストの matchResource が設定されます。

matchResource が設定されている場合、元のリソースの代わりに module.rules と照合するために使用されます。これは、リソースにさらにローダーを適用する必要がある場合や、モジュールタイプを変更する必要がある場合に役立ちます。また、統計情報に表示され、Rule.issuersplitChunkstest の照合にも使用されます。

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 バージョンが使用されている場合のフォールバックを提供できます。

12 貢献者

TheLarkInnjhnnstbroadleybyzyksokraEugeneHlushkojantimonsuperburritowizardofhogwartssnitin315chenxsanjamesgeorge007