For AI agents: the complete documentation index is available at /zh/llms.txt, the full documentation bundle is available at /zh/llms-full.txt, and this page is available as Markdown at /zh/api/loader-api/context.md.
close
CC 4.0 协议

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

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

Loader 上下文

Loader 上下文表示 loader 内部可用的属性,这些属性在 loader 中通过 this 属性进行访问。

this.addBuildDependency()

  • 类型:
function addBuildDependency(file: string): void;

添加一个文件作为 loader 结果的构建依赖。当构建依赖发生变化时,Rspack 会使持久化缓存失效。

它适用于会影响 loader 行为或转换结果的文件,例如 loader 的配置文件。

loader.mjs
import path from 'node:path';

export default function loader(source) {
  this.addBuildDependency(
    path.resolve(this.rootContext, 'custom-loader.config.js'),
  );
  return source;
}
Tip

this.addBuildDependency() 不会将文件添加为 watch 依赖。如果文件变化时还应在 watch 模式下触发重新构建,请同时调用 this.addDependency()

this.addContextDependency()

  • 类型:
function addContextDependency(directory: string): void;

添加目录作为 loader 结果的依赖,使目录中文件的任何变化可以被监听到。

例如,添加 src/static 目录作为依赖,当目录中的文件发生变化时,会触发重新构建。

loader.mjs
import path from 'node:path';

export default function loader(source) {
  this.addContextDependency(path.resolve(this.rootContext, 'src/static'));
  return source;
}

this.addDependency()

  • 类型:
function addDependency(file: string): void;

添加一个文件作为 loader 结果的依赖,使它们的任何变化可以被监听到。例如,sass-loaderless-loader 就使用了这个技巧,当导入的样式文件发生变化时就会重新编译。

loader.mjs
import path from 'node:path';

export default function loader(source) {
  this.addDependency(path.resolve(this.rootContext, 'src/styles/foo.scss'));
  return source;
}

this.addMissingDependency()

  • 类型:
function addMissingDependency(file: string): void;

添加一个当前不存在的文件作为 loader 结果的依赖,使它们的创建和任何变化可以被监听到。例如,当该路径下新建了文件时,会触发重新构建。

loader.mjs
import path from 'node:path';

export default function loader(source) {
  this.addMissingDependency(
    path.resolve(this.rootContext, 'src/dynamic-file.json'),
  );
  return source;
}

this.async()

  • 类型: () => LoaderContextCallback

告诉 Rspack 这个 loader 将会异步被调用。返回值为 this.callback

查看 异步 loader 了解如何使用。

this.cacheable()

  • 类型:
function cacheable(flag: boolean = true): void;

默认情况下,当前模块经过整条 loader 链生成的最终构建结果可以被缓存。调用 this.cacheable(false) 会将该结果标记为不可缓存。

设置后,后续 loader 即使调用 this.cacheable(true)this.cacheable() 也无法重新启用缓存。只有 this.clearDependencies() 会重置这个状态。

loader.mjs
export default function loader(source) {
  this.cacheable(false);
  return source;
}

this.callback()

  • 类型:
interface AdditionalData {
  [index: string]: any;
}

function callback(
  err?: Error | null,
  content?: string | Buffer,
  sourceMap?: string | Rspack.RawSourceMap,
  additionalData?: AdditionalData,
): void;

调用 this.callback() 返回 loader 的处理结果,同步或异步 loader 均可使用。各参数的含义如下:

  1. err:loader 执行失败时传入 Error;执行成功时传入 nullundefined
  2. content:转换后的模块内容,可以是 stringBuffer。只报告错误时可以省略。
  3. sourceMap:可选的 source map,可以是 stringRspack.RawSourceMap
  4. additionalData:可选的附加数据。Rspack 会将它作为第三个参数传给 loader 链中的下一个 loader。

查看 同步 loader 了解如何使用。

Warning

当这个函数被调用时,你应该返回 undefined 以避免 loader 结果的歧义。

contentsourceMapadditionalData 会传递给 loader 链中的下一个 loader。

this.clearDependencies()

  • 类型:
function clearDependencies(): void;

清除 loader 链中已收集的所有文件依赖上下文依赖缺失依赖,但不会清除 build dependencies。它还会将 cacheable 重置为 true,因此此前任何 loader 调用 this.cacheable(false) 产生的设置都会失效。

