> For AI agents: the complete documentation index is available at https://rspack.rs/zh/llms.txt, the full documentation bundle is available at https://rspack.rs/zh/llms-full.txt.

# 模块方法

当使用 Rspack 打包应用程序时，你可以选择多种模块语法风格，包括 [ES modules](https://nodejs.org/api/esm.html#modules-ecmascript-modules) 和 [CommonJS](https://nodejs.org/api/modules.html)。

尽管 Rspack 支持多种模块语法，但我们还是建议尽量使用一致的语法，以此避免一些奇怪的行为和 bug。

事实上，当距离最近的 `package.json` 文件中 ["type"](https://nodejs.org/api/packages.html#type) 字段值为 `"module"` 或 `"commonjs"` 时，Rspack 会对 `.mjs` 文件、`.cjs` 文件或`.js` 文件进行对应的处理：

- 文件后缀为 `.mjs`，或者 `package.json` 中 `"type": "module"` 且后缀为 `.js` 时：
  - 不允许使用 CommonJS，如 `require`，`module.exports` 或 `exports`
  - 引入文件时需指定扩展名，例如，应使用 `import './src/App.mjs'`，而非 `import './src/App'`
- 文件后缀为 `.cjs`，或者 `package.json` 中 `"type": "commonjs"` 且后缀为 `.js` 时：
  - 不允许使用 ESM，如 `import` 和 `export`

## ES modules (推荐)

Rspack 原生支持 ES modules 语法，可以使用静态的 `import`、`export` 和 `import()` 语法。

:::warning
如果使用其他的 ES6+ 特性，你仍然需要引入 SWC 或 Babel 进行转换。
:::

### import

静态 `import` 另一个模块的 `export`。

```js
import MyModule from './my-module.js';
import { NamedExport } from './other-module.js';
```

你还可以 `import` Data URI，这允许你直接在导入语句中嵌入 Base64 编码的 JavaScript 代码：

```js
// 等同于 import 一个包含 `console.log('hello')` 的模块
import 'data:text/javascript;charset=utf-8;base64,Y29uc29sZS5sb2coJ2hlbGxvJyk=';

// 等同于 import 一个包含 `export const number = 42;` 的模块
import { number } from 'data:text/javascript;charset=utf-8;base64,ZXhwb3J0IGNvbnN0IG51bWJlciA9IDQyOw==';
```

### export

将任何内容作为默认导出或具名导出。

```js
// 具名导出
export var Count = 5;
export function Multiply(a, b) {
  return a * b;
}

// 默认导出
export default {
  // Some data...
};
```

### Dynamic import()

```ts
function import(path: string): Promise;
```

动态加载模块，参考 [Dynamic import](https://rspack.rs/zh/guide/optimization/code-splitting.md#%E5%8A%A8%E6%80%81%E5%AF%BC%E5%85%A5dynamic-import) 了解更多。

对 `import()` 的调用被视为分割点，这意味着请求的模块及其子模块被拆分成单独的 chunk。

```js
if (module.hot) {
  import('lodash').then((_) => {
    // 使用 lodash 做些事情...
  });
}
```

:::warning
此功能内部依赖于 `Promise`。如果你在旧版浏览器中使用 `import()`，请记得使用类似于 [core-js](https://github.com/zloirock/core-js)， [es6-promise](https://github.com/stefanpenner/es6-promise) 或 [promise-polyfill](https://github.com/taylorhakes/promise-polyfill) 的 polyfill 来模拟 `Promise`。
:::

### import() 中的动态表达式

`import()` 无法使用完全动态的导入语句，例如 `import(foo)`。因为 `foo` 可能是系统或项目中任何文件的任何路径。

`import()` 必须至少包含一些关于模块所在位置的信息。可以将打包限制在特定目录或一组文件中，这样当你使用动态表达式时，在 `import()` 调用中可能被请求的每个模块都会被包括进来。

例如，`import(./locale/${language}.json)` 会将 `./locale` 目录中的每个 `.json` 文件都被打包进新的代码块。在运行时，一旦变量 `language` 被计算出来，任何像 `english.json` 或 `german.json` 这样的文件都将可供使用。

```js
// 想象一下，如果我们有一种方法可以从 Cookie 或其他存储中获取语言
const language = detectVisitorLanguage();
import(`./locale/${language}.json`).then((module) => {
  // 做一些翻译相关的事情
});
```

### import() 中的魔法注释 \{#magic-comments}


Rspack/Webpack specific

通过向 import 语句添加注释，可以指定 chunk 名称、加载模式等行为。

:::tip
从 Rspack 2.1.0 开始，推荐使用下方的 `rspack` 前缀魔法注释。对应的 `webpack` 前缀注释仍会被兼容支持，例如 `webpackIgnore` 等价于 `rspackIgnore`。

下方示例统一使用 `rspack` 前缀；如需兼容 webpack，可以将其替换为对应的 `webpack` 前缀。
:::

```js
// 单个模块
import(
  /* rspackChunkName: "my-chunk-name" */
  /* rspackMode: "lazy" */
  /* rspackFetchPriority: "high" */
  'module'
);

// 多个可能模块
import(
  /* rspackInclude: /\.json$/ */
  /* rspackExclude: /\.noimport\.json$/ */
  /* rspackChunkName: "my-chunk-name" */
  /* rspackMode: "lazy" */
  /* rspackPrefetch: true */
  /* rspackPreload: true */
  `./locale/${language}`
);
```

#### rspackIgnore \{#rspackignore}

- **类型：** `boolean`
- **webpack 兼容名称：** `webpackIgnore`

设置为 `true` 时，Rspack 将跳过对该动态导入的静态分析和打包处理。具体表现为：

1. 构建时不会分析该模块的依赖关系
2. 该模块不会被打包为独立的 chunk 文件
3. 导入操作将在运行时由浏览器原生 `import()` 执行

这在需要从外部 CDN 动态加载 ESM 格式的第三方库时特别有用，例如：

```js
import('https://esm.sh/react' /* rspackIgnore: true */).then((React) => {
  console.log(React.version); // 19.0.0
});
```

`rspackIgnore` 同样适用于 `new URL()` 语法。默认情况下，Rspack 会解析 `new URL()` 中的模块标识符，并将其引用的模块打包到构建产物中。当你需要 Rspack 跳过某个 `new URL()` 的处理时，可以添加 `rspackIgnore: true` 注释：

```js
// Rspack 会处理这个 URL，将 './index.css' 打包到构建产物中
const url1 = new URL('./index.css', import.meta.url);

// Rspack 会忽略这个 URL，保持原始的模块标识符
const url2 = new URL(/* rspackIgnore: true */ './index.css', import.meta.url);

// 同样支持 `webpackIgnore`
const url3 = new URL(/* webpackIgnore: true */ './index.css', import.meta.url);
```

#### rspackMode \{#rspackmode}

- **类型：** `"eager" | "lazy" | "weak" | "lazy-once"`
- **webpack 兼容名称：** `webpackMode`
- **默认值：** `'lazy'`

可以指定以不同的模式解析动态导入。支持以下选项：

- `'lazy'`（默认值）：为每个可能导入的模块生成一个可延迟加载的 chunk。
- `'lazy-once'`：将动态导入上下文中的所有可能模块生成到同一个异步 chunk 中。第一次调用 `import()` 时加载该 chunk，后续调用会复用它。此模式适用于 `import('./locales/' + language + '.json')` 这类可能匹配多个模块的动态表达式。
- `'eager'`：不生成额外的 chunk，而是将所有可能的模块放入当前 chunk，因此不会产生额外的网络请求。`import()` 仍然返回 Promise，且模块要等到调用 `import()` 时才会执行。
- `'weak'`：仅在模块已通过其他方式加载时才解析成功，例如模块已包含在另一个加载完成的 chunk 中。此模式不会发起网络请求；如果模块不可用，Promise 会被拒绝。它主要用于由服务端确保所需 chunk 已包含在初始响应中的 SSR 场景。

例如，使用 `lazy-once` 将所有可能的语言模块合并到同一个异步 chunk 中：

```js
const language = detectVisitorLanguage();
const messages = await import(
  /* rspackMode: "lazy-once" */
  `./locales/${language}.js`
);
```

#### rspackPrefetch \{#rspackprefetch}

- **类型：**
  - `number`：预取优先级
  - `boolean`：`false` 表示不预取，`true` 表示预取且优先级为 `0`
- **webpack 兼容名称：** `webpackPrefetch`

告诉浏览器将来可能需要该资源来进行某些导航跳转，详情请查看[预取/预载模块](https://rspack.rs/zh/guide/optimization/code-splitting.md#prefetchingpreloading-%E6%A8%A1%E5%9D%97)。

例如，当父 chunk 加载后，浏览器会在空闲时预取编辑器 chunk：

```js
export function openEditor() {
  return import(
    /* rspackPrefetch: true */
    './editor.js'
  );
}
```

也可以使用数字设置预取优先级：

```js
import(/* rspackPrefetch: 10 */ './editor.js');
```

#### rspackPreload \{#rspackpreload}

- **类型：**
  - `number`：预载优先级
  - `boolean`：`false` 表示不预载，`true` 表示预载且优先级为 `0`
- **webpack 兼容名称：** `webpackPreload`

告诉浏览器在当前导航期间可能需要该资源，详情请查看[预取/预载模块](https://rspack.rs/zh/guide/optimization/code-splitting.md#prefetchingpreloading-%E6%A8%A1%E5%9D%97)。

例如，在加载父 chunk 的同时预载图表库：

```js
export async function renderDashboard() {
  const { renderChart } = await import(
    /* rspackPreload: true */
    './chart.js'
  );

  renderChart();
}
```

#### rspackChunkName \{#rspackchunkname}

- **类型：** `string`
- **webpack 兼容名称：** `webpackChunkName`

指定新 chunk 的名称。

```js
const settings = await import(
  /* rspackChunkName: "settings" */
  './settings.js'
);
```

最终文件名仍由 [`output.chunkFilename`](https://rspack.rs/zh/config/output.md#outputchunkfilename) 决定。

#### rspackFetchPriority \{#rspackfetchpriority}

- **类型：** `"low" | "high" | "auto"`
- **webpack 兼容名称：** `webpackFetchPriority`

为指定的动态导入设置 [`fetchPriority`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/fetchPriority)。也可以通过使用 `module.parser.javascript.dynamicImportFetchPriority` 选项为所有动态导入设置全局默认值。

例如，为首屏关键模块设置较高的获取优先级：

```js
const hero = await import(
  /* rspackFetchPriority: "high" */
  './hero.js'
);
```

#### rspackInclude \{#rspackinclude}

- **类型：** `RegExp`
- **webpack 兼容名称：** `webpackInclude`

在导入解析时匹配的正则表达式。只有匹配的模块**才会被打包**。

例如，只将 `./locales` 目录中的 `.json` 文件纳入动态导入上下文：

```js
const messages = await import(
  /* rspackInclude: /\.json$/ */
  `./locales/${language}`
);
```

#### rspackExclude \{#rspackexclude}

- **类型：** `RegExp`
- **webpack 兼容名称：** `webpackExclude`

在导入解析时匹配的正则表达式。只有匹配的模块**不会被打包**。

例如，排除 `./locales` 目录中的测试文件：

```js
const messages = await import(
  /* rspackExclude: /\.test\.js$/ */
  `./locales/${language}.js`
);
```

:::info
`rspackInclude` 和 `rspackExclude` 只会筛选静态路径前缀（例如 `./locales`）下发现的候选模块，不会改变该前缀。等价的 `webpackInclude` 和 `webpackExclude` 注释也会被兼容支持。
:::

#### rspackExports \{#rspackexports}

- **类型：** `string | string[]`
- **webpack 兼容名称：** `webpackExports`

使 Rspack 在处理该动态 `import()` 模块时仅打包指定的导出。这样可以降低 chunk 的产物体积。

例如，当导入结果传给其他函数、Rspack 无法静态推断具体使用了哪些导出时，可以显式声明需要的导出：

```js
const widget = await import(
  /* rspackExports: ["render", "version"] */
  './widget.js'
);

consumeWidget(widget);
```

如果代码直接访问导入模块的属性或对其进行解构，Rspack 通常可以自动推断使用的导出，无需添加 `rspackExports`。

## CommonJS

Rspack 也支持 `CommonJS` 语法，可以使用 `require` 和 `module.exports` 语法。

### require

以同步的方式引入其他模块。

```js
require(dependency: string);
```

### require.resolve

以同步的方式获取模块的 ID。此方法会将模块打包进最终的 bundle 中，但不会执行模块代码。返回的模块 ID 主要用于与 `require.cache[id]` 或 Rspack 内部的 `__webpack_require__(id)` 一起使用，在大多数应用场景中应避免直接使用此方法。

```js
require.resolve(dependency: string);
```

:::warning
模块 ID 的类型可以是 `number` 或 `string`，具体取决于 `optimization.moduleIds` 配置。
:::

### require.cache

多处引用同一模块，最终只会产生一次模块执行和一次导出。所以，会在运行时（runtime）中会保存一份缓存。删除此缓存，则会产生新的模块执行和新的导出。

```js
var d1 = require('dependency');
require('dependency') === d1;
delete require.cache[require.resolve('dependency')];
require('dependency') !== d1;
```

### require.context


Rspack/Webpack specific

`require.context` 允许你动态地 require 一组模块。

你可以在代码中使用 `require.context`，Rspack 将在构建时进行解析并引用匹配的模块。

:::tip
`require.context` 的返回值与 [import.meta.webpackContext](https://rspack.rs/zh/api/runtime-api/module-variables.md#importmetawebpackcontext) 相同。
:::

- **类型：**

```ts
function requireContext(
  /**
   * 要搜索的目录
   */
  directory: string,
  /**
   * 是否还搜索其子目录
   * @default true
   */
  includeSubdirs?: boolean,
  /**
   * 匹配文件的正则表达式
   * @default /^\.\/.*$/（匹配任意文件）
   */
  filter?: RegExp,
  /**
   * 模块加载模式
   * @default 'sync'
   */
  mode?: 'sync' | 'eager' | 'weak' | 'lazy' | 'lazy-once',
): Context;
```

- **示例：**

```js
// 创建一个上下文，
// 文件直接来自 test 目录，匹配的文件名以 `.test.js` 结尾。
const context = require.context('./test', false, /\.test\.js$/);
```

```js
// 创建一个上下文，
// 文件来自父文件夹及其所有子级文件夹，匹配的文件名以 `.stories.js` 结尾。
const context = require.context('../', true, /\.stories\.js$/);
```

```js
// 如果 `mode` 被设置为 `lazy`，模块将会被异步加载
const context = require.context('./locales', true, /\.json$/, 'lazy');
```

:::tip
Rspack 在编译时，会通过静态分析来解析 `require.context` 的参数，因此参数必须是[字面量](https://developer.mozilla.org/en-US/docs/Glossary/Literal)。

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

### require.ensure


Rspack/Webpack specific

:::tip
建议使用更符合标准的 `import()` 来替代 `require.ensure()`。
:::

将给定 `dependencies` 单独打包，并异步加载这些依赖。

- **Type:**

```ts
function requireEnsure(
  /**
   * 需要异步加载的模块列表
   */
  dependencies: String[],
  /**
   * 当 dependencies 中的模块都加载完毕时，这个函数就会被执行。
   * 在这个函数中也可以进一步使用 require() 来加载模块。
   */
  callback: function(),
  /**
   * 当加载依赖失败的时候执行的函数
   */
  errorCallback?: function(error),
  /**
   * 指定由 require.ensure() 生成的 chunk 名称。
   * 通过指定相同的 chunkName 来合并多个 require.ensure() 调用的代码，从而只生成一个 bundle，
   * 从而减少浏览器加载的次数。
   */
  chunkName?: string
): Context;
```

:::warning

- 该特性内部依赖于 [Promise](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise)。 如果你在旧的浏览器上使用 `require.ensure`， 最好加入 polyfill [es6-promise](https://github.com/stefanpenner/es6-promise) 或 [promise-polyfill](https://github.com/taylorhakes/promise-polyfill)。
- 和 webpack 一样，callback 函数也可以接收一个名为 require 的参数（且必须名为 require），该 require 参数和 cjs 的 require 全局变量一致，但我们建议直接使用全局的 require 来加载模块而不是该 require 参数，因为 loader 可能会将其重命名导致依赖分析失败。

:::

- **Example:**

```ts
var a = require('normal-dep');

if (module.hot) {
  require.ensure(['b'], function () {
    var c = require('c');

    // Do something special...
  });
}
```

### require.resolveWeak


Rspack/Webpack specific

与 `require.resolve` 类似，但是不会把 module 打包到最终的 bundle 中。是 "弱（weak）" 依赖。

```js
require.resolveWeak(dependency: string);
```

示例：

```js
if (__webpack_modules__[require.resolveWeak('module')]) {
  // 当模块可用时，执行一些操作
}
if (require.cache[require.resolveWeak('module')]) {
  // 在模块加载完成之前，执行一些操作
}

// 你可以像执行其他 require/import 方法一样，
// 执行动态解析上下文 resolves ("context")
const page = 'Foo';
__webpack_modules__[require.resolveWeak(`./page/${page}`)];
```

## Data URI 模块

Rspack 支持使用 `import` 和 `require` 语法导入 Data URI 模块。

- **import**

```js
import DataURI from 'data:text/javascript,export default 42';
```

- **require**

```js
require('data:text/javascript,module.exports = 42');
```

除此之外，还支持了 Base64 编码：

```js
const {
  number,
  fn,
} = require('data:text/javascript;charset=utf-8;base64,ZXhwb3J0IGNvbnN0IG51bWJlciA9IDQyOwpleHBvcnQgZnVuY3Rpb24gZm4oKSB7CiAgcmV0dXJuICJIZWxsbyB3b3JsZCI7Cn0=');
```

::: tip
Data URI 模块可以被用作虚拟模块（Virtual Modules）的实现方式，如：配合 loader 完成运行时动态加载自定义模块。
:::

### 内置 Rules

Rspack 默认支持这些 [MIME 类型](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Guides/MIME_types) 的 data URI 模块：`application/json`、`text/javascript`、`application/javascript`、`application/node` 和 `application/wasm`。这意味着当你使用这些 MIME 类型创建 data URI 模块时，Rspack 会自动识别他们。

Rspack 内置的 MIME rules 如下：

```js
const defaultMimeRules = [
  {
    mimetype: 'application/node',
    type: 'javascript/auto',
  },
  {
    mimetype: 'application/json',
    type: 'json',
  },
  {
    mimetype: {
      or: ['text/javascript', 'application/javascript'],
    },
    type: 'javascript/esm',
    // ...
  },
  {
    mimetype: 'application/wasm',
    type: 'webassembly/async',
    // ...
  },
];
```

### 自定义 Rules

你可以也使用 [rules\[\].mimetype](https://rspack.rs/zh/config/module-rules.md#rulesmimetype) 来扩展 Data URI 模块的匹配规则，例如为 `text/javascript` 添加自定义的 loaders：

```js title="rspack.config.mjs"
export default {
  module: {
    rules: [
      {
        mimetype: 'text/javascript',
        use: [
          // ...
        ],
      },
    ],
  },
};
```


本页改编自 [webpack 文档](https://webpack.docschina.org/api/module-methods/)，遵循 [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)，且已作修改。

