close
CC 4.0 协议

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

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

模块变量

本节涵盖了使用 Rspack 编译代码时所有可用的变量。模块将能够通过 module 和其他变量访问来自编译过程的特定数据。

CommonJS

module.loaded

false 表示该模块正在执行, true 表示同步执行已经完成。

module.id

当前模块的 ID。

src/main.js
module.id === require.resolve('./src/main.js'); // true

module.hot

是否启用了热模块替换,并提供了一些方法来处理该过程。有关详细信息,请参阅 HMR API 页面。

global

node.js global.

Rspack 会将 global 替换为代理对象并在其中处理兼容性问题。

源码
global['property']
产物
__webpack_require__.g['property'];

// webpack/runtime/global
__webpack_require__.g = (function () {
  // 兼容处理
})();

__filename

依赖于配置项 node.__filename

如果在一个被 Parser 解析的表达式内部使用,则配置选项会被当作 true 处理。

源码
__filename
产物
'src/main.js';

__dirname

依赖于配置项 node.__dirname

如果在一个被 Parser 解析的表达式内部使用,则配置选项会被当作 true 处理。

源码
__dirname
产物
'src';

import.meta(ESM)

import.meta 将特定上下文的元数据暴露给 JavaScript 模块,例如模块的 URL。它仅在支持 ESM(模块类型javascript/autojavascript/esm)的模块中可用。

通常情况下,未知的 import.meta 元数据默认会被替换为 undefined。当使用 ESM 格式输出时,module.parser.javascript.importMeta 的默认值为 'preserve-unknown',因此未知的元数据会被保留并在运行时被计算。

Rspack 在编译时会静态分析将 import.meta 的属性替换为具体值,因此不支持动态访问 import.meta(如 Object.keys(import.meta)),否则会抛出警告。你应该通过属性访问或解构赋值的方式来访问 import.meta 上的元数据。

源码
// 会抛出警告
Object.keys(import.meta);
// 允许 typeof 访问
typeof import.meta;
// 允许属性访问
import.meta.url;
// 允许解构赋值访问
let { url } = import.meta;
产物
// Warning
Object.keys({});

('object');

('file:///project/index.js');

let { url } = { url: 'file:///project/index.js' };

import.meta.url

返回当前模块的以 file: 开头的绝对路径 URL 字符串。

源码
import.meta.url;
typeof import.meta.url;
产物
'file:///project/index.js';
'string';

import.meta.main

返回一个布尔值,表示当前模块是否为入口模块。

源码
if (import.meta.main) {
  main();
}
产物
if (
  __webpack_module_cache__[/* entry module id */ __webpack_require__.s] ===
  module
) {
  main();
}

import.meta.filename

返回当前模块的完整文件路径,是 __filename 的 ESM 等价写法。常用于在 ESM 模块中获取当前文件的路径信息。

具体的编译行为由 node.__filename 配置项控制,详见该配置文档。

import.meta.dirname

返回当前模块所在的目录路径,是 __dirname 的 ESM 等价写法。常用于在 ESM 模块中构造基于当前文件位置的路径。

具体的编译行为由 node.__dirname 配置项控制,详见该配置文档。

import.meta.resolve

Added in v2.0.0
Stability: Experimental

require.resolve() 的 ESM 等价写法,用于获取其他模块的 ID。会将模块打包进最终的 bundle 中,并返回该模块的模块 ID。

源码
let img = new Image();
img.src = import.meta.resolve('./img.png');
产物
let img = new Image();
img.src = './src/img.png'; // img.png 的模块 ID
Warning

import.meta.resolve() 目前仍是实验性功能,需要通过 module.parser.javascript.importMetaResolve 开启,未来会优先对齐标准实现,因此该 API 行为可能会发生变化,请谨慎使用。

import.meta.webpackContext

Rspack/Webpack specific

import.meta.webpackContextrequire.context() 的 ESM 等价写法,它允许你动态地引入一组模块。

