CC 4.0 协议声明

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

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

Loader 上下文

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

this.addContextDependency()

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

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

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

loader.js
const path = require('node:path');

module.exports = 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.js
const path = require('node:path');

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

this.addMissingDependency()

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

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

loader.js
const path = require('node:path');

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

this.async()

  • 类型: () => LoaderContextCallback

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

this.cacheable()

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

默认情况下,loader 的处理结果会被标记为可缓存。调用这个方法然后传入 false,可以关闭 loader 处理结果的缓存能力。

this.clearDependencies()

  • 类型:
function clearDependencies(): void;

移除 loader 结果的所有依赖。

this.callback()

  • 类型:
function callback(
  err: Error | null,
  content: string | Buffer,
  sourceMap?: SourceMap,
  meta?: any,
): void;

将 Loader 处理后的结果告诉 Rspack。

第一个参数必须是 Error 或者 null,会标记当前模块为编译失败,第二个参数是一个 string 或者 Buffer,表示模块被该 Loader 处理后的文件内容,第三个参数是一个可以该 Loader 处理后的 source map,第四个参数会被 Rspack 忽略,可以是任何东西(例如一些元数据)。

WARNING

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

传递给 this.callback 的值会传递给下一个 loader。 sourceMapmeta 参数是可选的,如果没有传递,那么下一个 loader 将不会收到它们。

this.context

  • 类型: string | null

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

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

loader.js
module.exports = function loader(source) {
  console.log(this.context); // '/project/src/components'
  return source;
};

如果被处理的是模块不是来自文件系统,例如虚拟模块,那么 this.context 的值为 null

this.data

  • 类型: unknown

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

this.dependency()

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

this.addDependency() 的别名。

this.emitError()

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

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

this.emitWarning()

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

发出一个警告。

this.emitFile()

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

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

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

  return source;
};

this.getOptions()

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

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

例如:

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

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

my-loader.js
module.exports = function myLoader(source) {
  const options = this.getOptions();
  console.log(options); // { foo: 'bar' }
  return source;
};

在 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 验证,请自行调用 scheme-utils 或其他 schema 验证库。

this.getResolve()

  • 类型:
function getResolve(options: ResolveOptions): resolve;

创建一个类似于 this.resolve 的解析函数。

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.js
const path = require('node:path');

module.exports = 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.js
const path = require('node:path');

module.exports = 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.resolve()

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

解析一个模块标识符。

  • context 必须是一个目录的绝对路径。此目录用作解析的起始位置。
  • request 是要被解析的模块标识符。
  • callback 是一个处理解析路径的回调函数。

this.mode

  • 类型: Mode

当 Rspack 运行时读取 mode 的值,可能的值为:'production''development''none'

loader.js
module.exports = function loader(source) {
  console.log(this.mode); // 'production' or other values
  return source;
};

this.target

  • 类型: Target

当 Rspack 运行时读取 target 的值。

loader.js
module.exports = function loader(source) {
  console.log(this.target); // 'web' or other values
  return source;
};

this.resource

  • 类型: string

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

loader.js
module.exports = 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.js
module.exports = function loader(source) {
  console.log(this.resourcePath); // '/abc/resource.js'
  return source;
};

this.resourceQuery

  • 类型: string

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

loader.js
module.exports = function loader(source) {
  console.log(this.resourceQuery); // '?query'
  return source;
};

this.resourceFragment

  • 类型: string

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

loader.js
module.exports = function loader(source) {
  console.log(this.resourceFragment); // '#hash'
  return source;
};

this.rootContext

  • 类型: string

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

loader.js
module.exports = function loader(source) {
  console.log(this.rootContext); // /path/to/project
  return source;
};

this.sourceMap

  • 类型: boolean

是否应该生成一个 source map。

this.getLogger()

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

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