只有在当前 loader 会为最终结果重新注册全部所需依赖时,才应调用此方法。

this.context

  • 类型: string | null

当前被处理的模块所在的目录路径,会随着每个被处理的模块的位置而变化。

例如,如果 loader 处理的是 /project/src/components/Button.js,那么 this.context 的值就是 /project/src/components

loader.mjs
export default function loader(source) {
  console.log(this.context); // '/project/src/components'
  return source;
}

如果正在处理的模块没有资源路径,this.context 的值为 null

this.loaderIndex

  • 类型: number

当前 loader 在 loaders 数组中的索引。

this.loaders

  • 类型: LoaderObject[]

this.loaders 包含应用于当前模块的所有 loader。每一项都提供解析后的 requestpathqueryoptions 等信息。

在 pitch 阶段可以修改这个数组,以调整 loader 链。可通过 this.loaderIndex 定位当前 loader。

loader.mjs
export function pitch() {
  const currentLoader = this.loaders[this.loaderIndex];
  console.log(currentLoader.request);
}

this.data

  • 类型: unknown

用于在 pitch 和 normal 阶段之间共享数据。

this.dependency()

  • 类型:
function dependency(file: string): void;

this.addDependency() 的别名。

this.emitError()

  • 类型:
function emitError(error: Error): void;

发出一个错误。

与在 loader 中 throwthis.callback(err) 不同,它不会将当前模块标记为编译失败,只会向 Rspack 的 Compilation 添加一个错误,并在本次编译结束后显示在命令行中。

this.emitWarning()

  • 类型:
function emitWarning(warning: Error): void;

发出一个警告。

this.experiments.emitDiagnostic()

Stability: Experimental
  • 类型:
interface DiagnosticLocation {
  /** Text for highlighting the location */
  text?: string;
  /** 1-based line */
  line: number;
  /** 0-based column in bytes */
  column: number;
  /** Length in bytes */
  length: number;
}

interface Diagnostic {
  message: string;
  help?: string;
  sourceCode?: string;
  /**
   * 源代码的位置信息
   * 如果未提供 `sourceCode`,则位置信息将被省略
   */
  location?: DiagnosticLocation;
  /**
   * 可选展示的文件名
   * 如果设置,它将成为 stats 中的 `StatsError.file` 值
   */
  file?: string;
  severity: 'error' | 'warning';
}

function emitDiagnostic(diagnostic: Diagnostic): void;

格式化并输出错误或警告诊断信息,支持显示模块路径、源代码片段和行列号。

Info

与在 loader 中 throwthis.callback(err) 不同,它不会将当前模块标记为编译失败,而是根据 severity 向 Rspack 的 Compilation 添加错误或警告,并在本次编译结束后显示在命令行中。

  • 基础示例:

只提供 messageseverity 时,仅会输出基本的诊断信息。

loader.mjs
/** @type {import("@rspack/core").LoaderDefinition} */
export default function () {
  this.experiments.emitDiagnostic({
    message: '`React` is not defined',
    severity: 'error',
  });
  this.experiments.emitDiagnostic({
    message: '`React` is not defined',
    severity: 'warning',
  });
  return '';
}

将会打印:

ERROR in (./loader.mjs!)
  × ModuleError: `React` is not defined

WARNING in (./loader.mjs!)
  ⚠ ModuleWarning: `React` is not defined
  • 打印代码片段:
loader.mjs
/** @type {import("@rspack/core").LoaderDefinition} */
export default function () {
  this.experiments.emitDiagnostic({
    message: '`React` is not defined',
    severity: 'error',
    sourceCode: `<div></div>`,
    location: {
      line: 1,
      column: 1,
      length: 3,
    },
    file: './some-file.js',
  });
  return '';
}

将会打印:

ERROR in ./some-file.js
 ./file.js 1:1-4
  × ModuleError: `React` is not defined
   ╭────
 1 │ <div></div>
   ·  ───
   ╰────

其中 ./some-file.js 为传入的 file 字段。

this.emitFile()

  • 类型:
function emitFile(
  name: string,
  content: string | Buffer,
  sourceMap?: string,
  assetInfo?: AssetInfo,
): void;

输出一个新文件。这个方法允许你在 loader 执行过程中创建新的文件。

  • 基础示例:
