CC 4.0 协议声明

本节内容派生于以下链接指向的内容 ,并遵守 CC BY 4.0 许可证的规定。

以下内容如果没有特殊声明,可以认为都是基于原内容的修改和删减后的结果。

示例

以下部分提供了不同类型 loader 的一些基本示例。请注意,mapmeta 可选参数,请参见下面的 this.callback

同步 Loader

returnthis.callback 都可以用来同步返回转换后的内容:

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; // 调用 callback() 时总是返回未定义的结果
};
INFO

出于技术和性能方面的考虑,Rspack 内部会将所有 loader 转换为异步 loader。

// ... 前面的内容保持不变 ...

异步 Loader

对于异步 Loader,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);
  });
};

ESM Loader

Rspack 支持 ESM 格式的 loader,你可以使用 ESM 语法编写 loader,通过 export default 导出 loader 函数。

在编写 ESM Loader 时,文件名需要以 .mjs 结尾,或者在最近的 package.json 中将 type 设置为 module

my-loader.mjs
export default function loader(content, map, meta) {
  // ...
}

如果需要设置 rawpitch 等选项,可以使用具名导出:

my-loader.mjs
export default function loader(content) {
  // ...
}

// 设置 raw loader
export const raw = true;

// 添加 pitch 函数
export function pitch(remainingRequest, precedingRequest, data) {
  // ...
}
TIP

ESM loader 和 CommonJS loader 的功能完全相同,只是使用了不同的模块语法。你可以根据项目需求选择使用哪种格式。

'Raw' Loader

默认情况下,资源文件会被转化为 UTF-8 字符串,然后传给 loader。通过设置 rawtrue,loader 可以接收原始的 Buffer。每一个 loader 都可以用 String 或者 Buffer 的形式传递它的处理结果。Compiler 将会把它们在 loader 之间相互转换。

module.exports = function (content) {
  assert(content instanceof Buffer);
  // ...
};
module.exports.raw = true;

Pitching loader

Loader 总是从右向左被调用。有些情况下,loader 只关心请求背后的元数据,可以忽略之前 loader 的结果。在 loader 真正执行之前(从右向左),loader 上的 pitch 方法会从左向右被调用。

对于以下使用的配置:

rspack.config.js
module.exports = {
  //...
  module: {
    rules: [
      {
        //...
        use: ['a-loader', 'b-loader', 'c-loader']      },
    ],
  },
};

会得到这些步骤:

|-a-loader `pitch |- b-loader `pitch `. |-c-loader `pitch` |- 所请求的模块被作为依赖收集起来 |- c-loader正常执行 |-b-loader正常执行 |- a-loader 正常执行

通常情况下,如果 loader 足够简单以至于只导出了 normal 阶段的钩子:

module.exports = function (source) {};

那么其 pitching 阶段将被跳过。

那么,"pitching" 阶段对于 loader 来说有哪些优势呢?

首先,传递给 pitch 方法的数据在执行阶段也暴露在 this.data 下,可以用来捕获和共享 loader 生命周期中早期的信息。

module.exports = function (content) {
  return someSyncOperation(content, this.data.value);
};

module.exports.pitch = function (remainRequest, precedingRequest, data) {
  data.value = 42;
};

第二,如果一个 loader 在 pitch 方法中提供了一个结果,整个 loader 链路就会翻转过来,跳过其余的 normal 阶段的 loader 。 在我们上面的例子中,如果 b-loaders 的 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`返回一个模块 |- a-loader 正常执行

一个实际应用的例子是 style-loader,它利用了第二个优势来处理请求的调度。 请访问 style-loader 了解详情。