你可以在代码中使用 import.meta.webpackContext,Rspack 将在构建时进行解析并引用匹配的模块。

  • 类型:
function webpackContext(
  /**
   * 要搜索的目录
   */
  request: string,
  options?: {
    /**
     * 是否还搜索其子目录
     * @default true
     */
    recursive?: boolean;
    /**
     * 匹配文件的正则表达式
     * @default /^\.\/.*$/(匹配任意文件)
     */
    regExp?: RegExp;
    /**
     * 模块加载模式
     * @default 'sync'
     */
    mode?: 'sync' | 'eager' | 'weak' | 'lazy' | 'lazy-once';
    include?: RegExp;
    exclude?: RegExp;
    preload?: boolean | number;
    prefetch?: boolean | number;
    chunkName?: string;
    exports?: string | string[][];
  },
): Context;
  • 示例:
// 创建一个上下文,
// 文件直接来自 test 目录,匹配的文件名以 `.test.js` 结尾。
const context = import.meta.webpackContext('./test', {
  recursive: false,
  regExp: /\.test\.js$/,
});
// 创建一个上下文,
// 文件来自父文件夹及其所有子级文件夹,匹配的文件名以 `.stories.js` 结尾。
const context = import.meta.webpackContext('../', {
  recursive: true,
  regExp: /\.stories\.js$/,
});
// 如果 `mode` 被设置为 `lazy`,模块将会被异步加载
const context = import.meta.webpackContext('./locales', {
  recursive: true,
  regExp: /\.json$/,
  mode: 'lazy',
});
Tip

Rspack 在编译时,会通过静态分析来解析 import.meta.webpackContext() 的参数,因此参数必须是字面量

例如,regExp 的值不允许传入一个变量,也不允许传入 new RegExp() 生成的值,只能是一个正则表达式字面量。

context API

import.meta.webpackContext() 返回的 context 是一个函数,它接收一个 request 参数(模块路径)。

这个函数有三个属性:resolvekeysid

  • resolve 是一个函数,它返回模块标识符被解析后得到的模块 id。
  • keys 也是一个函数,它返回一个数组,由所有可能被此上下文模块处理的请求组成。
  • id 是上下文模块的模块 id. 它可能在使用 module.hot.accept 时会用到。

如果你想引入一个文件夹下面的所有文件,或者引入能匹配一个正则表达式的所有文件,这个功能就会很有帮助。

考虑一种情况,你有一个这样的文件夹结构:

src
├── components
│   ├── Button.js
│   ├── Header.js
│   └── Footer.js

你可以使用 import.meta.webpackContext() 动态导入文件夹中的所有组件:

const componentsContext = import.meta.webpackContext('./components', {
  recursive: false,
  regExp: /\.js$/,
});

componentsContext.keys().forEach((fileName) => {
  const componentModule = componentsContext(fileName);

  // 在这里你可以使用你的模块,例如使用 console.log 输出
  console.log(componentModule);
});

import.meta.webpackContext() 简化了模块导入过程,尤其是当你有大量模块需要管理时。在使用时,请避免匹配到不需要的文件,否则可能导致构建时间和产物体积明显增加。

import.meta.glob

Added in v2.0.5Rspack only

import.meta.glob 允许你使用 glob 模式一次导入多个模块。Rspack 将在构建时解析并引用匹配的模块。

  • 类型:
interface ImportMetaGlobOptions<Eager extends boolean = boolean> {
  /**
   * 如果为 `true`,模块将同步加载
   *
   * @default false
   */
  eager?: Eager;
  /**
   * 只导入指定的具名导出。设置为 `default` 时会导入默认导出。
   */
  import?: string;
  /**
   * 为每个匹配模块请求追加 query。
   */
  query?: string | Record<string, string | number | boolean>;
  /**
   * 搜索 `node_modules` 和隐藏路径中的文件。
   *
   * @default false
   */
  exhaustive?: boolean;
  /**
   * 用于解析相对 glob 模式和返回 key 的 base 路径。
   */
  base?: string;
}