loader.mjs
export default function loader(source) {
  // 输出一个新文件,该文件将在产物目录中输出为 `foo.js`
  this.emitFile('foo.js', 'console.log("Hello, world!");');
  return source;
}
  • 带有 asset info 的示例:
loader.mjs
export default function loader(source) {
  this.emitFile(
    'foo.js',
    'console.log("Hello, world!");',
    undefined, // no sourcemap
    {
      sourceFilename: this.resourcePath,
    },
  );

  return source;
}

this.fs

  • 类型: InputFileSystem

访问 compilation 对象的 inputFileSystem 属性。

this.getContextDependencies()

  • 类型:
function getContextDependencies(): string[];

返回 loader 当前作为上下文依赖监听的所有目录,其中包括通过 this.addContextDependency() 添加的目录。

loader.mjs
export default function loader(source) {
  const contextDependencies = this.getContextDependencies();
  console.log(contextDependencies);

  return source;
}

this.getDependencies()

  • 类型:
function getDependencies(): string[];

返回 loader 当前作为依赖监听的所有文件,其中包括通过 this.addDependency()this.dependency() 添加的文件。

loader.mjs
export default function loader(source) {
  const dependencies = this.getDependencies();
  console.log(dependencies);

  return source;
}

this.getMissingDependencies()

  • 类型:
function getMissingDependencies(): string[];

返回 loader 当前监听的所有尚不存在的文件路径,其中包括通过 this.addMissingDependency() 添加的路径。当这些文件被创建时,可能会触发重新构建。

loader.mjs
export default function loader(source) {
  const missingDependencies = this.getMissingDependencies();
  console.log(missingDependencies);

  return source;
}

这三个方法都会返回一个新数组。修改返回的数组不会影响 loader 已注册的依赖。如需清空这三类依赖列表,请使用 this.clearDependencies()

this.getOptions()

  • 类型:
function getOptions(schema?: any): OptionsType;

获取 loader 的使用者传入的选项。

例如:

rspack.config.mjs
export default {
  module: {
    rules: [
      {
        test: /\.txt$/,
        use: {
          loader: './my-loader.mjs',
          options: {
            foo: 'bar',
          },
        },
      },
    ],
  },
};

my-loader.mjs 中获取传入的选项:

my-loader.mjs
export default function myLoader(source) {
  const options = this.getOptions();
  console.log(options); // { foo: 'bar' }
  return source;
}
Tip

当 loader 通过查询字符串配置时,例如 loader: './my-loader?s=foo+bar'this.getOptions() 会使用 Node.js 的 querystring.parse() 解析该字符串。这意味着字面量 + 会被解码为空格,因此结果会是 { s: 'foo bar' }

如果你需要字面量加号,请将 + 编码为 %2B,或者优先在规则里使用 options 对象。若你需要读取原始查询字符串,请使用 this.query

在 TypeScript 中,你可以通过 LoaderContext 的泛型来设置 options 的类型。

my-loader.ts
import type { LoaderContext } from '@rspack/core';

type MyLoaderOptions = {
  foo: string;
};

export default function myLoader(
  this: LoaderContext<MyLoaderOptions>,
  source: string,
) {
  const options = this.getOptions();
  console.log(options); // { foo: 'bar' }
  return source;
}
Tip

参数 schema 是可选的,在 Rspack 中不会被使用。

为了提供最佳性能,Rspack 不会执行 schema 验证。如果你的 loader 需要 schema 验证,请自行调用 schema-utils 或其他 schema 验证库。

this.getResolve()

  • 类型:
type ResolveFunction = {
  (
    context: string,
    request: string,
    callback: (
      err: Error | null,
      result?: string | false,
      resolveRequest?: ResolveRequest,
    ) => void,
  ): void;
  (context: string, request: string): Promise<string | false | undefined>;
};

function getResolve(options?: ResolveOptions): ResolveFunction;

创建一个类似于 this.resolve() 的解析函数。可以通过 options 自定义解析行为;省略时使用不带额外选项的普通解析器。

返回的解析函数同时支持回调和 Promise 两种调用方式。不传回调函数时,它会返回 Promise。

loader.mjs
export default async function loader(source) {
  const resolve = this.getResolve({
    extensions: ['.js', '.json'],
  });
  const result = await resolve(this.context, './dependency');

  console.log(result);
  return source;
}

this.hot

  • 类型: boolean

是否启用了 HMR。

