website/docs/en/config/module-rules.mdx
import { ApiMeta, Stability } from '../../../components/ApiMeta'; import PropertyType from '@components/PropertyType'; import WebpackLicense from '@components/WebpackLicense';
<WebpackLicense from="https://webpack.docschina.org/configuration/module/" />(Rule | Falsy)[][]module.rules defines how Rspack processes different types of modules during the build.
It is an array of rules. Each rule is matched against a module's metadata when the module is resolved and created, such as its file path, file type, or query parameters. Once a rule matches, Rspack transforms or resolves the module according to the rule's configuration.
The most common use case is configuring loaders for different kinds of modules. For example, transforming TypeScript into browser-executable JavaScript, or handling stylesheets, images, and other assets.
By combining various matching conditions with specific processing logic, module.rules provides fine-grained control over how different modules are built.
For example, use the built-in swc-loader to handle files ending with .ts:
export default {
module: {
rules: [
{
test: /\.(?:js|mjs|ts)$/,
use: 'builtin:swc-loader',
options: {
// loader options...
},
},
],
},
};
Rule{}Rule defines the conditions for matching a module and the behavior of handling those modules.
Rule behavior
Defines the processing behavior of the corresponding matching module, e.g. :
rules[].use)rules[].type)rules[].resolve)type Condition =
| string
| RegExp
| ((value: string) => boolean)
| Conditions
| LogicalConditions;
type Conditions = Condition[];
type LogicalConditions = {
and?: Conditions;
or?: Conditions;
not?: Condition;
};
Defines a module's match conditions, common matches are resource, resourceQuery, include, and exclude.
Example: app.js imports ./image.png?inline#foo:
resource is /path/to/image.png, and will match against with rules[].resource ConditionresourceQuery is ?inline, and will match against with rules[].resourceQuery ConditionresourceFragment is #foo, and will match against with rules[].resourceFragment ConditionCondition represents the form of matching a given input, and it supports the following types:
String: Given an input, the match is successful when the input string satisfies startsWith. Note: You can think of it as input.startsWith(condition).RegExp: Given an input, the match is successful when the input string satisfies the regular expression. Note: You can think of it as condition.test(input).Condition[]: A list of conditions. At least one of the Conditions must match.LogicalConditions: All Conditions must match.
{ and: Condition[] }: All Conditions must match.{ or: Condition[] }: At least one of the Conditions must match.{ not: Condition }: All Conditions must NOT match.(value: string) => boolean: If it's called with the input and return a truthy value, the match is succeeds.Nested Rule can be specified under the properties rules[].rules and rules[].oneOf, These rules are evaluated only when the parent Rule condition matches. Each nested rule can contain its own conditions.
The order of evaluation is as follows:
rules[].rulesrules[].oneOfConditionundefinedExcludes all modules that match this condition and will match against the absolute path of the resource (without query and fragment). This option cannot be present together with rules[].resource.
export default {
module: {
rules: [
{
exclude: /\.js$/,
},
],
},
};
ConditionundefinedMatches all modules that match this condition against the absolute path of the resource (without query and fragment). This option cannot be present together with rules[].resource.
export default {
module: {
rules: [
{
include: /\.js$/,
},
],
},
};
ConditionundefinedMatches all modules that match this resource, and will match against Resource (the absolute path without query and fragment). This option cannot be present together with rules[].test.
export default {
module: {
rules: [
{
resource: /\.js$/,
},
],
},
};
ConditionundefinedMatches all modules that match this resource against the Resource's query. Note: Containing ?, when rules[].resourceQuery is ?raw, it will match the resource request of foo?raw
export default {
module: {
rules: [
{
test: /\.css$/,
resourceQuery: /inline/,
type: 'asset/inline',
},
],
},
};
ConditionundefinedMatches all modules that match this resource against the Resource's fragment. Note: Containing #, when rules[].resourceFragment is #abc, it will match the resource request of foo#abc
export default {
module: {
rules: [
{
resourceFragment: '#abc',
},
],
},
};
ConditionundefinedMatches all modules that match this resource, and will match against Resource (the absolute path without query and fragment). This option cannot be present together with rules[].resource.
export default {
module: {
rules: [
{
test: /\.js$/,
},
],
},
};
ConditionundefinedMatches all modules that match this resource, and will match against Resource (the absolute path without query and fragment) of the module that issued the current module.
export default {
module: {
rules: [
{
issuer: /\.js$/,
},
],
},
};
stringundefinedMatches all modules that match this resource, and will match against layer of the module that issued the current module.
For more information about layers, see the Layer guide.
A basic example:
export default {
module: {
rules: [
{
issuerLayer: 'other-layer',
},
],
},
};
A more complex example is the combination with entry options to build modern and legacy bundles at the same time:
export default {
entry: {
index: {
import: './src/index.js',
layer: 'modern',
},
'index-legacy': {
import: './src/index.js',
layer: 'legacy',
},
},
module: {
rules: [
{
test: /\.js$/,
issuerLayer: 'modern',
options: {
env: { targets: ['chrome >= 100'] },
},
},
{
test: /\.js$/,
issuerLayer: 'legacy',
options: {
env: { targets: ['ie >= 11'] },
},
},
],
},
};
ConditionundefinedMatches all modules that match this resource, and will match against the category of the dependency that introduced the current module, for example:
esm for import and import()cjs for require()url for new URL() and url().For example, match all .js files, but exclude url type dependencies (such as new URL('./path/to/foo.js', import.meta.url)):
export default {
module: {
rules: [
{
test: /\.js$/,
dependency: { not: 'url' },
},
],
},
};
ConditionundefinedMatches all modules that match this resource, and will match against the Resource's scheme.
For example, you can treat the inline data uri resource as a separate resource with the following configuration:
export default {
module: {
rules: [
{
scheme: 'data',
type: 'asset/resource',
},
],
},
};
ConditionundefinedMatches modules based on MIME type instead of file extension. It's primarily useful for data URI module.
export default {
module: {
rules: [
{
mimetype: 'text/javascript',
use: [
// ...
],
},
],
},
};
{ [key: string]: Condition }undefineddescriptionData option allows you to match values of properties in the description file, typically package.json, to determine which modules a rule should apply to. This is a useful way to apply rules to specific modules based on metadata found in their package.json.
The object keys in descriptionData correspond to keys in the module's package.json, such as name, version, etc. Each key should be associated with a Condition for matching the package.json data.
For example, below we are applying the rule only to JavaScript resources with 'rspack' string included in their package.json name.
export default {
module: {
rules: [
{
test: /\.js$/,
include: /node_modules/,
descriptionData: {
name: (packageJsonName) => packageJsonName.includes('rspack'),
},
// additional rule options...
},
],
},
};
{ [key: string]: Condition }undefinedwith can be used in conjunction with import attributes.
For example, the following configuration will match { type: "url" } and will change the type of the matched modules to "asset/resource":
export default {
module: {
rules: [
{
with: { type: 'url' },
type: 'asset/resource',
},
],
},
};
The following import will match:
import url from './data' with { type: 'url' };
import('./data', { with: { type: 'url' } });
It should be noted that in order for Rspack to properly match the with syntax, when you use builtin:swc-loader, you need to manually enable the keepImportAttributes configuration to preserve import attributes:
export default {
module: {
rules: [
{
with: { type: 'url' },
type: 'asset/resource',
},
{
test: /\.(?:js|mjs|ts)$/,
exclude: [/node_modules/],
loader: 'builtin:swc-loader',
options: {
detectSyntax: 'auto',
jsc: {
experimental: {
+ keepImportAttributes: true,
},
},
},
type: 'javascript/auto',
},
],
},
};
rules[].loader is a shortcut to rules[].use: [ { loader } ]. See rules[].use for details.
For example, use the built-in swc-loader to compile TypeScript files:
export default {
module: {
rules: [
{
test: /\.(?:js|mjs|ts)$/,
loader: 'builtin:swc-loader',
},
],
},
};
rules[].options is a shortcut to rules[].use: [ { options } ]. See rules[].use for details.
For example, pass options to the swc-loader:
export default {
module: {
rules: [
{
test: /\.ts$/,
loader: 'builtin:swc-loader',
options: {
detectSyntax: 'auto',
},
},
],
},
};
Object{}Parser options for the specific modules that matched by the rule conditions, this will override the parser options in module.parser.
export default {
module: {
rules: [
{
test: /\.css/,
parser: {
namedExports: false,
},
type: 'css/module',
},
],
},
};
For specific parser options and the corresponding module type, you can refer to module.parser.
Object{}Generator options for the specific modules that matched by the rule conditions, this will override the parser options in module.generator.
export default {
module: {
rules: [
{
test: /\.png/,
generator: {
filename: '[contenthash][ext]',
},
type: 'asset',
},
],
},
};
For specific generator options and the corresponding module type, you can refer to module.generator.
booleanFlag the module for side effects, this will affect the result of Tree Shaking.
export default {
module: {
rules: [
{
test: /foo\.js$/,
sideEffects: false,
},
],
},
};
Specifies the category of the loader. When not specified, it defaults to normal loader.
There is also an additional category "inlined loader" which are loaders applied inline of the import/require.
When specified as 'pre', the loader will execute before all other loaders.
export default {
module: {
rules: [
{
test: /\.js$/,
enforce: 'pre',
loader: 'my-pre-loader',
},
],
},
};
When specified as 'post', the loader will execute after all other loaders.
export default {
module: {
rules: [
{
test: /\.js$/,
enforce: 'post',
loader: 'my-post-loader',
},
],
},
};
There are two phases that all loaders enter one after the other:
pitch method on loaders is called in the order post, inline, normal, pre. See Pitching Loader for details.pre, normal, inline, post. Transformation on the source code of a module happens in this phase.type RuleType =
| 'asset'
| 'css'
| 'css/auto'
| 'css/module'
| 'javascript/auto'
| 'javascript/dynamic'
| 'javascript/esm'
| 'json';
Used to mark the type of the matching module, which affects how the module is handled by Rspack's built-in processing.
By default, Rspack will determine the type of the module based on the file extension. For example:
.js files will be treated as javascript/auto modules..mjs files, as well as .js files in packages with type="module" in package.json, will be treated as javascript/esm modules..json files will be treated as json modules..css files will be treated as css/auto modules.For example, if you want to load a .json file through a custom loader, you'd need to set the type to javascript/auto to bypass Rspack's built-in JSON importing.
export default {
module: {
rules: [
{
test: /\.json$/,
type: 'javascript/auto',
loader: 'custom-json-loader',
},
],
},
};
The meanings of all type options are as follows:
'javascript/auto': JavaScript modules. Rspack automatically determines the module type based on file content, providing the best compatibility.'javascript/esm': JavaScript modules, treated as strict ES modules.'javascript/dynamic': JavaScript modules, treated as Script.'json': JSON data module, see JSON.'css' | 'css/module' | 'css/auto': CSS module, see Built-in CSS support.'asset' | 'asset/source' | 'asset/resource' | 'asset/inline' | 'asset/bytes': Asset module, see Asset Module.stringUsed to mark the layer of the matching module. A group of modules could be united in one layer which could then be used in split chunks, stats or entry options.
For more information about layers, see the Layer guide.
export default {
module: {
rules: [
{
test: /\.js$/,
layer: 'layer-name',
},
],
},
};
type RuleSetUse =
| RuleSetUseItem[]
| RuleSetUseItem
| ((ctx: RawFuncUseCtx) => RuleSetUseItem[]);
type RuleSetUseItem = { loader: string; options: Record<string, any> } | string;
interface RawFuncUseCtx {
resource?: string;
realResource?: string;
resourceQuery?: string;
issuer?: string;
}
An array to pass the Loader package name and its options. string[] e.g.: use: ['svgr-loader'] is shorthand for use: [ { loader: 'svgr-loader' } ].
Loaders will be executed in right-to-left order.
export default {
module: {
rules: [
{
use: [
'svgr-loader',
{
loader: 'svgo-loader',
options: {
configFile: false,
},
},
],
},
],
},
};
A function can also be used:
export default {
module: {
rules: [
{
test: /\.svg$/,
type: 'asset',
use: (info) => [
{
loader: 'svgo-loader',
options: {
plugins: [
{
cleanupIDs: { prefix: basename(info.resource) },
},
],
},
},
],
},
],
},
};
booleanfalseControls whether a given loader should run in worker threads for parallel execution. Loaders marked with parallel are scheduled across multiple threads, reducing pressure on the main thread and improving overall build performance.
true, the loader runs in a worker. Rspack automatically selects an appropriate number of worker threads.{ maxWorkers }, you can explicitly define the maximum number of workers to use.false or omitted, the loader runs on the main thread.For example, enabling parallel execution for less-loader:
export default {
module: {
rules: [
{
test: /\.less$/,
use: [
{
loader: 'less-loader',
parallel: true,
options: {
// loader options
},
},
],
},
],
},
};
When multiple loaders within the same rule have parallel enabled, Rspack executes them sequentially inside the same worker until it encounters a non-parallel loader or a Rust-implemented builtin loader. This preserves loader order while maximizing parallel efficiency.
:::tip
LoaderContext._compilation, LoaderContext._compiler, LoaderContext._module are not supported.:::
Set specific module resolve options based on the matching modules.
export default {
module: {
rules: [
{
test: /\.css$/,
resolve: {
preferRelative: true,
},
},
],
},
};
undefinedA kind of Nested Rule, an array of Rules that is also used when the parent Rule matches.
export default {
module: {
rules: [
{
test: /\.css$/,
// When a CSS file is matched, continue to use these nested rules
rules: [
{
// Handle CSS files with "?raw" query
resourceQuery: /raw/,
type: 'asset/source',
},
{
// Handle normal CSS files
resourceQuery: {
not: /raw/,
},
type: 'css/auto',
},
],
},
],
},
};
undefinedA kind of Nested Rule, an array of Rules from which only the first matching Rule is used when the parent Rule matches.
export default {
module: {
rules: [
{
test: /\.(png|jpg)$/i,
oneOf: [
{
// Handle images with "?raw" query
resourceQuery: /raw/,
type: 'asset/source',
},
{
// Otherwise, output as a separate file
type: 'asset/resource',
},
],
},
],
},
};
booleanfalseExtracts existing source map data from files (from their //# sourceMappingURL comment), useful for preserving the source maps of third-party libraries.
export default {
module: {
rules: [
{
test: /\.m?js$/,
extractSourceMap: true,
},
],
},
};