function glob(
  /**
   * 匹配文件的 glob 模式,或 glob 模式数组
   */
  pattern: string | readonly string[],
  options?: ImportMetaGlobOptions<false>,
): Record<string, () => Promise<any>>;

function glob(
  /**
   * 匹配文件的 glob 模式,或 glob 模式数组
   */
  pattern: string | readonly string[],
  options: ImportMetaGlobOptions<true>,
): Record<string, any>;
  • 参数:

    • pattern:匹配文件的 glob 模式字符串,或 glob 模式字符串数组(例如 './dir/*.js')。支持 *?[abc]{a,b} 以及 **(递归匹配)。数组模式也可以包含负向模式,例如 '!**/bar.js'
    • options.eager:设置为 true 时,模块直接包含在 bundle 中并同步加载。默认为 false,模块会延迟加载,每个值是一个返回 Promise 的 thunk 函数。
    • options.import:只导入每个匹配模块的指定导出。例如使用 'default' 获取默认导出,或使用 'setup' 这样的具名导出。
    • options.query:为每个匹配模块请求追加 query。可以是 '?raw' 这样的 query 字符串,也可以是会序列化为 URL query 字符串的对象。import.meta.glob() 返回对象中的 key 不包含 query。
    • options.exhaustive:搜索 node_modules 和隐藏路径中的文件。默认关闭,因为可能增加构建时间。
    • options.base:用于解析相对 glob 模式和返回 key 的 base 路径。绝对 glob 模式仍从项目根目录解析,但返回 key 会相对于 base
  • 示例:

// 延迟加载(默认):每个值是一个 () => Promise<module> 函数
const modules = import.meta.glob('./dir/*.js');

// 所有匹配的模块都可以通过异步 thunk 访问
const foo = await modules['./dir/foo.js']();
console.log(foo.default);

// 同步加载:每个值直接是模块对象
const eagerModules = import.meta.glob('./dir/*.js', { eager: true });
console.log(eagerModules['./dir/foo.js'].default);

// 只导入每个匹配模块的默认导出
const defaultModules = import.meta.glob('./dir/*.js', { import: 'default' });
const fooDefault = await defaultModules['./dir/foo.js']();
console.log(fooDefault);

// 将同步加载和指定导出结合使用
const eagerDefaultModules = import.meta.glob('./dir/*.js', {
  eager: true,
  import: 'default',
});
console.log(eagerDefaultModules['./dir/foo.js']);

// 为每个匹配的 import 追加 query
const rawModules = import.meta.glob('./dir/*.js', {
  query: '?raw',
  import: 'default',
});
const rawFoo = await rawModules['./dir/foo.js']();

// query 对象会被序列化为 URL query 字符串
const dataModules = import.meta.glob('./dir/*.js', {
  query: { type: 'data', inline: true },
  eager: true,
});

// 从 ./base 解析文件,并暴露相对于 ./base 的 key
const modulesWithBase = import.meta.glob('./**/*.js', {
  base: './base',
});

// 包含 node_modules 和隐藏路径中的匹配文件
const exhaustiveModules = import.meta.glob(
  ['./node_modules/**/*.js', './.config/*.js'],
  {
    exhaustive: true,
  },
);

// 使用 ** 进行递归匹配
const allModules = import.meta.glob('./components/**/*.js', { eager: true });
Tip

Rspack 在编译时会通过静态分析来解析 import.meta.glob() 的参数,因此 pattern 参数必须是字符串字面量或字符串字面量数组,options 参数必须是对象字面量。不支持使用变量或动态构造的值。

Warning

import.meta.glob() 会在构建时匹配文件系统中的文件并将其包含在 bundle 中。避免使用过于宽泛的 glob 模式,否则可能导致构建时间和产物体积明显增加。

import.meta.webpackHot

