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

# Low-level plugins

These plugins are publicly exposed low-level building blocks that Rspack primarily uses to implement target presets, runtime templates, child compilers, and higher-level plugins.

:::tip Usage guidance
For most application builds, prefer the corresponding high-level configuration. Direct use is mainly intended for custom compilers, child compilers, and advanced integrations.
:::

Categories of low-level plugins:

- [environment](#environment)
- [entry](#entry)
- [output](#output)
- [loader](#loader)
- [module federation](#module-federation)
- [experiments](#experiments)

## environment

Plugins affecting the compiler environment and runtime target.

### ElectronTargetPlugin \{#electron-target-plugin}

```js
new rspack.electron.ElectronTargetPlugin(context);
```

`ElectronTargetPlugin` keeps Electron built-in modules external so Electron can load them at runtime. Pass `'main'`, `'preload'`, or `'renderer'` to externalize the additional modules available in that process.

The [`externalsPresets.electron`](/config/externals.md#externalspresetselectron), [`externalsPresets.electronMain`](/config/externals.md#externalspresetselectronmain), [`externalsPresets.electronRenderer`](/config/externals.md#externalspresetselectronrenderer), and [`externalsPresets.electronPreload`](/config/externals.md#externalspresetselectronpreload) options apply this plugin internally.

For a regular Electron application, prefer the corresponding [target](/config/target.md):

```js title="rspack.config.mjs"
export default {
  target: 'electron-main',
  entry: './src/main.js',
};
```

When configuring a child compiler directly, apply the plugin to that compiler:

```js
new compiler.rspack.electron.ElectronTargetPlugin('main').apply(childCompiler);
```

### NodeEnvironmentPlugin

```js
new rspack.node.NodeEnvironmentPlugin(options);
```

`NodeEnvironmentPlugin` installs infrastructure logging, a cached Node.js input file system, the Node.js `fs` module as the output file system, and a watch file system on a compiler. The `rspack()` API applies it automatically to the root compiler.

When a custom compiler needs its own Node.js file-system environment, pass its normalized infrastructure logging options and apply the plugin directly:

```js
new compiler.rspack.node.NodeEnvironmentPlugin({
  infrastructureLogging: childCompiler.options.infrastructureLogging,
}).apply(childCompiler);
```

This plugin configures compiler I/O and logging; it does not set the JavaScript runtime target. Use `NodeTargetPlugin` when Node.js built-in modules should remain external.

### NodeTargetPlugin \{#node-target-plugin}

```js
new rspack.node.NodeTargetPlugin();
```

`NodeTargetPlugin` keeps Node.js built-in modules and requests using the `node:` scheme external so the Node.js runtime loads them instead of Rspack bundling them. The [`externalsPresets.node`](/config/externals.md#externalspresetsnode) option applies this plugin internally.

For a regular Node.js application, prefer the `node` target:

```js title="rspack.config.mjs"
export default {
  target: 'node',
  entry: './src/index.js',
};
```

When configuring a child compiler directly, apply the plugin to that compiler:

```js
new compiler.rspack.node.NodeTargetPlugin().apply(childCompiler);
```

## entry

Plugins that add entry chunks to the compilation.

### DynamicEntryPlugin

```js
new rspack.DynamicEntryPlugin(context, entry);
```

`DynamicEntryPlugin` calls an entry function during every `make` event and adds the returned entries to the compilation. This allows the entry list to change between watch rebuilds.

The direct API receives normalized entry descriptions, so each `import` value is an array:

```js title="rspack.config.mjs"
import { rspack } from '@rspack/core';

const context = process.cwd();

export default {
  context,
  entry: {},
  plugins: [
    new rspack.DynamicEntryPlugin(context, async () => ({
      main: {
        import: ['./src/index.js'],
      },
    })),
  ],
};
```

For a regular build, prefer an [`entry` function](/config/entry.md#entry), which Rspack normalizes and passes to this plugin automatically.

### EntryOptionPlugin

```js
new rspack.EntryOptionPlugin();
```

`EntryOptionPlugin` handles the `entryOption` compiler hook. It applies an `EntryPlugin` for each static entry request or a `DynamicEntryPlugin` for a function entry. Rspack applies it automatically to the root compiler.

The static `applyEntryOption` helper is useful when adding normalized entries to a child compiler:

```js
const childOptions = compiler.rspack.config.getNormalizedRspackOptions({
  entry: {
    child: './src/child.js',
  },
});

compiler.rspack.EntryOptionPlugin.applyEntryOption(
  childCompiler,
  compiler.context,
  childOptions.entry,
);
```

## output

Plugins affecting generated modules, chunks, and runtime loading.

### EnableChunkLoadingPlugin \{#enable-chunk-loading-plugin}

```js
new rspack.javascript.EnableChunkLoadingPlugin(type);
```

`EnableChunkLoadingPlugin` enables the runtime modules required by a chunk-loading type. Rspack normally applies it for the types collected in [`output.enabledChunkLoadingTypes`](/config/output.md#outputenabledchunkloadingtypes).

The supported built-in types are `'jsonp'`, `'import-scripts'`, `'require'`, `'async-node'`, and `'import'`.

Direct application is useful when a dynamic entry selects a type that Rspack cannot discover while normalizing the configuration:

```js title="rspack.config.mjs"
import { rspack } from '@rspack/core';

export default {
  entry: () => ({
    main: {
      import: './src/index.js',
      chunkLoading: 'jsonp',
    },
  }),
  output: {
    chunkLoading: false,
  },
  plugins: [new rspack.javascript.EnableChunkLoadingPlugin('jsonp')],
};
```

For a custom chunk-loading implementation, call `EnableChunkLoadingPlugin.setEnabled(compiler, type)` after installing its runtime hooks. This method only registers the type; it does not implement chunk loading.

### EnableLibraryPlugin \{#enable-library-plugin}

```js
new rspack.library.EnableLibraryPlugin(type);
```

`EnableLibraryPlugin` registers a library output type with the compiler. Rspack normally applies it for the types collected in [`output.enabledLibraryTypes`](/config/output.md#outputenabledlibrarytypes).

The following dynamic entry selects the `'var'` library type and enables it explicitly because Rspack cannot inspect a function entry during configuration normalization:

```js title="src/index.js"
export const add = (a, b) => a + b;
```

```js title="rspack.config.mjs"
import { rspack } from '@rspack/core';

export default {
  entry: () => ({
    main: {
      import: './src/index.js',
      library: {
        name: 'MathLibrary',
        type: 'var',
      },
    },
  }),
  plugins: [new rspack.library.EnableLibraryPlugin('var')],
};
```

For a regular library build, prefer [`output.library`](/config/output.md#outputlibrary), which automatically enables its library type.

### EnableWasmLoadingPlugin \{#enable-wasm-loading-plugin}

```js
new rspack.wasm.EnableWasmLoadingPlugin(type);
```

`EnableWasmLoadingPlugin` enables the runtime modules required by a WebAssembly loading type. Rspack normally applies it for the types collected in [`output.enabledWasmLoadingTypes`](/config/output.md#outputenabledwasmloadingtypes).

The supported types are `'fetch'`, `'async-node'`, and `'universal'`.

The following example sets `output.wasmLoading` to `false` to disable automatic setup, then directly applies `EnableWasmLoadingPlugin` to install the `'fetch'` loading runtime:

```js title="src/index.js"
import { add } from './add.wasm';

console.log(add(1, 2));
```

```js title="rspack.config.mjs"
import { rspack } from '@rspack/core';

export default {
  target: 'web',
  entry: './src/index.js',
  experiments: {
    asyncWebAssembly: true,
  },
  output: {
    wasmLoading: false,
  },
  plugins: [new rspack.wasm.EnableWasmLoadingPlugin('fetch')],
};
```

For a regular build, prefer [`output.wasmLoading`](/config/output.md#outputwasmloading), which automatically enables the selected type.

### EvalDevToolModulePlugin

```js
new rspack.EvalDevToolModulePlugin(options);
```

`EvalDevToolModulePlugin` wraps each non-external JavaScript module in `eval` and appends a `sourceURL`, allowing browser developer tools to display the original module name. Setting `devtool: 'eval'` applies this plugin automatically.

The following configuration applies it directly and uses `dashboard` as the source URL namespace:

```js title="rspack.config.mjs"
import { rspack } from '@rspack/core';

export default {
  mode: 'development',
  devtool: false,
  plugins: [
    new rspack.EvalDevToolModulePlugin({
      namespace: 'dashboard',
    }),
  ],
};
```

The `moduleFilenameTemplate` and `sourceUrlComment` options can customize the generated module URL and comment format.

### FetchCompileAsyncWasmPlugin

```js
new rspack.web.FetchCompileAsyncWasmPlugin();
```

`FetchCompileAsyncWasmPlugin` adds the browser runtime that fetches and compiles asynchronous WebAssembly modules. `EnableWasmLoadingPlugin('fetch')` applies this implementation internally.

This example disables automatic WebAssembly loading setup and installs the fetch implementation directly:

```js title="src/index.js"
import { add } from './add.wasm';

console.log(add(1, 2));
```

```js title="rspack.config.mjs"
import { rspack } from '@rspack/core';

export default {
  target: 'web',
  entry: './src/index.js',
  experiments: {
    asyncWebAssembly: true,
  },
  output: {
    wasmLoading: false,
  },
  plugins: [new rspack.web.FetchCompileAsyncWasmPlugin()],
};
```

For a regular web build, prefer `output.wasmLoading: 'fetch'`, which enables the same runtime automatically.

### JsonpTemplatePlugin \{#jsonp-template-plugin}

```js
new rspack.web.JsonpTemplatePlugin();
```

`JsonpTemplatePlugin` configures browser output for child compilers. It sets [`output.chunkLoading`](/config/output.md#outputchunkloading) to `'jsonp'`, applies the [`'array-push'` chunk format](/config/output.md#outputchunkformat), and enables the required JSONP chunk-loading runtime.

The following browser entry creates an asynchronous chunk:

```js title="src/browser-child.js"
document.querySelector('button').addEventListener('click', async () => {
  const { message } = await import('./message.js');
  console.log(message);
});
```

```js title="src/message.js"
export const message = 'Hello from the child compiler';
```

This configuration creates a child compiler and applies `JsonpTemplatePlugin` directly:

```js title="rspack.config.mjs"
export default {
  target: 'web',
  entry: {},
  plugins: [
    (compiler) => {
      compiler.hooks.make.tapAsync(
        'BrowserChildCompiler',
        (compilation, callback) => {
          const childCompiler = compilation.createChildCompiler(
            'browser-child',
            {
              filename: 'browser-child.js',
              chunkFilename: '[name].browser-child.js',
            },
            [
              new compiler.rspack.web.JsonpTemplatePlugin(),
              new compiler.rspack.EntryPlugin(
                compiler.context,
                './src/browser-child.js',
                { name: 'browser-child' },
              ),
            ],
          );

          childCompiler.runAsChild((error) => callback(error));
        },
      );
    },
  ],
};
```

`JsonpTemplatePlugin` makes the child compiler emit array-push chunks and load asynchronous chunks by adding `script` elements to the page.

For a regular web build, prefer `target: 'web'`. It selects the `'array-push'` chunk format and `'jsonp'` chunk loading through Rspack's target defaults. Setting `output.chunkLoading: 'jsonp'` only selects the loading implementation; it does not apply `JsonpTemplatePlugin` or choose the chunk format.

### NodeTemplatePlugin \{#node-template-plugin}

```js
new rspack.node.NodeTemplatePlugin(options);
```

`NodeTemplatePlugin` configures Node.js output for child compilers. It applies the [`'commonjs'` chunk format](/config/output.md#outputchunkformat), sets [`output.chunkLoading`](/config/output.md#outputchunkloading) to `'require'` by default, and enables the required chunk-loading runtime.

#### asyncChunkLoading

- Type: `boolean`
- Default: `false`

When `asyncChunkLoading` is `true`, the plugin uses `'async-node'` chunk loading instead of `'require'`.

The following Node.js entry creates an asynchronous chunk:

```js title="src/node-child.js"
async function main() {
  const { run } = await import('./task.js');
  run();
}

main();
```

```js title="src/task.js"
export function run() {
  console.log('Task completed');
}
```

This configuration creates a child compiler and applies `NodeTemplatePlugin` directly:

```js title="rspack.config.mjs"
export default {
  target: 'node',
  entry: {},
  plugins: [
    (compiler) => {
      compiler.hooks.make.tapAsync(
        'NodeChildCompiler',
        (compilation, callback) => {
          const childCompiler = compilation.createChildCompiler(
            'node-child',
            {
              filename: 'node-child.js',
              chunkFilename: '[name].node-child.js',
            },
            [
              new compiler.rspack.node.NodeTemplatePlugin(),
              new compiler.rspack.EntryPlugin(
                compiler.context,
                './src/node-child.js',
                { name: 'node-child' },
              ),
            ],
          );

          childCompiler.runAsChild((error) => callback(error));
        },
      );
    },
  ],
};
```

`NodeTemplatePlugin` makes the child compiler emit CommonJS chunks and load asynchronous chunks with `require`.

For a regular Node.js build, prefer `target: 'node'`. It selects the `'commonjs'` chunk format and `'require'` chunk loading through Rspack's target defaults. Setting `output.chunkLoading: 'require'` only selects the loading implementation; it does not apply `NodeTemplatePlugin` or choose the chunk format.

### WebWorkerTemplatePlugin \{#web-worker-template-plugin}

```js
new rspack.webworker.WebWorkerTemplatePlugin();
```

`WebWorkerTemplatePlugin` configures Web Worker output for child compilers. It sets [`output.chunkLoading`](/config/output.md#outputchunkloading) to `'import-scripts'`, applies the [`'array-push'` chunk format](/config/output.md#outputchunkformat), and enables the required `importScripts` chunk-loading runtime.

The following worker creates an asynchronous chunk:

```js title="src/worker-child.js"
self.onmessage = async ({ data }) => {
  const { double } = await import('./math.js');
  self.postMessage(double(data));
};
```

```js title="src/math.js"
export const double = (value) => value * 2;
```

This configuration creates a child compiler and applies `WebWorkerTemplatePlugin` directly:

```js title="rspack.config.mjs"
export default {
  target: 'webworker',
  entry: {},
  plugins: [
    (compiler) => {
      compiler.hooks.make.tapAsync(
        'WorkerChildCompiler',
        (compilation, callback) => {
          const childCompiler = compilation.createChildCompiler(
            'worker-child',
            {
              filename: 'worker-child.js',
              chunkFilename: '[name].worker-child.js',
            },
            [
              new compiler.rspack.webworker.WebWorkerTemplatePlugin(),
              new compiler.rspack.EntryPlugin(
                compiler.context,
                './src/worker-child.js',
                { name: 'worker-child' },
              ),
            ],
          );

          childCompiler.runAsChild((error) => callback(error));
        },
      );
    },
  ],
};
```

`WebWorkerTemplatePlugin` makes the child compiler emit array-push chunks and load asynchronous chunks with `importScripts`.

For a regular Web Worker build, prefer `target: 'webworker'`. It selects the `'array-push'` chunk format and `'import-scripts'` chunk loading through Rspack's target defaults. Setting `output.chunkLoading: 'import-scripts'` only selects the loading implementation; it does not apply `WebWorkerTemplatePlugin` or choose the chunk format.

## loader

Plugins that customize the context in which loaders execute.

### LoaderOptionsPlugin

```js
new rspack.LoaderOptionsPlugin(options);
```

`LoaderOptionsPlugin` copies custom option fields onto the loader context for resources matching `test`, `include`, and `exclude`. The matching fields themselves are used only as filters and are not copied.

This loader reads a custom `message` property from its context:

```js title="loaders/message-loader.cjs"
module.exports = function () {
  return `export default ${JSON.stringify(this.message)};`;
};
```

The plugin provides that property only while processing `.message` files:

```js title="rspack.config.mjs"
import { rspack } from '@rspack/core';

export default {
  entry: './src/welcome.message',
  module: {
    rules: [
      {
        test: /\.message$/,
        use: './loaders/message-loader.cjs',
      },
    ],
  },
  plugins: [
    new rspack.LoaderOptionsPlugin({
      test: /\.message$/,
      message: 'Hello from the loader',
    }),
  ],
};
```

This plugin mainly supports loaders that read custom properties from `this`. New loaders should usually receive values through their own loader options.

### LoaderTargetPlugin

```js
new rspack.LoaderTargetPlugin(target);
```

`LoaderTargetPlugin` assigns `target` to `this.target` in every loader context. It is useful when a custom compiler needs loaders to observe a target that differs from the compiler's configured target.

The following loader replaces its input with the target it observes:

```js title="loaders/target-loader.cjs"
module.exports = function () {
  return `console.log(${JSON.stringify(this.target)});`;
};
```

Although the build target is `web`, this plugin makes the loader receive `'node'`:

```js title="rspack.config.mjs"
import { rspack } from '@rspack/core';

export default {
  target: 'web',
  entry: './src/index.js',
  module: {
    rules: [
      {
        test: /index\.js$/,
        use: './loaders/target-loader.cjs',
      },
    ],
  },
  plugins: [new rspack.LoaderTargetPlugin('node')],
};
```

For a regular build, prefer the top-level [`target`](/config/target.md) option.

## module federation

These plugins implement the `exposes`, `remotes`, and `shared` parts of Module Federation. For regular application builds, prefer [`ModuleFederationPlugin`](/plugins/module-federation-plugin.md), which configures these low-level plugins together.

### ContainerPlugin

```js
new rspack.container.ContainerPlugin(options);
```

`ContainerPlugin` creates a container entry that exposes local modules through the Module Federation `get` and `init` interface. It is the low-level implementation of the `exposes` option.

This configuration emits `remoteEntry.js` and exposes `src/Button.js` as `./Button`:

```js title="rspack.config.mjs"
import { container } from '@rspack/core';

export default {
  entry: {},
  plugins: [
    new container.ContainerPlugin({
      name: 'catalog',
      filename: 'remoteEntry.js',
      exposes: {
        './Button': './src/Button.js',
      },
    }),
  ],
};
```

### ContainerReferencePlugin

```js
new rspack.container.ContainerReferencePlugin(options);
```

`ContainerReferencePlugin` registers remote containers as externals and adds the runtime needed to load modules from them. It is the low-level implementation of the `remotes` option.

With the following configuration, an import such as `import('catalog/Button')` loads `./Button` from the remote container:

```js title="rspack.config.mjs"
import { container } from '@rspack/core';

export default {
  entry: './src/index.js',
  plugins: [
    new container.ContainerReferencePlugin({
      remoteType: 'script',
      remotes: {
        catalog: 'catalog@http://localhost:3001/remoteEntry.js',
      },
    }),
  ],
};
```

### ConsumeSharedPlugin

```js
new rspack.sharing.ConsumeSharedPlugin(options);
```

`ConsumeSharedPlugin` resolves configured module requests from a share scope. It can enforce version and singleton requirements and use a local module as a fallback when no suitable provider is available.

This example consumes `react` as a singleton from the default share scope and falls back to the locally installed package without checking its version:

```js title="rspack.config.mjs"
import { sharing } from '@rspack/core';

export default {
  entry: './src/index.js',
  plugins: [
    new sharing.ConsumeSharedPlugin({
      consumes: {
        react: {
          import: 'react',
          requiredVersion: false,
          singleton: true,
        },
      },
    }),
  ],
};
```

### ProvideSharedPlugin

```js
new rspack.sharing.ProvideSharedPlugin(options);
```

`ProvideSharedPlugin` registers local modules and their versions in a share scope so other builds can consume them. It is the provider half of the `shared` option.

The shorthand form below provides the locally installed `react` package under the `react` share key and infers its version from the package metadata:

```js title="rspack.config.mjs"
import { sharing } from '@rspack/core';

export default {
  plugins: [
    new sharing.ProvideSharedPlugin({
      provides: ['react'],
    }),
  ],
};
```

### SharePlugin

```js
new rspack.sharing.SharePlugin(options);
```

`SharePlugin` applies both `ConsumeSharedPlugin` and `ProvideSharedPlugin` for the same `shared` configuration. It is the low-level equivalent of `ModuleFederationPlugin`'s `shared` option.

This example provides the local `react` package as a fallback and consumes a singleton instance from the default share scope:

```js title="rspack.config.mjs"
import { sharing } from '@rspack/core';

export default {
  plugins: [
    new sharing.SharePlugin({
      enhanced: false,
      shared: {
        react: {
          requiredVersion: false,
          singleton: true,
        },
      },
    }),
  ],
};
```

### TreeShakingSharedPlugin \{#tree-shaking-shared-plugin}

```js
new rspack.sharing.TreeShakingSharedPlugin(options);
```


Stability: Experimental

`TreeShakingSharedPlugin` creates independent builds and optimizes exports for Module Federation shared dependencies. `ModuleFederationPlugin` applies it automatically when at least one `shared` dependency enables `treeShaking`.

#### Options

- `mfConfig`: The `ModuleFederationPluginOptions` used to configure the shared dependencies and output.
- `secondary`: Whether to perform a second tree-shaking pass during the independent build. The default is `false`.
- `onBuildAssets`: A callback invoked with the generated shared fallback assets.

Direct application is mainly intended for deployment integrations that perform a secondary build. It must be combined with a sharing plugin so `TreeShakingSharedPlugin` can collect the shared modules to build:

```js title="src/index.js"
import { add } from 'lodash-es';

console.log(add(1, 2));
```

```js title="rspack.config.mjs"
import { sharing } from '@rspack/core';

const shared = {
  'lodash-es': { treeShaking: { mode: 'server-calc' } },
};

export default {
  entry: './src/index.js',
  plugins: [
    new sharing.SharePlugin({
      enhanced: true,
      shared,
    }),
    new sharing.TreeShakingSharedPlugin({
      secondary: true,
      mfConfig: {
        name: 'app',
        shared,
        library: { type: 'var', name: 'App' },
      },
    }),
  ],
};
```

The plugin creates an independent build only for shared dependencies that enable `treeShaking` and retain a local implementation. Direct use does not generate Module Federation stats or manifest files. When `ModuleFederationPlugin` applies it internally with manifest generation enabled, the plugin writes the generated fallback asset information into those files.

## experiments

### RemoveDuplicateModulesPlugin

```js
new rspack.experiments.RemoveDuplicateModulesPlugin();
```


Stability: Experimental

`RemoveDuplicateModulesPlugin` finds modules that occur in the same set of multiple chunks and moves them into one reusable or newly created shared chunk. Rspack uses it internally for `modern-module` library output.

In this example, both entries import the same `src/shared.js` module. Disabling `splitChunks` makes `RemoveDuplicateModulesPlugin` responsible for extracting that duplicated module:

```js title="rspack.config.mjs"
import { rspack } from '@rspack/core';

export default {
  entry: {
    admin: './src/admin.js',
    store: './src/store.js',
  },
  optimization: {
    splitChunks: false,
  },
  plugins: [new rspack.experiments.RemoveDuplicateModulesPlugin()],
};
```


This page is adapted from [webpack documentation](https://webpack.js.org/plugins/internal-plugins/) under the [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), with modifications.

