close
  • English
  • Handle third-party dependencies

    This section introduces how to handle third-party dependencies in bundle mode.

    Generally, third-party dependencies required by a project can be installed via the install command in the package manager. After the third-party dependencies are successfully installed, they will generally appear under dependencies and devDependencies in the project package.json.

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

    Dependencies under "dependencies" are generally required for the package in runtime, and if these third-party dependencies are declared under "devDependencies", then there will be missing dependencies in production runtime.

    In addition to "dependencies", "peerDependencies"can also declare dependencies that are needed in the production environment, but it puts more emphasis on the existence of these dependencies declared by "peerDependencies" in the project's runtime environment, similar to the plugin mechanism.

    Default handling of third-party dependencies

    By default, when generating CJS or ESM outputs, third-party dependencies under "dependencies", "optionalDependencies" and "peerDependencies" are not bundled by Rslib.

    This is because when the npm package is installed, its "dependencies" will also be installed. By not packaging "dependencies", you can reduce the size of the package product.

    If you need to package some dependencies, it is recommended to move them from "dependencies" to "devDependencies", which is equivalent to prebundle the dependencies and reduces the size of the dependency installation.

    The following example assumes that the project depends on foo:

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

    When the foo dependency is used in the source code:

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

    The foo package will not be bundled into the output:

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

    If you want to modify the default processing, you can use the following API:

    Customize third-party dependency handling

    Rslib mainly uses output.autoExternal and output.externals to control whether third-party dependencies are bundled.

    Configure autoExternal

    To override the behavior of output.autoExternal described above and bundle these dependencies, set it to false:

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

    If you only want to adjust certain dependency types, use the object form:

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

    Use exclude to exclude specific packages from the external rules auto-generated by output.autoExternal. If a package is excluded, its subpath imports will not be externalized either:

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

    Configure externals

    Use output.externals when you need to specify modules that should not be bundled by Rslib, or when you need to change the request path after externalization.

    The array form is useful when you want to keep the original request paths:

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

    The object form can specify the request path after externalization, commonly used to rename externalized modules:

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

    Subpath imports such as react/jsx-runtime need to be handled separately. Configuring only react does not mean react/jsx-runtime will use the same external rule.

    If you want to match a group of modules, use a regular expression:

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

    For complex scenarios where you need to decide whether to externalize a module based on the request issuer or context, configure Rspack's externals via tools.rspack:

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

    For more details, see the Rspack Externals documentation.