loader.mjs
export default function (source) {
  console.log(this.hot); // true if HMR is enabled
  return source;
}

this.importModule()

  • 类型:
interface ImportModuleOptions {
  /**
   * 指定模块的 layer
   */
  layer?: string;
  /**
   * 构建模块时使用的 public path
   */
  publicPath?: PublicPath;
  /**
   * 目标 base uri
   */
  baseUri?: string;
}

// 传入回调函数
function importModule<T = any>(
  request: string,
  options: ImportModuleOptions | undefined,
  callback: (err?: null | Error, exports?: T) => any,
): void;
// 不传入回调函数时,返回 Promise
function importModule<T = any>(
  request: string,
  options?: ImportModuleOptions,
): Promise<T>;

在构建过程中编译和执行一个模块。这是 child compiler 的轻量级替代方案。

在没有提供回调函数时,importModule 会返回一个 Promise。

loader.mjs
import path from 'node:path';

export default async function loader(source) {
  const modulePath = path.resolve(this.rootContext, 'some-module.ts');
  const moduleExports = await this.importModule(modulePath, {
    // 可选参数
  });

  const result = someProcessing(source, moduleExports);
  return result;
}

或者你可以传递一个回调函数给它。

loader.mjs
import path from 'node:path';

export default function loader(source) {
  const callback = this.async();
  const modulePath = path.resolve(this.rootContext, 'some-module.ts');

  this.importModule(
    modulePath,
    // 可选参数
    undefined,
    (err, moduleExports) => {
      if (err) {
        return callback(err);
      }

      const result = someProcessing(source, moduleExports);
      callback(null, result);
    },
  );
}

this.query

  • 类型: string | OptionsType

该值取决于 loader 的配置方式:

  • 如果当前 loader 配置了一个选项对象,this.query 将指向这个对象。
  • 如果当前 loader 没有选项,但是通过查询字符串调用,这将是一个以 ? 开头的字符串。

this.getOptions() 不同,查询字符串形式在这里不会被解析。例如,loader: './my-loader?s=foo+bar' 时,this.query === '?s=foo+bar'

this.remainingRequest

  • 类型: string

this.remainingRequest 由 loader 链中位于当前 loader 之后的所有 loader 和当前资源组成,各部分使用 ! 连接。

例如,假设 loader 链为:

/path/to/loader1.mjs!/path/to/loader2.mjs!/path/to/resource.js

执行到 loader1.mjs 时,this.remainingRequest 为:

/path/to/loader2.mjs!/path/to/resource.js

它通常用于构造内联请求,避免再次执行当前 loader。可以参考 Inline matchResource 中的示例。

this.currentRequest

  • 类型: string

this.currentRequest 由当前 loader、loader 链中位于它之后的所有 loader 和当前资源组成,各部分使用 ! 连接。

例如,假设 loader 链为:

/path/to/loader1.mjs!/path/to/loader2.mjs!/path/to/resource.js

执行到 loader2.mjs 时,this.currentRequest 为:

/path/to/loader2.mjs!/path/to/resource.js

this.previousRequest

  • 类型: string

this.previousRequest 由 loader 链中位于当前 loader 之前的所有 loader 组成,各部分使用 ! 连接。它不包含当前资源。

例如,假设 loader 链为:

/path/to/loader1.mjs!/path/to/loader2.mjs!/path/to/resource.js

执行到 loader2.mjs 时,this.previousRequest 为:

/path/to/loader1.mjs

this.request

  • 类型: string

完整的请求字符串,由所有 loader 和当前资源组成,各部分使用 ! 连接。

例如,如果 resource.jsloader1.mjsloader2.mjs 处理,那么 this.request 的值为 /path/to/loader1.mjs!/path/to/loader2.mjs!/path/to/resource.js

this.resolve()

  • 类型:
function resolve(
  context: string,
  request: string,
  callback: (
    err: Error | null,
    result?: string | false,
    resolveRequest?: ResolveRequest,
  ) => void,
): void;

解析一个模块标识符。

  • context 必须是一个目录的绝对路径。此目录用作解析的起始位置。
  • request 是要被解析的模块标识符。
  • callback 会接收错误、解析后的路径(请求被忽略时为 false),以及可选的解析详情。

this.mode

  • 类型: Mode | undefined

mode 配置的值,可能为 'production''development''none'undefined。如果没有配置 modethis.modeundefined,但 Rspack 仍会应用偏向生产环境的默认配置。

