close

处理三方依赖

本节介绍如何在 bundle 模式下处理三方依赖。

通常,项目所需的三方依赖可以通过包管理器的 install 命令安装。安装成功后,它们通常会出现在项目的 package.json 文件中的 dependenciesdevDependencies 字段下。

package.json
{
  "dependencies": {},
  "devDependencies": {}
}

dependencies 字段下的依赖通常来说是这个包运行所需的依赖,如果这些三方依赖声明在 devDependencies 字段下,那么在生产运行时会出现缺失依赖。

除了 dependencies 字段,peerDependencies 也可以声明在生产环境中需要的依赖,但它更强调这些依赖在项目运行时的存在,类似于插件机制。

三方依赖的默认处理

默认情况下,当生成 CJS 或 ESM 产物时,dependenciesoptionalDependenciespeerDependencies 字段下的三方依赖不会被 Rslib 打包。

这是因为在 npm 包安装时,其 dependencies 也会被安装。通过不打包 dependencies,可以减少包的体积。

如果需要打包某些依赖,建议将它们从 dependencies 移动到 devDependencies,这相当于预打包依赖,并减少依赖安装的体积。

示例

如果项目依赖了 foo

package.json
{
  "dependencies": {
    "foo": "^1.0.0"
  },
  // 或
  "peerDependencies": {
    "foo": "^1.0.0"
  }
}

当在源代码中使用 foo 依赖时:

src/index.ts
import foo from 'foo';
console.info(foo);

此时产物中不会包含 foo 的代码:

dist/index.js
import foo from 'foo';
console.info(foo);

自定义三方依赖处理

Rslib 主要通过 output.autoExternaloutput.externals 控制三方依赖是否被打包。

覆盖默认自动 external 行为

对于 ESM 和 CJS 的 bundle 产物,Rslib 默认启用 output.autoExternal,会自动 external dependenciesoptionalDependenciespeerDependencies 中声明的依赖。

如果希望这些依赖被打包进产物,可以禁用自动 external:

export default defineConfig({
  lib: [
    {
      output: {
        autoExternal: false,
      },
    },
  ],
});

如果只想调整某几类依赖,可以使用对象形式:

export default defineConfig({
  lib: [
    {
      output: {
        autoExternal: {
          dependencies: true,
          optionalDependencies: true,
          peerDependencies: true,
          devDependencies: false,
        },
      },
    },
  ],
});

如果只想让少数依赖不被自动 external,可以使用 exclude。被排除的依赖及其子路径会被打包进产物:

export default defineConfig({
  lib: [
    {
      output: {
        autoExternal: {
          exclude: ['react', /^@scope\//],
        },
      },
    },
  ],
});

外部化指定 import

当你需要指定某些 import 不被 Rslib 打包,或需要改变 external 后的请求路径时,可以使用 output.externals

数组形式适合保留原始请求路径:

export default defineConfig({
  lib: [
    {
      output: {
        externals: ['react', 'react/jsx-runtime'],
      },
    },
  ],
});

对象形式可以指定 external 后的请求路径,常用于给 external 改名:

export default defineConfig({
  lib: [
    {
      output: {
        externals: {
          react: 'react-18',
          'react/jsx-runtime': 'react-18/jsx-runtime',
        },
      },
    },
  ],
});

react/jsx-runtime 这类子路径 import 需要单独处理。只配置 react 不代表 react/jsx-runtime 也会使用相同的 external 规则。

如果要匹配一组 import,可以使用正则:

export default defineConfig({
  lib: [
    {
      output: {
        externals: [/^react($|\/)/],
      },
    },
  ],
});

配置更复杂的 external 规则

如果需要根据请求来源、上下文等信息决定是否 external,可以通过 tools.rspack 配置 Rspack 的 externals

export default defineConfig({
  lib: [
    {
      tools: {
        rspack: {
          externals: [
            ({ request }, callback) => {
              if (request?.startsWith('react')) {
                callback(null, request);
                return;
              }

              callback();
            },
          ],
        },
      },
    },
  ],
});

大多数场景优先使用 output.autoExternaloutput.externals。只有在需要更复杂的 Rspack external 能力时,才建议使用 tools.rspack.externals。更多用法可参考 Rspack 的 Externals 文档。