Rspack/Webpack specific

module.hot 的 ESM 等价写法,import.meta.webpackHot 可以在严格 ESM 模块(模块类型为 javascript/esm)中使用,而 module.hot 不能。

Runtime

__webpack_hash__

Rspack/Webpack specific

提供对编译过程中(compilation)的 hash 信息的访问。

源码
__webpack_hash__
产物
__webpack_require__.h();

// webpack/runtime/get_full_hash
__webpack_require__.h = function () {
  return '9210c6f859a51c6f9a62';
};

__webpack_runtime_id__

Rspack/Webpack specific

访问当前入口的 runtime chunk 的 id。

源码
__webpack_runtime_id__
产物
__webpack_require__.j;

// webpack/runtime/runtime_id
__webpack_require__.j = '909';

__webpack_public_path__

Rspack/Webpack specific

等于配置选项的 output.publicPath

源码
__webpack_public_path__
产物
__webpack_require__.p;

// output.publicPath !== "auto"
__webpack_require__.p = 'output.publicPath';
// output.publicPath === "auto",
__webpack_require__.p = '由 document/location 计算得来';

查看 动态设置 publicPath 了解更多关于 __webpack_public_path__ 的用法。

__webpack_base_uri__

Rspack/Webpack specific

运行时获取或修改 Base URI。

源码
__webpack_base_uri__
产物
__webpack_require__.b;

// chunk loading
__webpack_require__.b = document.baseURI || self.location.href;

__webpack_nonce__

Rspack/Webpack specific

Rspack 能够为其加载的所有脚本添加 nonce,即一次性随机数。在入口文件中设置 __webpack_nonce__ 变量以激活此功能。

源码
__webpack_nonce__ = 'your_nonce_code';
产物
__webpack_require__.nc = '2312312';

// webpack/runtime/load_script
if (__webpack_require__.nc) {
  script.setAttribute('nonce', __webpack_require__.nc);
}

Modules

__webpack_modules__

Rspack/Webpack specific

访问所有模块的内部对象。

源码
__webpack_modules__
产物
var __webpack_modules__ = {
  'main.js': function () {
    __webpack_require__.m;
  },
};
__webpack_require__.m = __webpack_modules__;

__webpack_module__

Rspack/Webpack specific

它提供对当前 module 的访问。module 在 ESM 严格模式下不可用。

源码
__webpack_module__
产物
"main.js": function(renamed_module) {
  renamed_module
}

__webpack_module__.id

Rspack/Webpack specific

它提供对当前 module(module.id) ID 的访问。module 在 ESM 严格模式下不可用。

源码
__webpack_module__.id
产物
"main.js": function(renamed_module) {
  renamed_module.id
}

__webpack_require__

Rspack/Webpack specific

原始 require 函数。这个表达式不会被解析器解析为依赖。

源码
__webpack_require__('./dep.js')
产物
"main.js": function(_, __, renamed_require) {
  renamed_require('./dep.js')
}

__non_webpack_require__

Rspack/Webpack specific

生成一个不会被 Rspack 解析的 require 函数。配合全局可以获取到的 require 函数,可以完成一些酷炫操作。

源码
__non_webpack_require__('outer.js')
产物
"main.js": function(_, __, __webpack_require__) {
  require('outer.js')
}

__webpack_is_included__

Rspack/Webpack specific

测试给定的模块是否被 Rspack 打包。

源码
if (__webpack_is_included__('./dep.js')) {
  // do something
}
产物
if (true) {
  // do something
}

__resourceQuery

Rspack/Webpack specific

当前模块的资源查询(resource query)。如果进行了如下的 require 调用,那么查询字符串(query string)在 file.js 中可用。

require('file.js?test');
源码
__resourceQuery
产物
'?test';

__webpack_exports_info__

Added in v1.0.0Rspack/Webpack specific