loader.mjs
export default function loader(source) {
  console.log(this.mode); // 'production'、'development'、'none' 或 undefined
  return source;
}

this.target

  • 类型: Target | undefined

默认情况下,Rspack 会根据 target 所描述的运行环境能力,为 loader 生成一个更简单的目标值。能够判断目标环境时,该值会是 'web''node''nwjs''electron-main' 等。因此,this.target 不一定与原始的 target 配置完全相同。

loader.mjs
export default function loader(source) {
  console.log(this.target); // 'web' or other values
  return source;
}

this.environment

  • 类型: Environment

描述目标运行环境支持的能力。默认情况下,该值是最终生效的 output.environment:Rspack 会根据 target 判断目标环境支持的能力,再应用 output.environment 中的显式配置。

loader 可以根据这些信息选择输出环境支持的语法。

loader.mjs
export default function loader(source) {
  if (this.environment.optionalChaining) {
    console.log('Optional chaining is supported');
  }

  return source;
}

this.utils

  • 类型:
type Utils = {
  absolutify: (context: string, request: string) => string;
  contextify: (context: string, request: string) => string;
  createHash: (algorithm?: string) => Hash;
};

访问以下 utils:

  • absolutify: 返回一个新的 request 字符串,尽可能使用绝对路径。
  • contextify: 返回一个新的 request 字符串,尽可能避免使用绝对路径。
  • createHash: 基于提供的哈希函数返回一个新的 Hash 对象。
loader.mjs
export default function (content) {
  this.utils.contextify(
    this.context,
    this.utils.absolutify(this.context, './index.js'),
  );

  this.utils.absolutify(this.context, this.resourcePath);

  const mainHash = this.utils.createHash(
    this._compilation.outputOptions.hashFunction,
  );
  mainHash.update(content);
  mainHash.digest('hex');

  return content;
}

this.resource

  • 类型: string

当前模块的路径字符串。比如 '/abc/resource.js?query#hash'

loader.mjs
export default function loader(source) {
  console.log(this.resource); // '/abc/resource.js?query#hash'
  return source;
}

this.resourcePath

  • 类型: string

当前模块的路径字符串,不包括 query 和 fragment 参数。比如 '/abc/resource.js?query#hash' 中的 '/abc/resource.js'

loader.mjs
export default function loader(source) {
  console.log(this.resourcePath); // '/abc/resource.js'
  return source;
}

this.resourceQuery

  • 类型: string

当前模块的路径字符串的 query 参数。比如 '/abc/resource.js?query#hash' 中的 '?query'

loader.mjs
export default function loader(source) {
  console.log(this.resourceQuery); // '?query'
  return source;
}

this.resourceFragment

  • 类型: string

当前模块的路径字符串的 fragment 参数。比如 '/abc/resource.js?query#hash' 中的 '#hash'

loader.mjs
export default function loader(source) {
  console.log(this.resourceFragment); // '#hash'
  return source;
}

this.rootContext

  • 类型: string

Rspack config 中通过 context 配置的基础路径。

loader.mjs
export default function loader(source) {
  console.log(this.rootContext); // /path/to/project
  return source;
}

this.sourceMap

  • 类型: boolean

是否应该生成 source map。

由于生成 source map 通常是一项耗费资源的任务,你应该检查是否需要 source map。

详见 处理 Source Map

this.getLogger()

  • 类型:
function getLogger(name?: string): Logger;

获取此次编译过程的 logger,可通过该 logger 记录消息。

this.version

  • 类型: number

loader API 的版本号。当前为 2。

这对于提供向后兼容性很有用。基于版本号,你可以为 breaking changes 指定自定义逻辑或降级方案。

内部属性

Warning

注意,使用 this._compilerthis._compilation 这些 Rspack 的内部属性会使你的 loader 失去独立性。

理想情况下,loader 应该只关注文件转换逻辑,对于给定的输入,输出是确定的,不依赖 Rspack 的内部状态。依赖这些内部对象会增加不可预测的行为,使测试和维护变得困难。

因此,建议仅在没有其他替代方案时才考虑使用这些属性。

this._compiler

  • 类型: Compiler

访问当前的 Rspack Compiler 对象。

this._compilation

  • 类型: Compilation

访问当前的 Rspack Compilation 对象。