Skip to content

ESM 外部依赖插件

¥ESM External Require Plugin

esmExternalRequirePlugin 是一个内置的 Rolldown 插件,它将 CommonJS require() 对外部依赖的调用转换为 ESM import 语句,从而确保在不支持 Node.js 模块 API 的环境中兼容。

¥The esmExternalRequirePlugin is a built-in Rolldown plugin that converts CommonJS require() calls for external dependencies into ESM import statements, ensuring compatibility in environments that don't support the Node.js module API.

为什么需要它

¥Why This Is Needed

使用 Rolldown 打包代码时,require() 对外部依赖的调用不会自动转换为 ESM 导入,以保留 require() 的语义。Rolldown 在设置 platform: 'node' 时会注入 require 函数,它会生成如下代码:

¥When bundling code with Rolldown, require() calls for external dependencies are not automatically converted to ESM imports to preserve the semantics of require(). While Rolldown injects require function when platform: 'node' is set, it does so by generating code like:

js
import { createRequire } from 'node:module';
var __require = createRequire(import.meta.url);

然而,这种方法依赖于 Node.js 模块 API,而该 API 在某些环境中不可用。这种方法对于预计稍后打包的库也有问题,因为这些代码很难被打包器分析和转换。

¥However, this approach relies on the Node.js module API, which isn't available in some environments. This approach is also problematic for libraries that are expected to be bundled later, as this code is difficult to be analyzed and transformed by bundlers.

用法

¥Usage

从 Rolldown 的实验性导出中导入并使用该插件:

¥Import and use the plugin from Rolldown's experimental exports:

js
import { defineConfig } from 'rolldown';
import { esmExternalRequirePlugin } from 'rolldown/experimental';

export default defineConfig({
  input: 'src/index.js',
  output: {
    dir: 'dist',
    format: 'esm',
  },
  plugins: [
    esmExternalRequirePlugin({
      external: ['react', 'vue', /^node:/],
    }),
  ],
});

选项

¥Options

external

类型:(string | RegExp)[]

¥Type: (string | RegExp)[]

定义哪些依赖应被视为外部依赖。当输出格式为 ESM 时,它们的 require() 调用将转换为 import 语句。对于非 ESM 输出格式,依赖将被标记为外部,但 require() 调用将保持不变。

¥Defines which dependencies should be treated as external. When the output format is ESM, their require() calls will be converted to import statements. For non-ESM output formats, the dependencies will be marked as external but the require() calls will remain unchanged.

skipDuplicateCheck

类型:boolean 默认值:false

¥Type: boolean Default: false

启用后,跳过检查此插件与顶层 external 选项之间重复的外部变量。当你确信没有重复项时,这可以提高构建性能。

¥When enabled, skips checking for duplicate externals between this plugin and the top-level external option. This can improve build performance when you're confident there are no duplicates.

javascript
esmExternalRequirePlugin({
  external: ['react', 'vue'],
  skipDuplicateCheck: true, // Skip duplicate check for better performance
});

重复外部检测

¥Duplicate External Detection

默认情况下,插件会检查你指定的任何外部组件是否也在顶层 external 选项中配置。如果发现重复项,你将看到一条警告:

¥By default, the plugin checks if any externals you specify are also configured in the top-level external option. If duplicates are found, you'll see a warning:

Found 2 duplicate external: `react`, `vue`. Remove them from top-level `external` as they're already handled by 'builtin:esm-external-require' plugin.

这有助于避免配置混淆,并确保插件正确处理 ESM require() 转换。如果你对配置有信心,可以通过设置 skipDuplicateCheck: true 来禁用此检查。

¥This helps avoid configuration confusion and ensures the plugin handles ESM require() transforms correctly. You can disable this check by setting skipDuplicateCheck: true if you're confident about your configuration.

限制

¥Limitations

由于此插件将 require() 调用更改为 import 语句,因此打包后会存在一些语义差异:

¥Since this plugin changes require() calls to import statements, there are some semantic differences after bundling:

  • 解析现在基于 import 行为,而不是 require 行为

    ¥resolution is now based on import behavior, not require behavior

    • 例如,使用 import 条件而不是 require 条件。

      ¥For example, import condition is used instead of require condition

  • 这些值可能与原始 require() 调用不同,尤其是对于具有默认导出的模块。

    ¥The values may be different from the original require() calls, especially for modules with default exports.

工作原理

¥How It Works

此插件会拦截选项中指定的依赖对 require() 的调用,并创建虚拟外观模块,该模块:

¥This plugin intercepts require() calls for dependencies specified in the option and creates virtual facade modules that:

  1. 使用 ESM import * as m from '...' 导入依赖

    ¥Import the dependency using ESM import * as m from '...'

  2. 使用 module.exports = m 重新导出以实现 CommonJS 兼容性

    ¥Re-export it using module.exports = m for CommonJS compatibility

  3. 用虚拟模块引用替换原始 require()

    ¥Replace the original require() with the virtual module reference

对于非外部 require() 调用,Rolldown 会自动封装它们并将其转换为 ESM 导入。

¥For non-external require() calls, Rolldown automatically wraps them and converts them into ESM imports.

js
// Input code
const react = require('react');

// Transformed output
const react = require('builtin:esm-external-require-react');

// Virtual module: builtin:esm-external-require-react
import * as m from 'react';
module.exports = m;