在模块中通过 __webpack_exports_info__ 可以读取如下导出信息:

  • __webpack_exports_info__ 始终为 true
  • 当导出未被引用时 __webpack_exports_info__.<exportName>.usedfalse,否则为 true
  • __webpack_exports_info__.<exportName>.useInfo 值如下:
    • false:导出未被引用
    • true:导出被引用
    • null:导出是否被引用依赖运行时条件判断
    • undefined:无法判断导出的引用情况
  • __webpack_exports_info__.<exportName>.provideInfo 值如下:
    • false:导出未被提供
    • true:导出被提供
    • null:导出是否被提供依赖运行时条件判断
    • undefined:无法判断导出的提供情况
  • 支持访问导出的多级子属性:如 __webpack_exports_info__.<exportName>.<exportProperty1>.<exportProperty2>.used
  • 通过 __webpack_exports_info__.<exportName>.canMangle 判断导出是否可被重命名
源码
if (__webpack_exports_info__.someUsedExport.used) { }
if (__webpack_exports_info__.someUnusedExport.used) { }
产物
if (true) {
}
if (false) {
}

Chunks

__webpack_chunkname__

Rspack/Webpack specific

访问当前 chunk 的名称。

源码
__webpack_chunkname__
产物
__webpack_require__.cn;

// webpack/runtime/chunk_name
__webpack_require__.cn = 'main';

__webpack_chunk_load__

内部 chunk 载入函数,有一个输入参数:

  • chunkId: 需要载入的 chunk id
源码
__webpack_chunk_load__
产物
__webpack_require__.e;

// webpack/runtime/ensure_chunk
__webpack_require__.e = function (chunkId) {
  // return chunk loading promise
};

以下为当一个 chunk 加载失败时,从备用公共路径加载 chunk 的示例:

const originalLoad = __webpack_chunk_load__;
const publicPaths = ['a', 'b', 'c'];
__webpack_chunk_load__ = async (id) => {
  let error;
  for (const path of publicPaths) {
    __webpack_public_path__ = path;
    try {
      return await originalLoad(id);
    } catch (e) {
      error = e;
    }
  }
  throw error;
};
import('./module-a').then((moduleA) => {
  // now webpack will use the custom __webpack_chunk_load__ to load chunk
});

__webpack_get_script_filename__

Added in v1.0.0Rspack/Webpack specific

通过 chunk 的 id 获取 chunk 的文件名。

源码
__webpack_get_script_filename__
产物
__webpack_require__.u;

// webpack/runtime/get_chunk_filename
__webpack_require__.u = function (chunkId) {
  // ...
};

可以通过赋值来在运行时修改它的行为。比如以下示例,在最终加载 chunk 的路径后增加特定后缀。

const oldFn = __webpack_get_script_filename__;

__webpack_get_script_filename__ = (chunkId) => {
  const filename = oldFn(chunkId);
  return filename + '.changed';
};

Module Federation

__webpack_share_scopes__

Rspack/Webpack specific

用于存储 module federation 中的一个远程容器共享作用域 (shared scope) 相关信息。

__webpack_init_sharing__

Rspack/Webpack specific

用于初始化 module federation 中的一个远程容器共享作用域 (shared scope) 并加载相关模块。

System.js

__system_context__

Rspack/Webpack specific

可在 output.library.type="system" 时获取 System.js 上下文。

Rspack

__rspack_version__

Rspack only

当前使用的 Rspack 版本,默认从 @rspack/core/package.json 读取。可以通过 output.bundlerInfo.version 修改。

源码
__rspack_version__
产物
__webpack_require__.rv;

// webpack/runtime/rspack_version
__webpack_require__.rv = '0.7.4';

__rspack_unique_id__

Added in v1.0.0Rspack only

当前打包工具的 ID,值为 {bundler}@{version}。其中:

源码
__rspack_unique_id__
产物
__webpack_require__.ruid;

// webpack/runtime/rspack_unique_id
__webpack_require__.ruid = '[email protected]';