--- url: /guide/start/introduction.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Introduction Rspack (pronounced as `/'ɑrespæk/` , ) is a fast Rust-based bundler for the web.  It modernizes the webpack API to  enable seamless replacement of webpack while  delivering lightning-fast build speeds. ## Why Rspack? Rspack was initially created to solve performance problems encountered at ByteDance, a tech company that maintains many large monolithic app projects with complex bundling requirements. Production build times had grown to ten minutes or even half an hour in some cases, and cold start times could exceed several minutes. After experimenting with many bundlers and optimization ideas, a common set of requirements emerged: - **Dev mode startup performance.** `npm run dev` is a command that developers may invoke many times per hour. Engineering productivity suffers if startup time exceeds 10-15 seconds. - **Fast builds.** `npm run build` is used in CI/CD pipelines and directly impacts merging productivity and application delivery time. Large applications may spend 20-30 minutes running these pipelines, and bundling time is often a major contributor. - **Flexible configuration.** From experimenting with various popular bundlers, we found that one-size-fits-all configurations encountered many problems when trying to accommodate real world projects. A major advantage of webpack is its flexibility and ease of accommodating customized requirements for each project. That same flexibility means legacy projects often face steep migration costs when moving away from webpack. - **Production optimization capabilities.** All of the existing bundling solutions also had various limitations when optimizing for a production environment, such as insufficiently fine-grained code splitting. Rspack has an opportunity to rethink these optimizations from the ground up, leveraging Rust-specific features such as multithreading. ## Current status of Rspack As of August 2024, we have released [Rspack 1.0](/blog/announcing-1-0.md), which we consider production-ready because it covers most of webpack's APIs and features. Rspack is currently compatible with almost all loaders in the community. For the 50 most downloaded [webpack plugins](/plugins/community-plugin-compatibility.md), more than 85% can be used in Rspack or have an alternative. :::tip Learn more - See [Rspack blogs](/blog/index.md) for the latest updates on Rspack. - See [Roadmap](/misc/planning/roadmap.md) for the future plans of Rspack. ::: ## Comparisons with other tools ### Compared with webpack [webpack](https://webpack.js.org/) is perhaps the most mature modern bundler, with an active ecosystem, flexible configuration, and rich features. - **Rust language efficiency:** webpack's competitors frequently challenge it based on performance, especially for larger projects. Rspack solves this using the Rust language, which was specifically designed to prioritize performance, topping benchmarks for both speed and memory management. Rust also provides many compiler safeguards to avoid common pitfalls of other native languages such as C++. - **Highly parallelized architecture:** webpack is limited by JavaScript's weak support for multithreading. By contrast, Rspack's native code takes full advantage of modern multi-core CPUs. - **Built-in implementations of essential bundling features:** webpack's hook system famously enables a vast landscape of loaders and plugins contributed by the community. Unfortunately these third-party packages can frequently lead to performance bottlenecks, sometimes because the authors did not have deep knowledge of webpack internals, and sometimes because the hook system by nature limits how algorithms can interact. Rspack provides built-in plugins for key features to improve performance. - **Optimized hot module replacement (HMR):** No matter how large your project is, ensuring a great experience for HMR places even steeper demands on build times than ordinary bundling. Rspack incorporates a specialized incremental compilation strategy to address this requirement. ### Compared with Vite If you are looking for an out-of-the-box development experience similar to Vite, we recommend using [Rsbuild](https://rsbuild.rs/), a build tool powered by Rspack. See [Rsbuild's comparison with Vite](https://rsbuild.rs/guide/start/#vite) to learn about their differences. ### Compared with esbuild [esbuild](https://esbuild.github.io/) achieves very good performance by implementing nearly all operations in Golang except for some JavaScript plugins. However, esbuild's feature set is not as complete as webpack, for example missing HMR and [optimization.splitChunks](/config/optimization.md#optimizationsplitchunks) features. ### Compared with Turbopack Turbopack is implemented in Rust like Rspack, but Turbopack started over with a redesigned architecture and configuration. This brings some benefits, but presents a steeper migration cost for projects that rely on webpack and its extensive ecosystem. ### Compared with Rollup Rollup is built around ES modules and supports multiple output formats. Rspack covers a broader range of build scenarios, including ESM and CJS library outputs as well as application bundles, while continuously improving build performance and memory usage. ### Compared with Parcel The overall architecture of Rspack shares many similarities with [Parcel](https://parceljs.org/). For example, both treat CSS assets as built-in supported modules and both support filter-based transformers. However, Parcel focuses more on out-of-the-box usability, while Rspack focuses more on providing flexible configuration for higher-level frameworks and tools. Parcel introduced features like the Unified Graph and built-in HTML support. Rspack also plans to support these features in the future. ## Online example Try Rspack online with the [Rsbuild StackBlitz example](https://stackblitz.com/~/github.com/rstackjs/rsbuild-stackblitz-example). ## Next steps Please read [Quick start](/guide/start/quick-start.md) to start using Rspack. Welcome to the [GitHub Discussions](https://github.com/web-infra-dev/rspack/discussions) and [Discord](https://discord.gg/sYK4QjyZ4V) to communicate with us. --- url: /guide/start/quick-start.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Quick start Get up to speed quickly with a new Rspack based project. - [Create a new project](#create-a-new-project): Use the CLI to create a brand-new Rspack or Rsbuild project. - [Migrating from existing projects](#migrating-from-existing-projects): Migrate from a webpack-based project to Rspack. ## Ecosystem As a low-level bundler, Rspack has a rich ecosystem that includes various frameworks, tools, and solutions. These ecosystem projects cover different aspects from frameworks to development tools, meeting diverse development needs across scenarios and providing an out-of-the-box experience. See the [Ecosystem](/guide/start/ecosystem.md) page to explore these ecosystem projects. ## Environment preparation Rspack supports using [Node.js](https://nodejs.org/), [Deno](https://deno.com/), or [Bun](https://bun.sh/) as the JavaScript runtime. You can refer to the following installation guides and choose one runtime: - [Install Node.js](https://nodejs.org/en/download) - [Install Bun](https://bun.com/docs/installation) - [Install Deno](https://docs.deno.com/runtime/getting_started/installation/) :::tip Version requirements - Rspack v2 requires Node.js version 20.19+, 22.12+. - Rspack v1 requires Node.js 18.12.0 or higher. ::: :::details For unsupported platforms If you are using a niche platform, Rspack may not provide native support for it. In this case, please manually install `@rspack/binding-wasm32-wasi` as a fallback. The Wasm build is compatible with most platforms. Currently supported platforms: - `darwin-arm64` - `darwin-x64` - `linux-arm64-gnu` - `linux-arm64-musl` - `linux-riscv64-gnu` - `linux-riscv64-musl` - `linux-ppc64-gnu` - `linux-s390x-gnu` - `linux-x64-gnu` - `linux-x64-musl` - `win32-arm64-msvc` - `win32-ia32-msvc` - `win32-x64-msvc` ::: ## Create a new project ### Using Rsbuild Rsbuild is a high-performance build tool powered by Rspack and developed by the Rspack team. It provides a set of thoughtfully designed default build configs, offering an out-of-the-box development experience and can fully unleash the performance advantages of Rspack. We recommend using [Rsbuild](https://rsbuild.rs/) to create new projects, simply run the following command: ```sh [npm] npm create rsbuild@latest ``` ```sh [yarn] yarn create rsbuild ``` ```sh [pnpm] pnpm create rsbuild@latest ``` ```sh [bun] bun create rsbuild@latest ``` ```sh [deno] deno init --npm rsbuild@latest ``` > For more information, refer to [Rsbuild - Quick start](https://rsbuild.rs/guide/start/quick-start). ### Using Rspack CLI Rspack CLI is a tool comparable to webpack CLI, offering the basic `serve` and `build` commands. Run the following command to create an Rspack CLI project: ```sh [npm] npm create rspack@latest ``` ```sh [yarn] yarn create rspack ``` ```sh [pnpm] pnpm create rspack@latest ``` ```sh [bun] bun create rspack@latest ``` ```sh [deno] deno init --npm rspack@latest ``` Then follow the prompts in your terminal. ### Non-interactive mode [create-rspack](https://www.npmjs.com/package/create-rspack) and [create-rsbuild](https://www.npmjs.com/package/create-rsbuild) support a non-interactive mode through command-line options. This mode lets you skip all prompts and create a project directly, which is useful for scripts, CI, and coding agents. For example, the following command creates a React app in the `my-app` directory: ```bash # Rspack CLI npx -y create-rspack --dir my-app --template react # Rsbuild npx -y create-rsbuild --dir my-app --template react # Using abbreviations npx -y create-rsbuild -d my-app -t react ``` ## Manual installation Start by creating a project directory and generating an npm \`package.json': ```bash mkdir rspack-demo cd rspack-demo npm init -y ``` Then installing [@rspack/core](https://www.npmjs.com/package/@rspack/core) and [@rspack/cli](https://www.npmjs.com/package/@rspack/cli) as dev dependencies: ```sh [npm] npm add @rspack/core @rspack/cli -D ``` ```sh [yarn] yarn add @rspack/core @rspack/cli -D ``` ```sh [pnpm] pnpm add @rspack/core @rspack/cli -D ``` ```sh [bun] bun add @rspack/core @rspack/cli -D ``` ```sh [deno] deno add npm:@rspack/core npm:@rspack/cli -D ``` Update your build scripts to use Rspack CLI: ```js title="package.json" { "scripts": { "dev": "rspack dev", "build": "rspack build", "preview": "rspack preview" } } ``` Next, see [Configure Rspack](/config/index.md) to learn about how to configure Rspack. ## Migrating from existing projects If you need to migrate from an existing project to Rspack, you can refer to the following guides: - [Migrating from webpack to Rspack](/guide/migration/webpack.md) - [Migrating from webpack to Rsbuild](https://rsbuild.rs/guide/migration/webpack) - [Migrating from Create React App to Rsbuild](https://rsbuild.rs/guide/migration/cra) - [Migrating from Vue CLI to Rsbuild](https://rsbuild.rs/guide/migration/vue-cli) - [Migrating from Vite to Rsbuild](https://rsbuild.rs/guide/migration/vite) - [Migrating from Tsup to Rslib](https://rslib.rs/guide/migration/tsup) - [Migrating from Storybook](/guide/migration/storybook.md) ## Install canary version When you need to test or verify the features of Rspack that are not yet released to the stable version, you may need to use the canary version. The canary version of Rspack has a `-canary` suffix in the package scope. For example, the canary package name of `@rspack/core` is `@rspack-canary/core`. To use these versions, you can configure the overrides of the package manager (npm/yarn/pnpm/bun). Here is an example of using pnpm overrides: ```json title="package.json" { "pnpm": { "overrides": { "@rspack/core": "npm:@rspack-canary/core@latest" }, "peerDependencyRules": { "allowAny": ["@rspack/*"] } } } ``` Rspack community also provides [install-rspack](https://github.com/rstackjs/install-rspack) tool to easily install canary version: ```shell npx install-rspack --version latest # Install the latest version npx install-rspack --version canary # Install the canary version npx install-rspack --version 1.0.0-canary-d614005-20250101082730 # Install the specified canary version ``` --- url: /guide/start/ecosystem.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Ecosystem ## Rstack Rspack is part of Rstack, the fast, unified JavaScript toolchain for developers and agents. ### Rsbuild Build tool [Rsbuild](https://github.com/web-infra-dev/rsbuild) is a high-performance build tool powered by Rspack. It provides a set of thoughtfully designed default build configs, offering an out-of-the-box development experience and can fully unleash the performance advantages of Rspack. ### Rslib Library development tool [Rslib](https://github.com/web-infra-dev/rslib) is a library development tool based on Rsbuild, which reuses the carefully designed build configuration and plugin system of Rsbuild. It allows developers to create JavaScript libraries in a simple and intuitive way. ### Rspress Static site generator React [Rspress](https://github.com/web-infra-dev/rspress) is a static site generator based on Rsbuild, React and MDX. It comes with a default documentation theme, and you can quickly build a documentation site with Rspress. You can also customize the theme to meet your personalized static site needs, such as blog sites, product homepages, etc. ### Rsdoctor Build analyzer [Rsdoctor](/guide/diagnostics/use-rsdoctor.md) is a build analyzer that can visually display the build process, such as compilation time, code changes before and after compilation, module reference relationships, duplicate modules, etc. ### Rstest Testing framework [Rstest](/guide/integrations/rstest.md) is a testing framework powered by Rspack. It delivers comprehensive, first-class support for the Rspack ecosystem, enabling seamless integration into existing Rspack-based projects. ### Rslint Linter [Rslint](https://github.com/web-infra-dev/rslint) is a high-performance JavaScript and TypeScript linter based on typescript-go. It offers strong compatibility with the ESLint and TypeScript-ESLint ecosystem, allowing for seamless replacement, and provides lightning-fast linting speeds. ## Community integrations ### Angular Rspack Build tool Angular [Angular Rspack](https://nx.dev/docs/technologies/angular/angular-rspack) is a set of plugins and tools to make it easy and straightforward to build Angular applications with Rspack and Rsbuild. ### Docusaurus Static site generator React [Docusaurus](https://docusaurus.io/) is a static site generator for building, deploying, and maintaining open source project websites easily. Docusaurus supports Rspack as the bundler since v3.6, see [Docusaurus Faster](https://docusaurus.io/blog/releases/3.6#docusaurus-faster) for details. ### Modern.js Web framework React [Modern.js](https://modernjs.dev/) is a Rsbuild-based progressive React framework that supports nested routes, SSR, and provides out-of-the-box CSS solutions such as styled components and Tailwind CSS. ### Meteor Web framework [Meteor](https://www.meteor.com/) is a full-stack JavaScript platform for developing modern web and mobile applications. [Meteor 3.4](https://blog.meteor.com/meteor-3-4-is-out-rspack-integration-4x-faster-builds-8x-smaller-bundles-and-extended-bundler-36600fb45976) provides an Rspack integration with faster builds and smaller bundles. ### Next.js Web framework React [Next.js](https://nextjs.org/) is a React framework for building full-stack web applications. You use React Components to build user interfaces, and Next.js for additional features and optimizations. Rspack team and Next.js team have partnered to provide the `next-rspack` plugin. This plugin allows you to use Rspack as the bundler for Next.js, see [Next.js guide](/guide/integrations/next.md) for details. ### Nuxt Web framework Vue [Nuxt](https://nuxt.com/) is a free and open-source framework with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with Vue.js. Nuxt v3.14 introduces a new first-class Nuxt builder for Rspack, see [Nuxt 3.14](https://nuxt.com/blog/v3-14) for details. ### Nx Build system Monorepo [Nx](https://nx.dev/) is a powerful open-source build system that provides tools and techniques for enhancing developer productivity, optimizing CI performance, and maintaining code quality. Rspack team and Nx team have collaborated to provide the [Rspack Nx plugin](https://nx.dev/nx-api/rspack). This plugin contains executors, generators, and utilities for managing Rspack projects in an Nx Workspace. ### Rspeedy Build tool Lynx [Rspeedy](https://lynxjs.org/rspeedy/) is an Rspack-based build tool designed specifically for Lynx applications. [Lynx](https://lynxjs.org/) is a family of technologies empowering developers to use their existing web skills to create truly native UIs for both mobile and web from a single codebase. ### Re.Pack Build tool React Native [Re.Pack](https://github.com/callstack/repack) is a build tool for building your React Native application. Re.Pack v5 uses Rspack and React Native community CLI's plugin system to allow you to bundle your application using Rspack and easily switch from Metro. ### Remotion Video framework React [Remotion](https://www.remotion.dev/) is a React-based framework for creating videos programmatically. The [`@remotion/bundler`](https://www.remotion.dev/docs/bundle#rspack) package can use Rspack to bundle Remotion projects. ### Shakapacker Build tool Rails [Shakapacker](https://shakapacker.com/) handles compiling rails frontend assets. See [Rspack setup Docs](https://github.com/shakacode/shakapacker/blob/main/docs/rspack.md) ### Storybook UI development [Storybook Rsbuild](https://storybook.rsbuild.rs/) allows you to use Rsbuild as the build tool for Storybook, and provides UI framework integrations like React and Vue. ### TanStack Router Router React [TanStack Router](https://tanstack.com/router/latest) is a type-safe router for building React applications with features like nested routes, route-level data loading, and search params APIs. You can integrate TanStack Router with Rspack through the [Rspack plugin](https://tanstack.com/router/latest/docs/installation/with-rspack). ### TanStack Start Web framework React Solid [TanStack Start](https://tanstack.com/start/latest) is a full-stack framework powered by TanStack Router for React and Solid. TanStack Start provides official support for Rsbuild, allowing you to use Rsbuild to build full-stack web applications. See [TanStack Start Adds First-Class Rsbuild Support](https://tanstack.com/blog/start-adds-rsbuild-support) for details. ## More Visit [awesome-rstack](https://github.com/rstackjs/awesome-rstack) to discover more projects within the Rspack ecosystem. --- url: /guide/start/ai.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # AI To help AI better understand Rspack's features, configuration, and best practices so it can provide more accurate assistance during day-to-day development and troubleshooting, Rspack provides the following capabilities: - [Agent Skills](#agent-skills) - [llms.txt](#llmstxt) - [Markdown docs](#markdown-docs) - [AGENTS.md](#agentsmd) ## Agent Skills Agent Skills are domain-specific knowledge packs that can be installed into Agents, enabling them to give more accurate and professional suggestions or perform actions in specific scenarios. In the [rstackjs/agent-skills](https://github.com/rstackjs/agent-skills) repository, there are many skills for the Rstack ecosystem. The skills related to Rspack include: - [rspack-best-practices](https://github.com/rstackjs/agent-skills#rspack-best-practices): Best practices for Rspack. - [rspack-v2-upgrade](https://github.com/rstackjs/agent-skills#rspack-v2-upgrade): Upgrade an existing Rspack 1.x project to v2. - [rspack-debugging](https://github.com/rstackjs/agent-skills#rspack-debugging): Debug crashes or deadlocks/hangs in the Rspack build process using LLDB. - [rspack-tracing](https://github.com/rstackjs/agent-skills#rspack-tracing): Diagnose Rspack build failures or performance bottlenecks. In Coding Agents that support skills, you can use the [skills](https://www.npmjs.com/package/skills) package to install a specific skill with the following command: ```sh [npx] npx skills add rstackjs/agent-skills --skill rspack-best-practices ``` ```sh [yarn] yarn dlx skills add rstackjs/agent-skills --skill rspack-best-practices ``` ```sh [pnpm] pnpm dlx skills add rstackjs/agent-skills --skill rspack-best-practices ``` ```sh [bunx] bunx skills add rstackjs/agent-skills --skill rspack-best-practices ``` ```sh [deno] deno run -A npm:skills add rstackjs/agent-skills --skill rspack-best-practices ``` After installation, simply use natural language prompts to trigger the skill, for example: ``` Help me migrate this Rspack 1.x project to v2 ``` ## llms.txt [llms.txt](https://llmstxt.org/) is a standard that helps LLMs discover and use project documentation. Rspack follows this standard and publishes the following two files: - [llms.txt](https://rspack.rs/llms.txt): A structured index file containing the titles, links, and brief descriptions of all documentation pages. ``` https://rspack.rs/llms.txt ``` - [llms-full.txt](https://rspack.rs/llms-full.txt): A full-content file that concatenates the complete content of every documentation page into a single file. ``` https://rspack.rs/llms-full.txt ``` You can choose the file that best fits your use case: - `llms.txt` is smaller and consumes fewer tokens, making it suitable for AI to fetch specific pages on demand. - `llms-full.txt` contains the complete documentation content, so AI doesn't need to follow individual links — ideal when you need AI to have a comprehensive understanding of Rspack, though it consumes more tokens and is best used with AI tools that support large context windows. ## Markdown docs Every Rspack documentation page has a corresponding `.md` plain-text version that can be provided directly to AI. On any doc page, you can click “Copy Markdown” or “Copy Markdown Link” under the title to get the Markdown content or link. ``` https://rspack.rs/guide/start/introduction.md ``` Providing the Markdown link or content allows AI to focus on a specific chapter, which is useful for targeted troubleshooting or looking up a particular topic. ## AGENTS.md When you create a new project with [create-rspack](https://www.npmjs.com/package/create-rspack), the generated project includes an `AGENTS.md` file. This file follows the [AGENTS.md](https://agents.md/) specification and provides key project information to Agents. Example `AGENTS.md` content: ```markdown wrapCode # AGENTS.md ## Commands - `npm run dev` - Start the dev server - `npm run build` - Build the app for production - `npm run preview` - Preview the production build locally ## Docs - Rspack: https://rspack.rs/llms.txt ``` You can also customize it for your project, adding more details about the project structure, overall architecture, and other relevant information so Agents can better understand your project. ::: tip If you are using Claude Code, you can create a `CLAUDE.md` file and reference the `AGENTS.md` file in it. ```markdown title="CLAUDE.md" @AGENTS.md ``` ::: --- url: /guide/features/plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Plugins If [loaders](/guide/features/loader.md) are the workhorse for file transformations, then plugins are the workhorse for the overall Rspack build process. Most of Rspack's native implementations rely on the Rust side of the plugin system. For Node.js users, you don't need to worry about interoperability issues with Node.js and Rust, because Rspack takes care of those details for you automatically. You can just focus on how to use the plugins. ## Plugin usage Rspack provides the [plugins](/config/plugins.md) configuration, which is used to register a set of Rspack or webpack plugins to customize the build process. Here is an example of using the [webpack-bundle-analyzer](https://github.com/webpack/webpack-bundle-analyzer) in Rspack configuration: **ESM** ```js title="rspack.config.mjs" import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; export default { plugins: [ new BundleAnalyzerPlugin({ // options }), ], }; ``` **CJS** ```js title="rspack.config.cjs" const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); module.exports = { plugins: [ new BundleAnalyzerPlugin({ // options }), ], }; ``` If you're looking for more Rspack plugins, have a look at the great list of [supported plugins](/plugins/index.md). You can also refer to [Community plugin compatibility](/plugins/community-plugin-compatibility.md) for the list of webpack plugins that have passed Rspack compatibility tests. ## Other plugins ### Unplugin [unplugin](https://github.com/unjs/unplugin) is a unified plugin system for various build tools. You can use plugins implemented based on unplugin in Rspack, typically by importing the `/rspack` subpath of the plugin and registering it through `plugins`. Here is an example of using [unplugin-vue-components](https://www.npmjs.com/package/unplugin-vue-components): **ESM** ```js title="rspack.config.mjs" import Components from 'unplugin-vue-components/rspack'; export default { plugins: [ Components({ // options }), ], }; ``` **CJS** ```js title="rspack.config.cjs" const Components = require('unplugin-vue-components/rspack'); module.exports = { plugins: [ Components.default({ // options }), ], }; ``` ### SWC plugins In the built-in [swc-loader](/guide/features/builtin-swc-loader.md) of Rspack, you can use SWC's Wasm plugins, see [jsc.experimental.plugins](/guide/features/builtin-swc-loader.md#jscexperimentalplugins). ### Rsbuild plugins [Rsbuild](https://rsbuild.rs) is a build tool based on Rspack, and Rsbuild has its own plugin system. Please note that you cannot use Rsbuild plugins in Rspack, because Rspack is a more low-level tool, but you can use Rspack plugins in Rsbuild. Here is a comparison table for the plugins that can be used in Rspack and Rsbuild: | Tool used | Rspack plugins | webpack plugins | Rsbuild plugins | Unplugins | SWC plugins | | --------- | -------------- | --------------- | --------------- | --------- | ----------- | | Rspack | ✅ | ✅ | ❌ | ✅ | ✅ | | Rsbuild | ✅ | ✅ | ✅ | ✅ | ✅ | > Please refer to the [Rsbuild plugin documentation](https://rsbuild.rs/plugins/list/index) for more information. ## Write a plugin ### Plugin structure As a plugin author, the structure of a plugin is very simple: just implement an `apply` method that accepts a `Compiler` instance. It will be called when the Rspack plugin is initialized. The detailed API can be found in the [Plugin API](/api/plugin-api/index.md). **ESM** ```js title="MyPlugin.mjs" const PLUGIN_NAME = 'MyPlugin'; export class MyPlugin { apply(compiler) { compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => { console.log('The Rspack build process is starting!'); }); } } ``` **CJS** ```js title="MyPlugin.cjs" const PLUGIN_NAME = 'MyPlugin'; class MyPlugin { apply(compiler) { compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => { console.log('The Rspack build process is starting!'); }); } } module.exports = MyPlugin; ``` ### Write with TypeScript If you use TypeScript to write Rspack plugins, you can import `Compiler` and `RspackPluginInstance` to declare the types of your plugins: ```ts title="MyPlugin.ts" import type { Compiler, RspackPluginInstance } from '@rspack/core'; const PLUGIN_NAME = 'MyPlugin'; export class MyPlugin implements RspackPluginInstance { apply(compiler: Compiler) { compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => { console.log('The Rspack build process is starting!'); }); } } ``` ## Publishing plugins ### Declaring peer dependencies When publishing a plugin as an npm package, declare the bundler packages it integrates with as optional peer dependencies. This documents the supported host bundlers without requiring users who only use one bundler to install the other. If the plugin is designed only for Rspack, declare `@rspack/core` as an optional peer dependency. Set the version range according to the APIs the plugin relies on. For example, if the plugin uses an API introduced in a newer Rspack release, set that release as the minimum supported version. ```json title="package.json" { "peerDependencies": { "@rspack/core": "^1.0.0 || ^2.0.0" }, "peerDependenciesMeta": { "@rspack/core": { "optional": true } } } ``` If the plugin is designed to work with both Rspack and webpack, declare both `@rspack/core` and `webpack` as optional peer dependencies: ```json title="package.json" { "peerDependencies": { "@rspack/core": "^1.0.0 || ^2.0.0", "webpack": "^5.0.0" }, "peerDependenciesMeta": { "@rspack/core": { "optional": true }, "webpack": { "optional": true } } } ``` --- url: /guide/features/loader.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Loader Rspack has built-in support for JavaScript, CSS, JSON, and static assets modules. A loader is a transformer that converts various types of modules into Rspack supported types. By using different kinds of loaders, you can extend Rspack to process additional module types, including JSX, Markdown, Sass, Less, and more. When Rspack bundles a module, it first pre-processes the module through loaders, transforming it into a Rspack supported module type, and then post-processes the module according to the [rules\[\].type](/config/module-rules.md#rulestype). ## Compatibility with webpack loaders Rspack allows you to use most webpack loaders in the community. See [awesome-rstack - Rspack loaders](https://github.com/rstackjs/awesome-rstack?tab=readme-ov-file#rspack-loaders) to find loaders provided by the community. If you find an unsupported loader, please feel free to communicate with us through [GitHub Issues](https://github.com/web-infra-dev/rspack/issues). ## Writing loaders Refer to [Writing loaders](/api/loader-api/writing-loaders.md) to learn how to develop a loader. ## Example ### Using Less You can use [less-loader](https://github.com/webpack/less-loader) to transform the contents of the `.less` file accordingly. ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.less$/, use: [ { loader: 'less-loader', }, ], type: 'css', }, ], }, }; ``` [less-loader](https://github.com/webpack/less-loader) can transform Less files to Rspack-supported CSS module types, so you can set the type to `'css'` to instruct Rspack to use the CSS handling method that is natively supported for post-processing. ### Combining multiple loaders You can chain multiple loaders for a particular [Rule](/config/module-rules.md#rule) match, with the loaders executed in right-to-left order. For example, you can use [less-loader](https://github.com/webpack/less-loader) to do the transformation between Less to CSS types and [postcss-loader](https://github.com/webpack/postcss-loader) for the transformed source code to perform a secondary transformation, which will then get passed to Rspack's CSS post-processor for further processing. ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.less$/, use: [ { loader: 'postcss-loader', }, { loader: 'less-loader', }, ], type: 'css', }, ], }, }; ``` ### Passing configuration items You can use [rules\[\].use](/config/module-rules.md#rulesuse) to pass the relevant configuration to the loader, for example: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.css$/, use: [ { loader: 'postcss-loader', options: { postcssOptions: { // ... }, }, }, ], type: 'css', }, ], }, }; ``` ### Using a custom loader You can use a custom loader with Rspack. In the example below, we'll use the loader API to write a simple banner-loader. The purpose of the banner-loader is to prepend a banner comment at the header of each module, such as a license notice: ```js /** * MIT Licensed * Copyright (c) 2022-present ByteDance, Inc. and its affiliates. * https://github.com/web-infra-dev/rspack/blob/main/LICENSE */ ``` Create a new `banner-loader.js` file under the root of the project with the following content: ```js title="banner-loader.js" const BANNER = `/** * MIT Licensed * Copyright (c) 2022-present ByteDance, Inc. and its affiliates. * https://github.com/web-infra-dev/rspack/blob/main/LICENSE */`; module.exports = function (content) { return `${BANNER}\n${content}`; }; ``` The first input to this loader is the content of the file, allowing us to process the file content and return the transformed result. The script file must be imported using CommonJS `require()`. For example, to add a banner to all `*.js` files, the configuration might look like this: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.js$/, loader: './banner-loader.js', }, ], }, }; ``` For details, you can refer to [loader-api](/api/loader-api/index.md) ### Using built-in loader Built-in Loaders offer superior performance compared to JS Loaders, without sacrificing the composability of JS Loaders. The following are some built-in loaders. - [builtin:swc-loader](/guide/features/builtin-swc-loader.md) - [builtin:lightningcss-loader](/guide/features/builtin-lightningcss-loader.md) --- url: /guide/features/builtin-swc-loader.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # SWC loader [SWC](https://github.com/swc-project/swc) (Speedy Web Compiler) is a transformer and minimizer for JavaScript and TypeScript based on Rust. SWC provides similar functionality to Babel and Terser, and it is 20x faster than Babel on a single thread and 70x faster on four cores. Rspack provides a built-in loader for SWC, which is the Rust version of [swc-loader](https://github.com/swc-project/pkgs/tree/main/packages/swc-loader), aiming to deliver better performance. The loader's [options](https://swc.rs/docs/configuration/compilation) is aligned with the JS version of `swc-loader`. ## Example If you need to use `builtin:swc-loader` in your project, configure it as follows: ### TypeScript transpilation To transpile `.ts` files: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.(?:js|mjs|ts)$/, exclude: [/node_modules/], loader: 'builtin:swc-loader', options: { detectSyntax: 'auto', }, }, ], }, }; ``` ### JSX transpilation To transpile React's `.jsx` files: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.(?:js|mjs|jsx|ts|tsx)$/, use: { loader: 'builtin:swc-loader', options: { detectSyntax: 'auto', jsc: { transform: { react: { pragma: 'React.createElement', pragmaFrag: 'React.Fragment', throwIfNamespace: true, development: false, }, }, }, }, }, }, ], }, }; ``` ### Syntax lowering SWC provides [jsc.target](https://swc.rs/docs/configuration/compilation#jsctarget) and [env.targets](https://swc.rs/docs/configuration/compilation#envtargets) to specify the target of JavaScript syntax lowering. :::tip Default target from Rspack If neither `env.targets` nor `jsc.target` is configured, `builtin:swc-loader` will automatically derive a default target from Rspack's [`target`](/config/target.md) configuration. This means you can rely on your Rspack `target` configuration without manually specifying the same targets in the loader options. ::: #### jsc.target [jsc.target](https://swc.rs/docs/configuration/compilation#jsctarget) is used to specify the ECMA version, such as `es5`, `es2015`, `es2016`, etc. ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.js$/, use: { loader: 'builtin:swc-loader', options: { jsc: { target: 'es2015', }, // ...other options }, }, }, ], }, }; ``` #### env.targets [env.targets](https://swc.rs/docs/configuration/compilation#envtargets) uses the [browserslist](https://github.com/browserslist/browserslist) syntax to specify browser range, for example: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.js$/, use: { loader: 'builtin:swc-loader', options: { env: { targets: [ 'chrome >= 87', 'edge >= 88', 'firefox >= 78', 'safari >= 14', ], }, // ...other options }, }, }, ], }, }; ``` :::tip `jsc.target` and `env.targets` cannot be configured at the same time, choose one according to your needs. ::: ### Polyfill injection When using higher versions of JavaScript syntax and APIs in your project, to ensure that the compiled code can run in lower version browsers, you will typically need to perform two parts of the downgrade: syntax downgrading and polyfill injection. SWC supports injecting [core-js](https://github.com/zloirock/core-js) as an API polyfill, which can be configured using [env.mode](https://swc.rs/docs/configuration/compilation#envmode) and [env.coreJs](https://swc.rs/docs/configuration/compilation#envcorejs): ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.js$/, exclude: /node_modules[\\/]core-js/, use: { loader: 'builtin:swc-loader', options: { env: { mode: 'usage', coreJs: '3.26.1', targets: [ 'chrome >= 87', 'edge >= 88', 'firefox >= 78', 'safari >= 14', ], }, isModule: 'unknown', // ...other options }, }, }, ], }, }; ``` Note: - Make sure to [exclude](/config/module-rules.md#rulesexclude) the `core-js` package, as `core-js` will not work properly if compiled by SWC. - When importing non-ES modules, add [isModule: 'unknown'](https://swc.rs/docs/configuration/compilation#ismodule) to allow SWC to correctly identify the module type. ## Type declaration You can enable type hints using the `SwcLoaderOptions` type exported by `@rspack/core`: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.js$/, use: { loader: 'builtin:swc-loader', /** @type {import('@rspack/core').SwcLoaderOptions} */ options: { // some options }, }, }, ], }, }; ``` - `rspack.config.ts`: ```ts import type { SwcLoaderOptions } from '@rspack/core'; export default { module: { rules: [ { test: /\.js$/, use: { loader: 'builtin:swc-loader', options: { // some options } satisfies SwcLoaderOptions, }, }, ], }, }; ``` ## Options The following is an introduction to some SWC configurations and Rspack specific configurations. Please refer to the [SWC Configurations](https://swc.rs/docs/configuration/swcrc) for the complete options. ### detectSyntax [Added in v2.0.0](https://github.com/web-infra-dev/rspack/releases/tag/v2.0.0) - Type: `false | "auto"` - Default: `false` When set to `"auto"`, `builtin:swc-loader` infers `jsc.parser` from the resource extension. This is useful when one rule needs to handle mixed module types such as `.js`, `.jsx`, `.ts`, and `.tsx`. Inference rules: - `.js`, `.jsx`, `.mjs`, `.cjs` -> `{ syntax: "ecmascript", jsx: true }` - `.ts`, `.mts`, `.cts` -> `{ syntax: "typescript", tsx: false }` - `.tsx` -> `{ syntax: "typescript", tsx: true }` - Resources without a recognizable extension -> `{ syntax: "typescript", tsx: true }` > If `jsc.parser.syntax` is explicitly provided, `detectSyntax` does not infer syntax. ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.(?:js|mjs|jsx|ts|tsx)$/, use: { loader: 'builtin:swc-loader', options: { detectSyntax: 'auto', }, }, }, ], }, }; ``` ### jsc.experimental.plugins Stability: Experimental :::warning The Wasm plugin is deeply coupled with the version of SWC, you need to choose a Wasm plugin that is compatible with the corresponding version of SWC in order to function normally. See [FAQ - SWC Plugin Version Unmatched](/errors/swc-plugin-version.md) for more details. ::: Rspack supports load Wasm plugin in `builtin:swc-loader`, you can specify the plugin name like ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.js$/, use: { loader: 'builtin:swc-loader', options: { jsc: { experimental: { plugins: [ [ '@swc/plugin-remove-console', { exclude: ['error'], }, ], ], }, }, }, }, }, ], }, }; ``` this is an [example](https://github.com/rstackjs/rstack-examples/blob/d4b8aaef9915ed0f540edbe504217c3d1afe8989/rspack/builtin-swc-loader/rspack.config.js#L45) of Wasm plugin usage. #### Set cache root When you use SWC's Wasm plugin, SWC will generate cache files in the `.swc` directory of the current project by default. If you want to adjust this directory, you can modify the `cacheRoot` configuration, such as: ```js title="rspack.config.mjs" import path from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); export default { module: { rules: [ { test: /\.js$/, use: { loader: 'builtin:swc-loader', options: { jsc: { experimental: { cacheRoot: path.join(__dirname, './node_modules/.cache/swc'), }, }, }, }, }, ], }, }; ``` ### transformImport Ported from [babel-plugin-import](https://github.com/umijs/babel-plugin-import), configurations are basically the same. Function can't be used in configurations, such as `customName`, `customStyleName`, they will cause some performance overhead as these functions must be called from `Rust` , inspired by [modularize\_imports](https://crates.io/crates/modularize_imports), some simple function can be replaced by template string instead. Therefore, the function type configuration such as `customName`, `customStyleName` can be passed in strings as templates to replace functions and improve performance. For example: ```ts import { MyButton as Btn } from 'foo'; ``` Apply following configurations: ```js title="rspack.config.mjs" export default { module: { rules: [ { loader: 'builtin:swc-loader', options: { transformImport: [ { libraryName: 'foo', customName: 'foo/es/{{ member }}', }, ], }, }, ], }, }; ``` `{{ member }}` will be replaced by the imported specifier: ```ts import Btn from 'foo/es/MyButton'; ``` Template `customName: 'foo/es/{{ member }}'` is the same as ``customName: (member) => `foo/es/${member}` ``, but template string has no performance overhead of Node-API. There are some useful builtin helpers available in template string, take the above import statement as an example: ```js title="rspack.config.mjs" export default { module: { rules: [ { loader: 'builtin:swc-loader', options: { transformImport: [ { libraryName: 'foo', customName: 'foo/es/{{ kebabCase member }}', }, ], }, }, ], }, }; ``` Transformed to: ```ts import Btn from 'foo/es/my-button'; ``` In addition to `kebabCase`, there are `camelCase`, `snakeCase`, `upperCase`, `lowerCase` and `legacyKebabCase`/`legacySnakeCase` can be used as well. The `legacyKebabCase`/`legacySnakeCase` works as babel-plugin-import versions before 1.13.7. You can check the document of [babel-plugin-import](https://www.npmjs.com/package/babel-plugin-import) for other configurations. Taking the classic 4.x version of [ant-design](https://4x.ant.design/) as an example, we only need to configure it as follows: ```js title="rspack.config.mjs" export default { module: { rules: [ { loader: 'builtin:swc-loader', options: { transformImport: [ { libraryName: 'antd', style: '{{member}}/style/index.css', }, ], }, }, ], }, }; ``` The above configuration will transform `import { Button } from 'antd'`; to: ```ts import Button from 'antd/es/button'; import 'antd/es/button/style/index.css'; ``` Then you can see the style file is automatically imported and applied on the page. Of course, if you have already configured support for `less`, you can simply use the following configuration: ```js title="rspack.config.mjs" export default { module: { rules: [ { loader: 'builtin:swc-loader', options: { transformImport: [ { libraryName: 'antd', style: true, }, ], }, }, ], }, }; ``` The above configuration will transform `import { Button } from 'antd';` to: ```ts import Button from 'antd/es/button'; import 'antd/es/button/style'; ``` ### rspackExperiments Experimental features provided by rspack. :::warning `rspackExperiments.import` has been moved to the top-level [`transformImport`](#transformimport) option. The `rspackExperiments.import` option is deprecated and will be removed in a future version. ::: ### collectTypeScriptInfo [Added in v1.7.0](https://github.com/web-infra-dev/rspack/releases/tag/v1.7.0) Collects information from TypeScript's AST for consumption by subsequent Rspack processes, providing better TypeScript development experience and smaller output bundle size. To ensure the accuracy of the collected information, users must ensure that subsequent Normal Loaders after `builtin:swc-loader` do not modify the Abstract Syntax Tree (AST) corresponding to the collected information. This precaution is necessary to prevent discrepancies between the collected information and the actual code. #### collectTypeScriptInfo.typeExports [Added in v1.7.0](https://github.com/web-infra-dev/rspack/releases/tag/v1.7.0) - **Type:** `boolean` - **Default:** `false` Whether to collect type exports information for [`typeReexportsPresence`](/config/module-parser.md#javascripttypereexportspresence). This is used to check type exports of submodules when running in `'tolerant'` mode. Please refer to [type reexports presence example](https://github.com/rstackjs/rstack-examples/tree/main/rspack/type-reexports-presence) for more details. #### collectTypeScriptInfo.exportedEnum [Added in v1.7.0](https://github.com/web-infra-dev/rspack/releases/tag/v1.7.0) - **Type:** `boolean | 'const-only'` - **Default:** `false` Whether to collect information about exported `enum`s, so Rspack can perform cross-module inline optimization for enums. - `true` will collect all `enum` information, including `const enum`s and regular `enum`s. - `false` will not collect any `enum` information. - `'const-only'` will gather only `const enum`s, then only perform cross-module inline optimization for `const enum`. ```js title="rspack.config.mjs" const isProduction = process.env.NODE_ENV === 'production'; export default { module: { rules: [ { test: /\.(?:js|mjs|ts)$/, use: [ { loader: 'builtin:swc-loader', options: { detectSyntax: 'auto', collectTypeScriptInfo: { exportedEnum: isProduction, }, }, }, ], }, ], }, }; ``` Since this feature relies on module export usage information ([optimization.usedExports](/config/optimization.md#optimizationusedexports)), it is recommended to enable it only when `mode = "production"`. Please refer to [inline enum example](https://github.com/rstackjs/rstack-examples/tree/main/rspack/inline-enum) for more details. :::info By default, Rspack will perform inline optimization for all enums. To inline only `const enum`, use `'const-only'` and configure `transform.tsEnumIsMutable = true`. For detailed examples, refer to: [inline const enum example](https://github.com/rstackjs/rstack-examples/tree/main/rspack/inline-const-enum) ::: --- url: /guide/features/builtin-lightningcss-loader.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Lightning CSS loader [Lightning CSS](https://lightningcss.dev) is a high performance CSS parser, transformer and minifier written in Rust. It supports parsing and transforming many modern CSS features into syntax supported by target browsers, and also provides a better compression ratio. Rspack provides a built-in `builtin:lightningcss-loader`, which is based on Lightning CSS to transform CSS. It can replace the [postcss-loader](https://github.com/postcss/postcss-loader) and [autoprefixer](https://github.com/postcss/autoprefixer) for CSS syntax downgrading, prefixing, and other functionalities, offering better performance. ::: warning Please note that Lightning CSS strictly requires standards-compliant CSS input. When non-standard CSS is processed by the `builtin:lightningcss-loader`, styles may be ignored or produce unexpected results (Undefined Behavior). To ensure that styles are correctly applied, avoid using non-standard CSS syntax or browser-specific proprietary syntax, and instead use standard CSS writing practices that conform to W3C specifications. ::: ## Example To use `builtin:lightningcss-loader` in your project, you need to configure it as follows. ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { module: { rules: [ { test: /\.css$/, use: [ { loader: 'builtin:lightningcss-loader', options: { targets: 'ie 10', }, }, // ... other loaders ], }, ], }, }; ``` ## Type declarations You can use the `LightningcssLoaderOptions` type exported by `@rspack/core` to enable type hints: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.css$/, use: [ { loader: 'builtin:lightningcss-loader', /** @type {import('@rspack/core').LightningcssLoaderOptions} */ options: { targets: 'ie 10', }, }, // ... other loaders ], }, ], }, }; ``` ## Options Below are the configurations supported by `builtin:lightningcss-loader`. For detailed configuration, please refer to [lightningcss document](https://lightningcss.dev/transpilation.html). ```ts type LightningcssFeatureOptions = { nesting?: boolean; notSelectorList?: boolean; dirSelector?: boolean; langSelectorList?: boolean; isSelector?: boolean; textDecorationThicknessPercent?: boolean; mediaIntervalSyntax?: boolean; mediaRangeSyntax?: boolean; customMediaQueries?: boolean; clampFunction?: boolean; colorFunction?: boolean; oklabColors?: boolean; labColors?: boolean; p3Colors?: boolean; hexAlphaColors?: boolean; spaceSeparatedColorNotation?: boolean; fontFamilySystemUi?: boolean; doublePositionGradients?: boolean; vendorPrefixes?: boolean; logicalProperties?: boolean; selectors?: boolean; mediaQueries?: boolean; color?: boolean; }; type Targets = { android?: string; chrome?: string; edge?: string; firefox?: string; ie?: string; ios_saf?: string; opera?: string; safari?: string; samsung?: string; }; type LightningcssLoaderOptions = { minify?: boolean; errorRecovery?: boolean; targets?: string[] | string | Targets; include?: LightningcssFeatureOptions; exclude?: LightningcssFeatureOptions; drafts?: Drafts; nonStandard?: NonStandard; pseudoClasses?: PseudoClasses; unusedSymbols?: Set; }; ``` ### targets - **Type:** `string | string[] | Targets` Browserslist query string or a `Targets` object specifying browser versions. :::tip Default targets from Rspack If `targets` is not configured, `builtin:lightningcss-loader` will automatically derive a default targets from Rspack's [`target`](/config/target.md) configuration when using browserslist-related targets (e.g., `browserslist` or `browserslist:modern`). Since Lightning CSS only supports browser-related targets, non-browser targets like `node` will not provide default targets for this loader. This means you can rely on your Rspack `target` configuration without manually specifying the same targets in the loader options. ::: Here are some examples of setting targets. - Setting a browserslist query string: ```js const loader = { loader: 'builtin:lightningcss-loader', /** @type {import('@rspack/core').LightningcssLoaderOptions} */ options: { targets: 'ie 10', }, }; ``` - Setting an array of browserslist query strings: ```js const loader = { loader: 'builtin:lightningcss-loader', /** @type {import('@rspack/core').LightningcssLoaderOptions} */ options: { targets: ['chrome >= 87', 'edge >= 88', '> 0.5%'], }, }; ``` - Setting a `Targets` object: ```js const loader = { loader: 'builtin:lightningcss-loader', /** @type {import('@rspack/core').LightningcssLoaderOptions} */ options: { targets: { chrome: '95.0', safari: '13.2', }, }, }; ``` ### errorRecovery - **Type:** `boolean` - **Default:** `true` Control how Lightning CSS handles invalid CSS syntax. By default, this option is enabled, meaning that when invalid CSS rules or declarations are parsed, Lightning CSS will skip them and emit warnings, while omitting them from the final output without interrupting the compilation process. #### Ignoring warnings If you confirm that these warnings can be ignored, you can use [ignoreWarnings](/config/other-options.md#ignorewarnings) to filter out the warnings from LightningCSS. For example, ignore all warnings: ```js title="rspack.config.mjs" export default { ignoreWarnings: [ (warning) => /LightningCSS parse warning/.test(warning.message), ], }; ``` You can also use regular expressions to ignore specific warnings. #### Disabling `errorRecovery` If you set `errorRecovery` to `false`, Lightning CSS will throw a compilation error and interrupt the build process when parsing any invalid CSS syntax: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.css$/, use: [ { loader: 'builtin:lightningcss-loader', /** @type {import('@rspack/core').LightningcssLoaderOptions} */ options: { errorRecovery: false, }, }, ], }, ], }, }; ``` --- url: /guide/features/dev-server.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Dev server The `rspack dev` and `rspack serve` commands run a local development server through [@rspack/dev-server](https://npmjs.com/package/@rspack/dev-server). It provides hot module replacement (HMR), static file serving, proxying, and related development features. ## Install dev server `@rspack/dev-server` is an optional peer dependency of `@rspack/cli`. Install it before using `rspack dev`, `rspack serve`, or `rspack preview`: ```sh [npm] npm add @rspack/dev-server -D ``` ```sh [yarn] yarn add @rspack/dev-server -D ``` ```sh [pnpm] pnpm add @rspack/dev-server -D ``` ```sh [bun] bun add @rspack/dev-server -D ``` ```sh [deno] deno add npm:@rspack/dev-server -D ``` ## HMR By default, Rspack enables HMR in dev mode. You can disable HMR by configuring the `devServer.hot` option in Rspack configuration. ```js title="rspack.config.mjs" export default { devServer: { hot: false, }, }; ``` :::warning Do not include `[hash]` or `[contenthash]` in [output.cssFilename](/config/output.md#outputcssfilename), otherwise CSS HMR may not work. ::: ## Proxy The dev server includes proxy support. Configure the `devServer.proxy` option to proxy matching requests. This feature is powered by [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware). For example, you can proxy `/api` to `http://localhost:3000` as follows: ```js title="rspack.config.mjs" export default { devServer: { proxy: [ { context: ['/api'], target: 'http://localhost:3000', changeOrigin: true, }, ], }, }; ``` For more devServer configuration options, please refer to [devServer](/config/dev-server.md). --- url: /guide/features/asset-module.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Asset modules Rspack has built-in support for assets (e.g. images, fonts, videos, etc.), which means you don't need any loader to process them. Unlike other module types, assets usually stand alone, so they are generated at the granularity of a module. :::tip Module and Chunk Other module types, such as JavaScript modules, are usually bundled into one or more chunks for final bundle generation. In the case of asset modules, it is almost impossible to be bundled, so they usually exist independently. This is one of the most straightforward reasons why it is called a "asset module." ::: ## Supported asset module types - **`'asset/inline'`**: Converts an asset to a DataURI, using Base64 encoding, no encoding configuration is supported at this time. - **`'asset/resource'`**: Converts an asset to a separate file and exports the URL address. - **`'asset'`**: - Automatically selects `'asset/inline'` or `'asset/resource'` depending on the size of the asset, depending on the configuration - By default, the `'asset/inline'` mechanism is applied if the asset size is less than or equal to 8096 bytes, otherwise the `'asset/resource'` mechanism is used. - **`'asset/source'`**: Converts and exports the asset file as a raw string. - **`'asset/bytes'`**: Converts and exports the asset file as a binary data `Uint8Array`. ## Example ### Using `type: 'asset'` Using `type: 'asset'` to automatically select a mechanism based on conditions: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.png$/, type: 'asset', }, ], }, }; ``` By default, the `'asset/inline'` mechanism is applied if the asset size is less than or equal to 8096 bytes, otherwise the `'asset/resource'` policy is used. If you wish to modify this behavior, you can use [`module.parser.asset.dataUrlCondition`](/config/module-parser.md#asset) to modify the global configuration, or use [`rules[].parser.dataUrlCondition`](/config/module-parser.md#assetdataurlcondition) to configure it separately for a specific eligible module. ### Replacing `url-loader` Replacing `url-loader` with `type: 'asset/inline'`: ```diff title="rspack.config.mjs" export default { module: { rules: [ { test: /\.png$/, - use: [ - { - loader: 'url-loader', - }, - ], + type: 'asset/inline' }, ], }, }; ``` ### Replacing `file-loader` Replacing `file-loader` with `type: 'asset/resource'`: ```diff title="rspack.config.mjs" export default { module: { rules: [ { test: /\.png$/, - use: [ - { - loader: 'file-loader', - }, - ], + type: 'asset/resource' }, ], }, }; ``` ### Replacing `raw-loader` Replacing `raw-loader` with `type: 'asset/source'`: ```diff title="rspack.config.mjs" export default { module: { rules: [ { resourceQuery: /raw/, - use: [ - { - loader: 'raw-loader', - }, - ], + type: 'asset/source' }, ], }, }; ``` ### Using optimizers as loaders There are times when we want to optimize a specific image, for example by compressing its size. We can still use these loaders. For example, optimizing all files ending in `.png` with [image-minimizer-webpack-plugin](https://github.com/webpack/image-minimizer-webpack-plugin): ```js title="rspack.config.mjs" import ImageMinimizerPlugin from 'image-minimizer-webpack-plugin'; export default { module: { rules: [ { test: /\.png$/, use: [ { loader: ImageMinimizerPlugin.loader, options: { // ... }, }, ], type: 'asset/resource', }, ], }, }; ``` The above condition uses `type: 'asset/resource'`, which will direct Rspack to complete individual file generation for all matching files and return the final asset URL address. --- url: /guide/features/asset-base-path.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Asset base path Rspack provides the [output.publicPath](/config/output.md#outputpublicpath) option, which sets the base URL path prefix for bundled static assets (such as JS, CSS, images, etc.). ## Use cases Imagine the following scenarios: - Your static assets need to be deployed to a CDN - Your web application is not deployed under the root path of the domain - You need to use different assets paths for different environments (development, testing, or production) In these scenarios, configuring `output.publicPath` can help you load static assets correctly. ## Basic example Set `output.publicPath` to `/`, then the assets path will be relative to the root path. ```js title="rspack.config.mjs" export default { output: { publicPath: '/', }, }; ``` With this configuration, the assets access path is `http://[domain]/`, for example `http://localhost:8080/main.js`. ## Subdirectory If your application needs to be deployed under a subdirectory, you can set `output.publicPath` to the corresponding subdirectory path: ```js title="rspack.config.mjs" export default { output: { publicPath: '/assets/', }, }; ``` With this configuration, all assets will be loaded from the `/assets/` path, for example `http://localhost:8080/assets/main.js`. :::tip - The value of `output.publicPath` usually ends with `/`. - Do not set `output.publicPath` to a relative path, such as `./assets/`. Using a relative path may cause assets to load incorrectly when they are located at different path depths. - If setting `output.publicPath` to an empty string, the asset URL path will be relative to the HTML page (same directory). ::: ## Use CDN When deploying static assets using CDN, you can set `output.publicPath` based on the environment variable, and set it to the CDN URL prefix during the production build. ```js title="rspack.config.mjs" const isProd = process.env.NODE_ENV === 'production'; export default { output: { publicPath: isProd ? 'https://cdn.example.com/' : '/', }, }; ``` With this configuration: - In the development mode, the assets access path is `http://[domain]/`, for example `http://localhost:8080/main.js`. - In the production mode, the assets access path is `https://cdn.example.com/`, for example `https://cdn.example.com/main.[hash].js`. ## Dynamically set publicPath You can set `publicPath` dynamically using [`import.meta.rspackPublicPath`](/api/runtime-api/module-variables.md#importmetarspackpublicpath) in your JavaScript code. The `import.meta.rspackPublicPath` will override the `output.publicPath` in the Rspack config, but it will only take effect for dynamically loaded assets, not for assets loaded via ` ``` You can refer to the related example [example-vue3](https://github.com/rstackjs/rstack-examples/tree/main/rspack/vue). ## Vue 2 Rspack has completed compatibility with Vue 2 (using vue-loader\@15). Please make sure to use `rules[].type = "javascript/auto"` in CSS-related rules: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.css$/, use: ['vue-style-loader', 'css-loader'], type: 'javascript/auto', }, { test: /\.(?:js|mjs|ts)$/, // add this rule when you use TypeScript in Vue SFC loader: 'builtin:swc-loader', options: { detectSyntax: 'auto', }, }, ], }, experiments: { css: false, }, }; ``` TypeScript is supported using Rspack's native `builtin:swc-loader`, see [this](/guide/features/builtin-swc-loader.md) for details. You can refer to the related example [example-vue2](https://github.com/rstackjs/rstack-examples/tree/main/rspack/vue2) and [example-vue2-ts](https://github.com/rstackjs/rstack-examples/tree/main/rspack/vue2-ts). ## Vue 3 JSX Since Rspack supports using `babel-loader`, you can directly use the [@vue/babel-plugin-jsx](https://github.com/vuejs/babel-plugin-jsx) plugin to support Vue 3 JSX syntax. ### Install First, you need to install [babel-loader](https://www.npmjs.com/package/babel-loader), [@babel/core](https://www.npmjs.com/package/@babel/core) and [@vue/babel-plugin-jsx](https://www.npmjs.com/package/@vue/babel-plugin-jsx): ```sh [npm] npm add babel-loader @babel/core @vue/babel-plugin-jsx -D ``` ```sh [yarn] yarn add babel-loader @babel/core @vue/babel-plugin-jsx -D ``` ```sh [pnpm] pnpm add babel-loader @babel/core @vue/babel-plugin-jsx -D ``` ```sh [bun] bun add babel-loader @babel/core @vue/babel-plugin-jsx -D ``` ```sh [deno] deno add npm:babel-loader npm:@babel/core npm:@vue/babel-plugin-jsx -D ``` ### Configure Then add the following configuration to support Vue 3 JSX syntax in `.jsx` files: ```js title="rspack.config.mjs" import { defineConfig } from '@rspack/cli'; export default defineConfig({ entry: { main: './src/index.jsx', }, module: { rules: [ { test: /\.jsx$/, use: [ { loader: 'babel-loader', options: { plugins: ['@vue/babel-plugin-jsx'], }, }, ], }, ], }, }); ``` Rspack provides a [example](https://github.com/rstackjs/rstack-examples/tree/main/rspack/vue-jsx) of Vue JSX for reference. ## Vue DevTools Vue DevTools is designed to enhance the Vue developer experience; it can significantly improve your productivity and debugging capabilities when working with Vue applications. For Vue applications built with Rspack, use [vue-devtools-rstack](https://github.com/OskarLebuda/vue-devtools-rstack) to integrate Vue DevTools. --- url: /guide/integrations/next.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Next.js [next-rspack](https://www.npmjs.com/package/next-rspack) is a community-driven plugin that enables Next.js projects to use Rspack as the bundler (experimental). :::tip See the [Rspack joins the Next.js ecosystem](/blog/rspack-next-partner.md) blog post to learn more details. ::: ## Installation Install the `next-rspack` package: ```sh [npm] npm add next-rspack -D ``` ```sh [yarn] yarn add next-rspack -D ``` ```sh [pnpm] pnpm add next-rspack -D ``` ```sh [bun] bun add next-rspack -D ``` ```sh [deno] deno add npm:next-rspack -D ``` :::tip If you are using a Next.js version below 15.3.0, please upgrade to >= 15.3.0 first, see [Next.js - Upgrading](https://nextjs.org/docs/pages/building-your-application/upgrading). ::: ## Usage Wrap your existing configuration in the project's `next.config.mjs` or `next.config.ts`: **next.config.ts** ```ts import withRspack from 'next-rspack'; import type { NextConfig } from 'next'; const nextConfig: NextConfig = {/* config options here */}; export default withRspack(nextConfig); ``` **next.config.mjs** ```js import withRspack from 'next-rspack'; /** @type {import('next').NextConfig} */ const nextConfig = {/* config options here */}; export default withRspack(nextConfig); ``` > Example: [next.js/examples/with-rspack](https://github.com/vercel/next.js/tree/canary/examples/with-rspack). ## Customizing Rspack configuration Through Rspack's compatibility with webpack, when using `next-rspack`, you can customize configurations in the same way as you would with webpack. In `next.config.mjs`, modify Rspack's configuration by adding the following callback function: ```js title="next.config.mjs" export default { webpack: ( config, { buildId, dev, isServer, defaultLoaders, nextRuntime, webpack }, ) => { // Important: return the modified config return config; }, }; ``` > For more details, see the [Next.js - Custom Webpack Config](https://nextjs.org/docs/app/api-reference/config/next-config-js/webpack). ## Usage with next-compose-plugins Alternatively, you can use [next-compose-plugins](https://www.npmjs.com/package/next-compose-plugins) to quickly integrate `next-rspack` with other Next.js plugins: ```js title="next.config.mjs" import withPlugins from 'next-compose-plugins'; import withRspack from 'next-rspack'; export default withPlugins([ [withRspack], // your other plugins here ]); ``` --- url: /guide/integrations/node.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Node.js applications Rspack can build Node.js applications by bundling application code, transforming TypeScript with SWC, keeping runtime dependencies external, and emitting assets that Node.js can load at runtime. For modern Node.js applications, see [Use ESM output](#use-esm-output). ## Install dependencies Install Rspack and the helper dependencies used by the examples on this page: ```sh [npm] npm add @rspack/core @rspack/cli @rspack/dev-server webpack-node-externals run-script-webpack-plugin -D ``` ```sh [yarn] yarn add @rspack/core @rspack/cli @rspack/dev-server webpack-node-externals run-script-webpack-plugin -D ``` ```sh [pnpm] pnpm add @rspack/core @rspack/cli @rspack/dev-server webpack-node-externals run-script-webpack-plugin -D ``` ```sh [bun] bun add @rspack/core @rspack/cli @rspack/dev-server webpack-node-externals run-script-webpack-plugin -D ``` ```sh [deno] deno add npm:@rspack/core npm:@rspack/cli npm:@rspack/dev-server npm:webpack-node-externals npm:run-script-webpack-plugin -D ``` ## Basic concepts - **Node.js target** ([`target: 'node'`](/config/target.md)): Generates output suitable for Node.js instead of the browser. - **External dependencies**: Server applications usually do not need to bundle every package in `node_modules`. Externalizing dependencies keeps the bundle smaller and allows Node.js to load packages normally at runtime. - **Development HMR**: In development, the Node.js process needs to restart or accept updates after Rspack rebuilds the server bundle. - **Native addons**: Dependencies or application code may reference `.node` files. These files need to be emitted as separate assets and loaded by Node.js at runtime. ## Configure Rspack The following configuration targets Node.js, externalizes `node_modules`, writes development output to disk, and starts the generated bundle during development: ```js title="rspack.config.mjs" // @ts-check import { defineConfig } from '@rspack/cli'; import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin'; import nodeExternals from 'webpack-node-externals'; export default defineConfig({ context: import.meta.dirname, target: 'node', entry: { main: process.env.NODE_ENV === 'production' ? './src/main.ts' : ['@rspack/core/hot/poll?100', './src/main.ts'], }, output: { clean: true, }, resolve: { extensions: ['...', '.ts', '.tsx', '.jsx'], }, module: { rules: [ { test: /\.(?:js|mjs|ts)$/, exclude: [/node_modules/], loader: 'builtin:swc-loader', options: { detectSyntax: 'auto', }, }, { test: /\.node$/, type: 'asset/resource', }, ], }, externals: [ nodeExternals({ allowlist: [/@rspack\/core\/hot\/poll/], }), ], plugins: [ process.env.NODE_ENV !== 'production' && new RunScriptWebpackPlugin({ name: 'main.js', autoRestart: false, }), ], devServer: { devMiddleware: { writeToDisk: true, }, }, }); ``` ## Configure scripts Use `rspack dev` for development and `rspack build` for production builds: ```json title="package.json" { "scripts": { "build": "rspack build", "dev": "rspack dev", "start": "node dist/main.js" } } ``` - `dev`: Runs Rspack Dev Server, writes the server bundle to disk, and starts `dist/main.js`. - `build`: Creates a production bundle without the HMR polling entry. - `start`: Runs the production output with Node.js. ## Configure development HMR Add `@rspack/core/hot/poll` only to the development entry, since including it in the production bundle will crash the Node.js application because HMR is not available in build mode: ```js title="rspack.config.mjs" export default { entry: { main: process.env.NODE_ENV === 'production' ? './src/main.ts' : ['@rspack/core/hot/poll?100', './src/main.ts'], }, }; ``` Because the server process is started from the generated bundle, `devServer.devMiddleware.writeToDisk` must be enabled: ```js title="rspack.config.mjs" export default { devServer: { devMiddleware: { writeToDisk: true, }, }, }; ``` `RunScriptWebpackPlugin` starts the generated `main.js` file during development: ```js title="rspack.config.mjs" import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin'; export default { plugins: [ new RunScriptWebpackPlugin({ name: 'main.js', autoRestart: false, }), ], }; ``` The HMR polling runtime must be allowlisted when `webpack-node-externals` is used so it is bundled into the server output instead of being treated as an external dependency. ## Externalize dependencies Use [webpack-node-externals](https://www.npmjs.com/package/webpack-node-externals) to externalize packages from `node_modules`: ```js title="rspack.config.mjs" import nodeExternals from 'webpack-node-externals'; export default { externals: [ nodeExternals({ allowlist: [/@rspack\/core\/hot\/poll/], }), ], }; ``` ## Use ESM output For modern Node.js applications, follow the [ESM guide](/guide/features/esm.md) to output ESM bundles. When using `webpack-node-externals` with ESM output, add `importType: 'module'` so external dependencies are loaded with ESM imports: ```js title="rspack.config.mjs" import nodeExternals from 'webpack-node-externals'; export default { output: { module: true, }, externals: [ nodeExternals({ importType: 'module', allowlist: [/@rspack\/core\/hot\/poll/], }), ], }; ``` ## Native node modules When building Node.js applications with Rspack, you may encounter dependencies that include Node.js native addon dependencies (`.node` modules). Because `.node` modules cannot be packaged into JavaScript artifacts, emit them as assets and load them with Node.js. ```js title="rspack.config.mjs" export default { target: 'node', output: { // Use the default publicPath or `publicPath: 'auto'` so emitted addon // URLs stay relative to the generated bundle. }, module: { rules: [ { test: /\.node$/, type: 'asset/resource', }, ], }, }; ``` Then load the emitted addon from application code with `dlopen`: ```js title="src/addon.mjs" import { dlopen } from 'node:process'; import { fileURLToPath } from 'node:url'; const file = new URL('./file.node', import.meta.url); const addon = { exports: {} }; try { dlopen(addon, fileURLToPath(file)); } catch (error) { // Handle addon loading errors here. } export default addon.exports; ``` --- url: /guide/integrations/nestjs.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # NestJS Rspack can build [NestJS](https://nestjs.com/) applications. Compared with `tsc`, Rspack can bundle application code, transform TypeScript with SWC, enable development HMR, and leave runtime dependencies external when needed. ## How to use Start with the common [Node.js application configuration](/guide/integrations/node.md), then add the NestJS settings described below. You can also use the [NestJS example](https://github.com/rstackjs/rstack-examples/tree/main/rspack/nestjs) in `rstack-examples` as a reference. It includes a complete `rspack.config.mjs`, development script, production build script, and HMR entry. ## Example The [rstack-examples](https://github.com/rstackjs/rstack-examples/tree/main/rspack/nestjs) repository contains a complete NestJS application built with Rspack. ## Install dependencies Install the common Node.js build dependencies from the [Node.js guide](/guide/integrations/node.md#install-dependencies), then install the NestJS runtime packages: ```sh [npm] npm add @nestjs/common @nestjs/core @nestjs/platform-express reflect-metadata rxjs ``` ```sh [yarn] yarn add @nestjs/common @nestjs/core @nestjs/platform-express reflect-metadata rxjs ``` ```sh [pnpm] pnpm add @nestjs/common @nestjs/core @nestjs/platform-express reflect-metadata rxjs ``` ```sh [bun] bun add @nestjs/common @nestjs/core @nestjs/platform-express reflect-metadata rxjs ``` ```sh [deno] deno add npm:@nestjs/common npm:@nestjs/core npm:@nestjs/platform-express npm:reflect-metadata npm:rxjs ``` ## Basic concepts NestJS applications run in Node.js, so most configurations can follow the common [Node.js configuration](/guide/integrations/node.md). The main NestJS-specific requirement is decorator metadata, which NestJS uses at runtime. - **Decorator metadata**: Enable TypeScript decorators and emitted metadata so dependency injection, controllers, routes, guards, interceptors, and other NestJS features work correctly. - **HMR cleanup**: When development HMR updates the server bundle, close the previous Nest application instance before accepting the update. - **Production minification**: Keep class and function names stable because NestJS may use them through metadata reflection and execution context APIs. ## Configure Rspack The following configuration is adapted from the NestJS example. It combines the common Node.js setup with the decorator metadata options required by NestJS: ```js title="rspack.config.mjs" // @ts-check import { defineConfig } from '@rspack/cli'; import { rspack } from '@rspack/core'; import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin'; import nodeExternals from 'webpack-node-externals'; export default defineConfig({ context: import.meta.dirname, target: 'node', entry: { main: process.env.NODE_ENV === 'production' ? './src/main.ts' : ['@rspack/core/hot/poll?100', './src/main.ts'], }, output: { clean: true, }, resolve: { extensions: ['...', '.ts', '.tsx', '.jsx'], }, module: { rules: [ { test: /\.ts$/, use: { loader: 'builtin:swc-loader', options: { detectSyntax: 'auto', jsc: { parser: { decorators: true, }, transform: { legacyDecorator: true, decoratorMetadata: true, }, }, }, }, }, ], }, optimization: { minimizer: [ new rspack.SwcJsMinimizerRspackPlugin({ minimizerOptions: { compress: { keep_classnames: true, keep_fnames: true, }, mangle: { keep_classnames: true, keep_fnames: true, }, }, }), ], }, plugins: [ process.env.NODE_ENV !== 'production' && new RunScriptWebpackPlugin({ name: 'main.js', autoRestart: false, }), ], devServer: { devMiddleware: { writeToDisk: true, }, }, externals: [ nodeExternals({ allowlist: [/@rspack\/core\/hot\/poll/], }), ], }); ``` ## Configure scripts Use `rspack dev` during development and `rspack build` for production: ```json title="package.json" { "scripts": { "build": "rspack build", "dev": "rspack dev", "start": "node dist/main.js" } } ``` - `dev`: Runs Rspack Dev Server, writes the server bundle to disk, and starts `dist/main.js`. - `build`: Creates a production bundle without the HMR polling entry. - `start`: Runs the production bundle with Node.js. ## Configure TypeScript decorators NestJS uses decorators such as `@Module()`, `@Controller()`, `@Injectable()`, and `@Get()`. Configure `builtin:swc-loader` so SWC can parse these decorators and emit the metadata NestJS needs: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.ts$/, use: { loader: 'builtin:swc-loader', options: { detectSyntax: 'auto', jsc: { parser: { decorators: true, }, transform: { legacyDecorator: true, decoratorMetadata: true, }, }, }, }, }, ], }, }; ``` If your project also runs `tsc`, keep `experimentalDecorators` and `emitDecoratorMetadata` enabled in `tsconfig.json` so TypeScript and Rspack use the same decorator assumptions: ```json title="tsconfig.json" { "compilerOptions": { "experimentalDecorators": true, "emitDecoratorMetadata": true } } ``` ## Configure development HMR Add `@rspack/core/hot/poll` only in development. If it is included in the production bundle, the Node.js application will fail at runtime because HMR is not available in build mode: ```js title="rspack.config.mjs" export default { entry: { main: process.env.NODE_ENV === 'production' ? './src/main.ts' : ['@rspack/core/hot/poll?100', './src/main.ts'], }, }; ``` Add HMR handling to the NestJS bootstrap file. This closes the old application instance before accepting the updated module: ```ts title="src/main.ts" declare const module: any; import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); await app.listen(3000); if (module.hot) { module.hot.accept(); module.hot.dispose(() => app.close()); } } bootstrap(); ``` See [Node.js - Configure development HMR](/guide/integrations/node.md#configure-development-hmr) for the shared Rspack entry, `writeToDisk`, `RunScriptWebpackPlugin`, and externals allowlist settings used with this bootstrap code. If your project needs ESM output, see [Node.js - Use ESM output](/guide/integrations/node.md#use-esm-output). ## Configure production minification When minifying a NestJS server bundle, keep class names and function names. NestJS can rely on stable class and handler references through metadata reflection and execution context APIs. ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { optimization: { minimizer: [ new rspack.SwcJsMinimizerRspackPlugin({ minimizerOptions: { compress: { keep_classnames: true, keep_fnames: true, }, mangle: { keep_classnames: true, keep_fnames: true, }, }, }), ], }, }; ``` ## Native node modules If a NestJS dependency includes a Node.js native addon (`.node` module), follow [Node.js - Native node modules](/guide/integrations/node.md#native-node-modules) to emit the addon with `asset/resource` and let Node.js load it at runtime. --- url: /guide/integrations/solid.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Solid ## How to use Rspack provides two solutions to support Solid: - **Use Rsbuild**: Rsbuild provides out-of-the-box support for Solid, allowing you to quickly create a Solid project. See [Rsbuild - Solid](https://rsbuild.rs/guide/framework/solid) for details. - **Manually configure Rspack**: You can refer to the current document to manually add configurations for Solid. ## Configure Solid Thanks to the good compatibility of Rspack with the babel-loader, it is very easy to use Solid in Rspack. All you need is babel-loader and Solid babel preset. Rspack provides Solid [example](https://github.com/rstackjs/rstack-examples/tree/main/rspack/solid) for reference. ```js title="rspack.config.mjs" import { defineConfig } from '@rspack/cli'; export default defineConfig({ entry: { main: './src/index.jsx', }, module: { rules: [ { test: /\.jsx$/, use: [ { loader: 'babel-loader', options: { presets: ['solid'], plugins: ['solid-refresh/babel'], }, }, ], }, ], }, }); ``` --- url: /guide/integrations/svelte.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Svelte ## How to use Rspack provides two solutions to support Svelte: - **Use Rsbuild**: Rsbuild provides out-of-the-box support for Svelte, allowing you to quickly create a Svelte project. See ["Rsbuild - Svelte"](https://rsbuild.rs/guide/framework/svelte) for details. - **Manually configure Rspack**: You can refer to the current document to manually add configurations for Svelte. ## Configure svelte-loader Thanks to the good compatibility of Rspack with the [svelte-loader](https://github.com/sveltejs/svelte-loader), it is very easy to use Svelte in Rspack. All you need is to configure svelte-loader. Rspack provides Svelte [example](https://github.com/rstackjs/rstack-examples/tree/main/rspack/svelte) for reference. ```js title="rspack.config.mjs" import path from 'node:path'; import { defineConfig } from '@rspack/cli'; import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); export default defineConfig({ entry: { main: './src/main.ts', }, resolve: { alias: { svelte: path.dirname(require.resolve('svelte/package.json')), }, extensions: ['.mjs', '.js', '.ts', '.svelte'], mainFields: ['svelte', 'browser', 'module', 'main'], }, module: { rules: [ { test: /\.svelte$/, use: [ { loader: 'svelte-loader', options: { compilerOptions: { dev: !prod, }, emitCss: prod, hotReload: !prod, preprocess: sveltePreprocess({ sourceMap: !prod, postcss: true }), }, }, ], }, ], }, }); ``` --- url: /guide/integrations/rstest.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Rstest [Rstest](https://rstest.rs/) is a JavaScript testing framework powered by Rspack. It runs tests through Rspack's bundling pipeline, and its official adapter can reuse module resolution, transforms, and plugins from an existing Rspack configuration. This guide covers unit testing with Rstest and end-to-end testing with [`@rstest/playwright`](https://rstest.rs/guide/advanced/playwright). ## Set up Rstest ### Create a new project When creating a project, follow the [Quick start](/guide/start/quick-start.md) guide and select **Rstest - testing** in the prompts. The generated project includes the Rstest dependencies, configuration, and test scripts. ### Add Rstest to an existing project Install Rstest and the official Rspack adapter as development dependencies: ```sh [npm] npm add @rstest/core @rstest/adapter-rspack -D ``` ```sh [yarn] yarn add @rstest/core @rstest/adapter-rspack -D ``` ```sh [pnpm] pnpm add @rstest/core @rstest/adapter-rspack -D ``` ```sh [bun] bun add @rstest/core @rstest/adapter-rspack -D ``` ```sh [deno] deno add npm:@rstest/core npm:@rstest/adapter-rspack -D ``` Then add scripts for running tests and watching for changes: ```json title="package.json" { "scripts": { "test": "rstest", "test:watch": "rstest --watch" } } ``` ### Reuse the Rspack configuration Create an `rstest.config.ts` file in the project root and use `withRspackConfig` to reuse the existing Rspack configuration: ```ts title="rstest.config.ts" import { withRspackConfig } from '@rstest/adapter-rspack'; import { defineConfig } from '@rstest/core'; export default defineConfig({ extends: withRspackConfig(), }); ``` The adapter loads `rspack.config.ts`, maps compatible Rspack options to Rstest, and merges them with the rest of the Rstest configuration. :::note By default, the adapter looks for the Rspack configuration in `process.cwd()`. It also disables Rstest's built-in CSS plugins so that the Rspack CSS configuration takes effect. For monorepos, custom configuration paths, named configurations, and complete mapping details, see [Rstest - Rspack integration](https://rstest.rs/guide/integration/rspack). ::: ## Unit testing Unit tests verify individual modules and functions in isolation. ### Write tests Create a source file and a corresponding test file: ```ts title="src/utils.ts" export function add(a: number, b: number) { return a + b; } ``` ```ts title="src/utils.test.ts" import { expect, test } from '@rstest/core'; import { add } from './utils'; test('adds two numbers correctly', () => { expect(add(1, 2)).toBe(3); expect(add(-1, 1)).toBe(0); }); ``` ### Run tests ```bash # Run all tests pnpm run test # Run tests in watch mode pnpm run test:watch # Run tests whose names match a pattern pnpm run test -- -t 'adds two numbers' ``` See the [Rstest documentation](https://rstest.rs/guide/) for test APIs, mocking, snapshots, coverage, and other features. ## End-to-end testing [`@rstest/playwright`](https://rstest.rs/guide/advanced/playwright) is Rstest's Playwright integration. It provides Playwright-style assertions and fixtures for testing local, preview, or deployed applications while sharing Rstest's runner, configuration, and reporting workflow with unit tests. :::tip If you need the full Playwright Test runner and its `playwright.config.ts` configuration model, use [native Playwright](https://playwright.dev/docs/test-intro). ::: ### Install `@rstest/playwright` Install the Rstest integration and the Playwright browser automation runtime: ```sh [npm] npm add @rstest/playwright playwright -D ``` ```sh [yarn] yarn add @rstest/playwright playwright -D ``` ```sh [pnpm] pnpm add @rstest/playwright playwright -D ``` ```sh [bun] bun add @rstest/playwright playwright -D ``` ```sh [deno] deno add npm:@rstest/playwright npm:playwright -D ``` Then install the Chromium browser binary: ```bash pnpm exec playwright install chromium ``` ### Test a running application Import `test` and `expect` from `@rstest/playwright` and navigate to the application served by Rspack: ```ts title="tests/home.e2e.test.ts" import { expect, test } from '@rstest/playwright'; test('home page', async ({ page }) => { await page.goto('http://localhost:3000'); await expect(page).toHaveTitle(/Rspack/); }); ``` ### Test local build output Use Rstest's `serve` fixture to start a static application from local files. The server is cleaned up automatically after the test: ```ts title="tests/home.e2e.test.ts" import { expect, test } from '@rstest/playwright'; test('home page', async ({ page, serve }) => { const { url } = await serve('./dist/index.html'); await page.goto(url); await expect(page.locator('h1')).toHaveText('Home'); }); ``` End-to-end tests use the Rstest runner, so they can live alongside unit tests and run with the same command: ```bash pnpm run test ``` For more fixtures, browser options, tracing, and debugging, see [Rstest - Playwright](https://rstest.rs/guide/advanced/playwright). --- url: /guide/optimization/production.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Production optimization ## Code splitting Rspack supports code splitting, which allows splitting the code into other chunks. You have the full control about size and number of generated assets, which allow you to gain performance improvements in loading time. See [Code splitting](/guide/optimization/code-splitting.md) for more details. ## Tree shaking Rspack supports tree shaking, a terminology widely used within the JavaScript ecosystem defined as the removal of unused code, commonly referred to as "dead code". See [Tree shaking](/guide/optimization/tree-shaking.md) for more details. ## Minification During the production build, Rspack uses the built-in minimizer to minify JavaScript and CSS code by default. If you need to customize the minification options, you can use [SwcJsMinimizerRspackPlugin](/plugins/swc-js-minimizer-rspack-plugin.md) and [LightningCssMinimizerRspackPlugin](/plugins/lightning-css-minimizer-rspack-plugin.md) for configuration. ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { optimization: { minimizer: [ new rspack.SwcJsMinimizerRspackPlugin({ // JS minimizer configuration }), new rspack.LightningCssMinimizerRspackPlugin({ // CSS minimizer configuration }), ], }, }; ``` If the built-in minimizer cannot meet your needs, you can also use [optimization.minimizer](/config/optimization.md#optimizationminimizer) to set custom minimizers. --- url: /guide/optimization/code-splitting.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Code splitting Rspack supports code splitting, letting you divide your code into separate chunks. You have full control over the size and number of generated assets to improve loading performance. Here, a Chunk refers to a resource that a browser needs to load. ## Dynamic import Rspack uses the [import()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) syntax that conforms to the ECMAScript proposal for dynamic imports. In `index.js`, we dynamically import two modules through `import()`, separating them into a new chunk. ```js title=index.js import('./foo.js'); import('./bar.js'); ``` ```js title=foo.js import './shared.js'; console.log('foo.js'); ``` ```js title=bar.js import './shared.js'; console.log('bar.js'); ``` Building this project produces three chunks: `src_bar_js.js`, `src_foo_js.js`, and `main.js`. Inspecting them shows that `shared.js` exists in both `src_bar_js.js` and `src_foo_js.js`. We will cover how to remove duplicated modules later. :::tip 1. Refer to [Module methods - Dynamic import()](/api/runtime-api/module-methods.md#dynamic-import) for the detailed dynamic import API, as well as how to use dynamic expressions and magic comments in dynamic import. 2. Although `shared.js` exists in two chunks, it is executed only once, so you don't have to worry about multiple instances. 3. Use the [output.asyncChunks option](/config/output.md#outputasyncchunks) to control whether dynamically imported modules generate independent async chunks. ::: ## Entry point This is the simplest and most intuitive way to split the code, but it requires manual configuration. Let's start by looking at how to create multiple Chunks from multiple entry points. ```js title="rspack.config.mjs" export default { mode: 'development', entry: { index: './src/index.js', another: './src/another-module.js', }, stats: 'normal', }; ``` ```js title=index.js import './shared'; console.log('index.js'); ``` ```js title=another-module.js import './shared'; console.log('another-module'); ``` This will yield the following build result: ``` ... Asset Size Chunks Chunk Names another.js 1.07 KiB another [emitted] another index.js 1.06 KiB index [emitted] index Entrypoint another = another.js Entrypoint index = index.js [./src/index.js] 41 bytes {another} {index} [./src/shared.js] 24 bytes {another} {index} ``` Similarly, examining the output shows that they all include the repeated `shared.js`. ## Configuring chunk splitting The splitting approach above is intuitive, but most modern browsers support concurrent network requests. If we split a single-page application into one chunk per page, the browser still has to fetch a large chunk when users switch pages, which wastes that concurrency. Instead, we can break the chunk into smaller ones and request those smaller chunks at the same time to use the browser's network capacity more effectively. Rspack defaults to splitting files in the `node_modules` directory and duplicate modules, extracting these modules from their original Chunk into a separate new Chunk. Why does `shared.js` still appear repeatedly in our example above? The `shared.js` file here is very small, and splitting such a small module into its own Chunk can actually slow down loading. We can configure the minimum split size through [splitChunks.minSize](/plugins/split-chunks-plugin.md#splitchunksminsize) to 0 to allow `shared.js` to be extracted on its own. ```diff title="rspack.config.mjs" export default { entry: { index: './src/index.js', }, + optimization: { + splitChunks: { + minSize: 0, + } + } }; ``` After rebuilding, you will find that `shared.js` has been extracted separately, and there is an additional Chunk in the output that contains only `shared.js`. If `shared.js` still appears duplicated after lowering [`splitChunks.minSize`](/plugins/split-chunks-plugin.md#splitchunksminsize), check [`splitChunks.minSizeReduction`](/plugins/split-chunks-plugin.md#splitchunksminsizereduction), [`splitChunks.minChunks`](/plugins/split-chunks-plugin.md#splitchunksminchunks), and request limits such as [`splitChunks.maxAsyncRequests`](/plugins/split-chunks-plugin.md#splitchunksmaxasyncrequests) / [`splitChunks.maxInitialRequests`](/plugins/split-chunks-plugin.md#splitchunksmaxinitialrequests) before reaching for [`splitChunks.cacheGroups.{cacheGroup}.enforce`](/plugins/split-chunks-plugin.md#splitchunkscachegroupscachegroupenforce). If you want sufficiently large candidates to keep splitting after hitting those request limits, prefer [`splitChunks.enforceSizeThreshold`](/plugins/split-chunks-plugin.md#splitchunksenforcesizethreshold) before forcing an entire cache group with `enforce`. For most production applications, a good baseline is: ```js title="rspack.config.mjs" export default { optimization: { splitChunks: { chunks: 'all', }, }, }; ``` while keeping the default cache groups. This usually deduplicates both initial and async chunks while still allowing the runtime to fetch only the chunks reachable from the current page. ### Force the splitting of certain modules We can use [`optimization.splitChunks.cacheGroups.{cacheGroup}.name`](/plugins/split-chunks-plugin.md#splitchunkscachegroupscachegroupname) to force specific modules to be grouped into the same chunk, for example, with the following configuration: ```js title="rspack.config.mjs" export default { optimization: { splitChunks: { cacheGroups: { someLib: { test: /\/some-lib\//, name: 'lib', }, }, }, }, }; ``` With the above configuration, all files that include the `some-lib` directory in their path can be extracted into a single Chunk named `lib`. If the modules in `some-lib` are rarely changed, this Chunk will consistently hit the user's browser cache, thus a well-considered configuration like this can increase the cache hit rate. However, separating `some-lib` into an independent Chunk can also have downsides. Suppose a Chunk only depends on a very small file within `some-lib`, but since all files of `some-lib` are split into a single Chunk, this Chunk has to rely on the entire `some-lib` Chunk, resulting in a larger load volume. Therefore, when using `cacheGroups.{cacheGroup}.name`, careful consideration is needed. More importantly, `name` is not just a filename choice. A fixed `name` can force different split candidates to be merged into the same shared chunk, which may cause a route to fetch modules from unrelated dependency chains. For most projects, avoid adding `name` unless you intentionally want one shared asset and accept the tradeoff. This tradeoff is about chunk grouping and network fetch boundaries. It does not change JavaScript execution order, and it is unrelated to tree shaking. CSS is a separate caveat: in extracted CSS flows, splitChunks can affect final CSS order. See the [SplitChunksPlugin documentation](/plugins/split-chunks-plugin.md#faq) for details. Here is an example showing the effect of the `name` configuration of cacheGroup. ![](https://assets.rspack.rs/rspack/assets/rspack-splitchunks-name-explain.png) ## Prefetching/Preloading modules Adding these inline directives to your imports allows Rspack to output resource hints that tell the browser that: - **prefetch**: resource is probably needed for some navigation in the future - **preload**: resource will also be needed during the current navigation An example of this is having a `HomePage` component, which renders a `LoginButton` component which then on demand loads a `LoginModal` component after being clicked. ```js title=LoginButton.js //... import(/* webpackPrefetch: true */ './path/to/LoginModal.js'); ``` This will result in `` being appended in the head of the page, which will instruct the browser to prefetch in idle time the `login-modal-chunk.js` file. :::info Rspack will add the prefetch hint once the parent chunk has been loaded. ::: Preload directive has a bunch of differences compared to prefetch: - A preloaded chunk starts loading in parallel to the parent chunk. A prefetched chunk starts after the parent chunk finishes loading. - A preloaded chunk has medium priority and is instantly downloaded. A prefetched chunk is downloaded while the browser is idle. - A preloaded chunk should be instantly requested by the parent chunk. A prefetched chunk can be used anytime in the future. - Browser support is different. An example of this can be having a `Component` which always depends on a big library that should be in a separate chunk. Let's imagine a component `ChartComponent` which needs a huge `ChartingLibrary`. It displays a `LoadingIndicator` when rendered and instantly does an on demand import of `ChartingLibrary`: ```js title=ChartComponent.js //... import(/* webpackPreload: true */ 'ChartingLibrary'); ``` When a page which uses the `ChartComponent` is requested, the charting-library-chunk is also requested via ``. Assuming the page-chunk is smaller and finishes faster, the page will be displayed with a `LoadingIndicator`, until the already requested `charting-library-chunk` finishes. This will give a little load time boost since it only needs one round-trip instead of two. Especially in high-latency environments. :::info Using webpackPreload incorrectly can actually hurt performance, so be careful when using it. ::: Sometimes you need to have your own control over preload. For example, preload of any dynamic import can be done via async script. This can be useful in case of streaming server side rendering. ```js const lazyComp = () => import('DynamicComponent').catch((error) => { // Do something with the error. // For example, we can retry the request in case of any net error }); ``` If the script loading will fail before Rspack starts loading of that script by itself (Rspack creates a script tag to load its code, if that script is not on a page), that catch handler won't start till chunkLoadTimeout is not passed. This behavior can be unexpected. But it's explainable — Rspack can not throw any error, cause Rspack doesn't know, that script failed. Rspack will add onerror handler to the script right after the error has happen. To prevent such problem you can add your own onerror handler, which removes the script in case of any error: ```html ``` In that case, errored script will be removed. Rspack will create its own script and any error will be processed without any timeouts. This page is adapted from [webpack documentation](https://webpack.js.org/guides/code-splitting/) under the [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), with modifications. --- url: /guide/optimization/tree-shaking.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Tree shaking Rspack supports [tree shaking](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking), a term commonly used in the JavaScript ecosystem for removing unused code, also known as "dead code". Dead code occurs when module exports are unused and have no side effects, allowing them to be safely removed to reduce bundle size. ## What is tree shaking Think of your application as a tree. The source code and libraries you actually use are the green, living leaves. Dead code is like the brown, dead leaves consumed by autumn. To remove the dead leaves, you shake the tree and they fall off. Rspack doesn't directly remove dead code—it marks unused exports as potential "dead code". Minification tools then recognize and process these markers. If [minimize](/config/optimization.md#optimizationminimize) is disabled, you won't see any actual code removal. :::tip What is dead code [Dead code](https://en.wikipedia.org/wiki/Dead_code) is code that's no longer executed, typically due to refactoring, optimization, or logical errors. It may be a remnant from previous versions or code that never executes under any condition. ::: ## Prerequisites To effectively leverage tree shaking, you need to: - Set Rspack's [mode](/config/mode.md) to `production` to enable tree shaking optimizations. - In production builds, `mode` defaults to `production`. - Use ES module syntax (`import` and `export`). - When using compilers like SWC or Babel, ensure they don't transform ES modules to CommonJS. - For example, in [@babel/preset-env](https://babeljs.io/docs/en/babel-preset-env), set `modules` to `false`. ## Configurations When [mode](/config/mode.md) is set to `production`, Rspack enables several tree shaking optimizations: - [usedExports](/config/optimization.md#optimizationusedexports): Detects which module exports are used, enabling removal of unused exports. - [sideEffects](/config/optimization.md#optimizationsideeffects): Analyzes modules for side effects. Modules without side effects can be further optimized through re-exports. - [providedExports](/config/optimization.md#optimizationprovidedexports): Analyzes all exports and tracks their re-export sources. - [innerGraph](/config/optimization.md#optimizationinnergraph): Tracks variable usage to more accurately determine if exports are actually used. The following examples illustrate how these options work. For clarity, we'll use simplified code to demonstrate code removal. Let's look at an example with `src/main.js` as the entry point: ```js title='src/main.js' import { foo } from './util.js'; console.log(foo); // `bar` is not used ``` ```js title='src/util.js' export const foo = 1; export const bar = 2; ``` In this example, `bar` from `util.js` is unused. In `production` mode, Rspack enables [usedExports](/config/optimization.md#optimizationusedexports) by default, which detects which exports are used. Unused exports like `bar` are removed. The final output looks like this: ```js title='dist/main.js' const foo = 1; console.log(foo); ``` ## Side effects analysis In `production` mode, Rspack also analyzes modules for side effects. If all exports from a module are unused and the module has no side effects, the entire module can be removed. Let's modify the previous example: ```diff title='src/main.js' import { foo } from './util.js'; - console.log(foo); // `bar` is not used ``` In this case, none of the exports from `util.js` are used, and it’s analyzed as having no side effects, permitting the entire deletion of `util.js`. You can manually indicate whether a module has side effects via `package.json` or `module.rules`. To do this, enable [optimization.sideEffects](/config/optimization.md#optimizationsideeffects). In `package.json`, you can use `true` or `false` to indicate whether all modules in the package have side effects. ```json title="package.json" { "name": "package", "version": "1.0.0", "sideEffects": false } ``` This `package.json` indicates that all modules in this package are side-effect-free. You can also use glob patterns to specify which modules have side effects. Unmatched modules are automatically treated as side-effect-free. If you manually mark side effects, ensure all unmarked modules truly have no side effects. ```json title="package.json" { "name": "package", "version": "1.0.0", "sideEffects": ["./src/main.js", "*.css"] } ``` This `package.json` indicates that only `./src/main.js` and all `.css` files have side effects, while all other modules are side-effect-free. ## Re-export analysis Re-exports are common in development. However, a module might import many other modules while only needing a few exports. Rspack optimizes this by allowing consumers to access the actual exported modules directly. Consider this re-export example: ```js title='src/main.js' import { value } from './re-exports.js'; console.log(value); ``` ```js title='src/re-exports.js' export * from './value.js'; export * from './other.js'; // this can be removed if `other.js` does not have any side effects ``` ```js title='src/value.js' export const value = 42; export const foo = 42; // not used ``` Rspack enables [providedExports](/config/optimization.md#optimizationprovidedexports) by default, which analyzes all exports from a re-exporting module and identifies their origins. If `src/re-exports.js` has no side effects, Rspack can convert the import in `src/main.js` to import directly from `src/value.js`: ```diff title='src/main.js' - import { value } from './re-exports.js'; + import { value } from './value.js'; console.log(value); ``` This allows Rspack to completely skip the `src/re-exports.js` module. By analyzing all re-exports in `src/re-exports.js`, Rspack determines that `foo` from `src/value.js` is unused and removes it from the final output. ## Variable transmission Sometimes exports are imported but not actually used. For example: ```js title='src/main.js' import { foo } from './value.js'; function log() { console.log(foo); } // `log` is not used const bar = foo; // `foo` is not used ``` In this scenario, even though the `log` function and the `bar` variable depend on `foo`, neither is used, so `foo` is considered dead code and removed. When [innerGraph](/config/optimization.md#optimizationinnergraph) is enabled (the default in `production` mode), Rspack can track variable usage across modules to achieve precise code optimization. ```js title='src/main.js' import { value } from './bar.js'; console.log(value); ``` ```js title='src/bar.js' import { foo } from './foo.js'; const bar = foo; export const value = bar; ``` ```js title='src/foo.js' export const foo = 42; ``` Since `value` is used, the `foo` it depends on is retained. ## Pure annotation Use the [`/*#__PURE__*/`](https://github.com/javascript-compiler-hints/compiler-notations-spec/blob/main/pure-notation-spec.md) annotation to tell Rspack that a function call is side-effect-free (pure). Place it before function calls to mark them as having no side effects. When an unused variable's initial value is marked as side-effect-free (pure), it's treated as dead code and removed by the minimizer. ```js /*#__PURE__*/ double(55); ``` :::tip - Function arguments aren't marked by the annotation and may need to be marked individually. - This behavior is enabled when [optimization.innerGraph](/config/optimization.md#optimizationinnergraph) is set to true. ::: ## NO\_SIDE\_EFFECTS annotation `/*#__NO_SIDE_EFFECTS__*/` is a feature that follows the community [JavaScript Compiler Hints Spec](https://github.com/javascript-compiler-hints/compiler-notations-spec/blob/main/no-side-effects-notation-spec.md). Unlike `/*#__PURE__*/` which marks call sites, `/*#__NO_SIDE_EFFECTS__*/` is used to mark **function definitions**, declaring that the function has no side effects when called with arguments. ### Configuration This feature is currently experimental and controlled by `experiments.pureFunctions`, which is enabled by default in production mode. It also depends on [optimization.sideEffects](/config/optimization.md#optimizationsideeffects) being `true` (`sideEffects` is `true` by default in production mode): ```js title="rspack.config.mjs" export default { experiments: { pureFunctions: true, }, }; ``` ### Usage You can place this annotation before function declarations, function expressions, arrow functions, or export statements, check [spec](https://github.com/javascript-compiler-hints/compiler-notations-spec/blob/main/no-side-effects-notation-spec.md) for details: ```js /*#__NO_SIDE_EFFECTS__*/ function foo() { console.log('foo'); } /*#__NO_SIDE_EFFECTS__*/ const bar = () => { console.log('bar'); }; /*#__NO_SIDE_EFFECTS__*/ export default function baz() {} /*#__NO_SIDE_EFFECTS__*/ export function baz() {} ``` If a function is marked as side-effect-free and its return value is unused, Rspack can safely remove the call. Compared to `/*#__PURE__*/`, the advantage is that you only need to mark it once at the definition, and all call sites will benefit. ## pureFunctions `pureFunctions` lets you manually mark top-level identifiers in matched modules as side-effect-free for pure-function-based tree shaking. Each name must resolve to a top-level binding in the module — a function/class/variable declaration, an `import` specifier, or an export alias of one. This is useful for third-party libraries where source code cannot be modified, such as packages in `node_modules`, and for asserting that a particular import is pure on the consumer side. For configuration details, see [`experiments.pureFunctions`](/config/experiments.md#experimentspurefunctions) and [`module.parser.javascript.pureFunctions`](/config/module-parser.md#javascriptpurefunctions). :::warning This option is experimental and only takes effect when `experiments.pureFunctions` is enabled, which is the default in production mode. ::: :::note For default exports configured on the source module, use `default` as the name. ::: For business source code where modification is possible, it is recommended to use the `/*#__NO_SIDE_EFFECTS__*/` annotation. ### Usage This option is configured in `module.rules[i].parser`: ```js title="rspack.config.mjs" export default { experiments: { pureFunctions: true, }, module: { rules: [ // Mark exports of a third-party library as pure. { test: /node_modules\/some-library\/index.js/, parser: { pureFunctions: ['isString', 'default'], }, }, // Or mark the import on the consumer side. { test: /src\/styles\.js$/, parser: { pureFunctions: ['cva'], }, }, ], }, }; ``` Rspack validates each configured name against the matched module. If a configured name does not appear as a top-level binding in the module, Rspack emits a warning. --- url: /guide/diagnostics/analysis.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Bundle analysis ## Rsdoctor's bundle analysis [Rsdoctor](/guide/diagnostics/use-rsdoctor.md) provides the `Bundle Size` module, which is mainly used to analyze the information of the outputs of Rspack, including the size of resources, duplicate packages, and module reference relationships: - **Bundle Overview**: Displays the total number and size of artifacts, as well as the number and size of each file type. It also shows the duplicate packages and their reference chains. - **Bundle Analysis Module**: Analyzes the size and code information of the build artifacts' resources (**Assets**) and the included **Modules**. In this module, you can view the **actual code size of modules after packaging** in the Assets, as well as the original code or **packaged code segments** and **module reference relationships**. ![](https://assets.rspack.rs/others/assets/rsdoctor/bundle-size.jpg) Click on the **"Bundle Size"** option in the navigation bar to view the Bundle analysis report. You can see more details from this page: [Bundle Size](https://rsdoctor.rs/guide/usage/bundle-size) ### Reduce duplicate dependencies Bundle size optimization is an important part in production build because it directly affects the user experience of online users. In this document, we will introduce some common bundle size optimization methods in Rspack. It is common for web projects to bundle multiple versions of third-party dependencies. Duplicate dependencies can lead to increased bundle size and slower build speed. - Detect duplicate dependencies You can use [Rsdoctor](https://rsdoctor.rs) to detect whether there are duplicate dependencies in the project. Rsdoctor will analyze during the build process, find any duplicate bundled dependencies and display them visually: ![](https://assets.rspack.rs/others/assets/rsdoctor/overall-alerts.jpg) For more details, see [Rsdoctor - Duplicate Dependency Problem](https://rsdoctor.rs/blog/topic/duplicate-pkg-problem). ## bundle-stats and statoscope You can also generate a `stats.json` file for further analysis with other bundle analysis tools like [bundle-stats](https://github.com/relative-ci/bundle-stats) or [statoscope](https://github.com/statoscope/statoscope): ```sh $ rspack build --json stats.json ``` --- url: /guide/diagnostics/profile.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Build performance profiling This chapter introduces some common performance bottlenecks and performance profile methods for Rspack. ## Analysis with Rsdoctor [Rsdoctor](https://rsdoctor.rs/) is a build analyzer that can visually display the build process, such as compilation time, code changes before and after compilation, module reference relationships, duplicate modules, etc. Please refer to [Use Rsdoctor](/guide/diagnostics/use-rsdoctor.md) for more information. ## Rspack profile The Rspack CLI supports the use of the `RSPACK_PROFILE` environment variable for build performance profile. ```sh RSPACK_PROFILE=ALL rspack build ``` This command will generate a `.rspack-profile-${timestamp}-${pid}` folder. By default, it contains the `rspack.log` file, which is generated by Rspack based on [tracing](https://github.com/tokio-rs/tracing) and records build timing information as JSON Lines. `@rspack-debug/core` is a diagnostic variant of `@rspack/core` that includes extra debugging and tracing capabilities. If you use `@rspack-debug/core` and set `RSPACK_TRACE_LAYER=perfetto`, the profile directory will contain `rspack.pftrace`, which can be viewed using [ui.perfetto.dev](https://ui.perfetto.dev/). > See [Tracing](/contribute/development/tracing.md) for more information. ## Performance bottlenecks Although Rspack itself provides good build performance, the use of some JavaScript loaders and plugins in Rspack can slow down the build performance, especially on large projects. Some of these issues can be resolved with Rspack's built-in high performance alternatives, while others can be identified and optimized using performance analysis tools. Here are some common cases: ### babel-loader [babel-loader](https://github.com/babel/babel-loader) compiles JavaScript and TypeScript code using Babel. You can replace Babel with the faster SWC. Rspack comes with a built-in [builtin:swc-loader](/guide/features/builtin-swc-loader.md), which is the Rust version of `swc-loader` and is intended to provide better performance. If you need to use some Babel plugins for custom transformations, configure babel-loader with [rules\[\].include](/config/module-rules.md#rulesinclude) to match as few files as possible to reduce the Babel compilation overhead. ### postcss-loader [postcss-loader](https://github.com/postcss/postcss-loader) compiles CSS code based on PostCSS, which is often used with PostCSS plugins to downgrade CSS syntax, add vendor prefixes, etc. You can replace PostCSS with the faster Lightning CSS by using Rspack's built-in [builtin:lightningcss-loader](/guide/features/builtin-lightningcss-loader.md). ### terser-webpack-plugin [terser-webpack-plugin](https://github.com/webpack/terser-webpack-plugin) minifies JavaScript code based on Terser. You can replace Terser with the faster SWC minimizer by using Rspack's built-in [SwcJsMinimizerRspackPlugin](/plugins/swc-js-minimizer-rspack-plugin.md). ### css-minimizer-webpack-plugin [css-minimizer-webpack-plugin](https://github.com/webpack/css-minimizer-webpack-plugin) minifies CSS code based on tools like cssnano. You can replace cssnano with the faster Lightning CSS minimizer by using Rspack's built-in [LightningCssMinimizerRspackPlugin](/plugins/lightning-css-minimizer-rspack-plugin.md). ### less-loader [less-loader](https://github.com/webpack/less-loader) compiles `.less` files based on Less. Since Less currently lacks an officially implemented high performance alternative, it is recommended to use [sass-loader](https://github.com/webpack/sass-loader) and [sass-embedded](https://www.npmjs.com/package/sass-embedded) instead. `sass-embedded` is a JavaScript wrapper for Sass's native Dart executable that provides excellent performance. ### html-webpack-plugin [html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin) performs poorly when generating large numbers of HTML files. The [HtmlRspackPlugin](/plugins/html-rspack-plugin.md) implemented in Rust by Rspack can provide better performance. ### ts-checker-rspack-plugin When using [ts-checker-rspack-plugin](https://github.com/rspack-contrib/ts-checker-rspack-plugin), TypeScript 7 or later is recommended to enable the native type checker and improve type-checking performance on large projects. See the [plugin README](https://github.com/rspack-contrib/ts-checker-rspack-plugin#typescript-7-support) for details. ## Blocking thread pool size Rspack internally uses a dedicated thread pool to handle blocking operations such as file system reads and writes, preventing the main thread from being blocked. By default, the pool size is set to `4`, matching Node.js's [libuv](https://docs.libuv.org/en/v1.x/threadpool.html) behavior, which provides stable performance across most development and CI environments. If your build environment uses high-speed storage, you can adjust the thread count via the `RSPACK_BLOCKING_THREADS` environment variable to improve parallelism and potentially reduce build time, for example: ```bash # Need to install cross-env package to set environment variables cross-env RSPACK_BLOCKING_THREADS=8 rspack build ``` After setting the variable, observe the build time to find the most suitable configuration. On slower or high-latency file systems, it's recommended to keep the default value or even lower it to avoid thread contention. ## Working thread pool size Rspack internally uses a Tokio thread pool and Rayon thread pool to handle CPU bound tasks (Tokio for async tasks and Rayon for sync tasks). By default, Tokio and Rayon automatically determines the number of worker threads based on the number of CPU cores available. If it consumes too much CPU resources during the build process, you can limit the number of worker threads by setting the `TOKIO_WORKER_THREADS` and `RAYON_NUM_THREADS` environment variable, for example: ```bash # Need to install cross-env package to set environment variables cross-env TOKIO_WORKER_THREADS=4 RAYON_NUM_THREADS=4 rspack build ``` Be aware that setting this value too low may lead to longer build times. After setting the variable, observe the build time to find the most suitable configuration. --- url: /guide/diagnostics/use-rsdoctor.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Use Rsdoctor [Rsdoctor](https://rsdoctor.rs/) is a build analyzer tailored for the Rspack ecosystem. Rsdoctor is committed to being a one-stop, intelligent build analyzer that makes the build process transparent, predictable, and optimizable through visualization and smart analysis, helping development teams precisely identify bottlenecks, optimize performance, and improve engineering quality. If you need to debug the build outputs or build process, you can use Rsdoctor for troubleshooting. ## How to use In an Rspack project, you can enable Rsdoctor by following these steps: 1. Install the `@rsdoctor/rspack-plugin` plugin: ```sh [npm] npm add @rsdoctor/rspack-plugin -D ``` ```sh [yarn] yarn add @rsdoctor/rspack-plugin -D ``` ```sh [pnpm] pnpm add @rsdoctor/rspack-plugin -D ``` ```sh [bun] bun add @rsdoctor/rspack-plugin -D ``` ```sh [deno] deno add npm:@rsdoctor/rspack-plugin -D ``` 2. Register the `RsdoctorRspackPlugin` plugin in the [plugins](/config/plugins.md) option of Rspack: ```ts title="rspack.config.mjs" import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin'; export default { plugins: [ // Register the plugin only when RSDOCTOR is true, as the plugin increases build time process.env.RSDOCTOR && new RsdoctorRspackPlugin({ // plugin options }), ], }; ``` 3. Add the `RSDOCTOR=true` variable before the build command: ```bash # dev RSDOCTOR=true rspack serve # build RSDOCTOR=true rspack build ``` As Windows does not support the above usage, you can also use [cross-env](https://npmjs.com/package/cross-env) to set environment variables. This ensures compatibility across different systems: ```bash # dev cross-env RSDOCTOR=true rspack serve # build cross-env RSDOCTOR=true rspack build ``` Rsdoctor will open the build analysis page after the build is complete. For complete features, please refer to [Rsdoctor documentation](https://rsdoctor.rs/). ## Configure Rsdoctor See the [Options](https://rsdoctor.rs/config/options/options) documentation of Rsdoctor to configure the options of the RsdoctorRspackPlugin. ## More features See the [Rsdoctor features](https://rsdoctor.rs/guide/start/features) to learn about all the features of Rsdoctor. --- url: /guide/migration/rspack_1.x.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # Upgrading from v1 to v2 This document lists the breaking changes from Rspack 1.x to 2.0. - For more details, see [Breaking changes in Rspack 2.0](https://github.com/web-infra-dev/rspack/discussions/9270) - For Rsbuild users, see [Rsbuild - Upgrading from v1 to v2](https://v2.rsbuild.rs/guide/upgrade/v1-to-v2) ## Using Agent Skills If your Coding Agent supports Skills, install the [rspack-v2-upgrade](https://github.com/rstackjs/agent-skills#rspack-v2-upgrade) skill to help with the migration. ```bash npx skills add rstackjs/agent-skills --skill rspack-v2-upgrade ``` After installation, let the agent guide you through the upgrade. ## Upgrade Rspack to v2 - Upgrade `@rspack/core` to the 2.0 release. - If you use `@rspack/cli`, `@rspack/dev-server`, or `@rspack/plugin-react-refresh`, upgrade them to the latest compatible versions so they stay in sync with `@rspack/core`. For example: ```json { "devDependencies": { "@rspack/core": "^2.0.0", "@rspack/cli": "^2.0.0", "@rspack/dev-server": "^2.0.0", "@rspack/plugin-react-refresh": "^2.0.0" } } ``` ## Upgrade Node.js Rspack 2.0 requires a minimum Node.js version of **20.19+** or **22.12+**, and Node.js 18 is no longer supported. ## Pure ESM packages `@rspack/core`, `@rspack/cli`, `@rspack/dev-server` and `@rspack/plugin-react-refresh` are now published as **pure ESM** packages, with CommonJS builds removed. In Node.js 20 and later, the runtime natively supports loading ESM modules via [require(esm)](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require), so for most projects that use Rspack through its JavaScript API, this change should have no practical impact and does not require code changes. > This does not affect Rspack's ability to build CommonJS output. All related build behavior and configuration remain unchanged. ## Dev server [@rspack/dev-server](https://npmjs.com/package/@rspack/dev-server) 2.0 includes the following changes: - `@rspack/cli` no longer depends on `@rspack/dev-server` by default, since some workflows do not require a dev server. When using the `rspack dev` or `rspack serve` commands, install `@rspack/dev-server` manually: ```sh [npm] npm add @rspack/dev-server -D ``` ```sh [yarn] yarn add @rspack/dev-server -D ``` ```sh [pnpm] pnpm add @rspack/dev-server -D ``` ```sh [bun] bun add @rspack/dev-server -D ``` ```sh [deno] deno add npm:@rspack/dev-server -D ``` - Some [devServer](/config/dev-server.md) options have changed, including `devServer.proxy` and `devServer.watchFiles`. See the [upgrade guide](https://github.com/rstackjs/rspack-dev-server/blob/main/docs/migrate-v1-to-v2.md) for details. `@rspack/dev-server` dependencies are now more streamlined and modernized: - It introduces the new [@rspack/dev-middleware](https://github.com/rstackjs/rspack-dev-middleware) package to replace `webpack-dev-middleware`. - It uses [connect-next](https://github.com/rstackjs/connect-next) instead of Express v4 as the default middleware framework. ## Bundle analysis The built-in `webpack-bundler-analyzer` has been removed from `@rspack/cli`, and the `--analyze` flag is no longer available. If you need to analyze bundle outputs, it is recommended to use [Rsdoctor](/guide/diagnostics/use-rsdoctor.md), which provides more powerful analysis capabilities. ## Module compilation changes ### Changed default value of module.parser.javascript.exportsPresence The default value of [module.parser.javascript.exportsPresence](/config/module-parser.md#javascriptexportspresence) has been changed from `warn` to `error`. When detecting non-existent exports, an error will now be thrown directly instead of just a warning. If you want to restore the old behavior, you can explicitly set it to `auto`: ```js title="rspack.config.mjs" export default { module: { parser: { javascript: { exportsPresence: 'auto', }, }, }, }; ``` ### Removed module.parser.javascript.strictExportPresence `module.parser.javascript.strictExportPresence` has been removed. You can use [module.parser.javascript.exportsPresence](/config/module-parser.md#javascriptexportspresence) to control the behavior when exports don't exist. ### Changed default value of module.parser.javascript.requireAlias The default value of [module.parser.javascript.requireAlias](/config/module-parser.md#javascriptrequirealias) changed from `true` to `false`. If your code relies on renamed `require` calls being parsed and bundled, explicitly enable it: ```js title="rspack.config.mjs" export default { module: { parser: { javascript: { requireAlias: true, }, }, }, }; ``` ### Disabled builtin:swc-loader reading .swcrc In Rspack 2.0, `builtin:swc-loader` no longer supports reading `.swcrc` files. Move your SWC configuration into the loader options in `rspack.config.js`: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.(?:js|mjs|jsx|ts|tsx)$/, loader: 'builtin:swc-loader', options: { detectSyntax: 'auto', jsc: { transform: { react: { runtime: 'automatic', }, }, }, }, }, ], }, }; ``` ### Removed builtin:swc-loader's rspackExperiments.collectTypeScriptInfo The `rspackExperiments.collectTypeScriptInfo` option of `builtin:swc-loader` has been removed. Use [collectTypeScriptInfo](/guide/features/builtin-swc-loader.md#collecttypescriptinfo) to control TypeScript information collection: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.ts$/, loader: 'builtin:swc-loader', options: { collectTypeScriptInfo: { typeExports: true, }, }, }, ], }, }; ``` ### Moved builtin:swc-loader's rspackExperiments.import The `rspackExperiments.import` option of `builtin:swc-loader` has been moved to the top-level [transformImport](/guide/features/builtin-swc-loader.md#transformimport) option. `rspackExperiments.import` is still supported as a deprecated alias in Rspack 2.0, but you should migrate to `transformImport` to avoid future breakage: ```diff title="rspack.config.mjs" export default { module: { rules: [ { test: /\.js$/, loader: 'builtin:swc-loader', options: { - rspackExperiments: { - import: [ - { - libraryName: 'antd', - style: true, - }, - ], - }, + transformImport: [ + { + libraryName: 'antd', + style: true, + }, + ], }, }, ], }, }; ``` ### Derive loader and plugin targets from target In Rspack 2.0, the `targets` configuration for `builtin:swc-loader`, `builtin:lightningcss-loader`, and `rspack.LightningCssMinimizerRspackPlugin` now defaults to the [target](/config/target.md) configuration. If you need different targets, configure them in the loader or plugin options: ```js title="rspack.config.mjs" export default { target: 'node', module: { rules: [ { test: /\.js$/, loader: 'builtin:swc-loader', options: { env: { targets: 'chrome >= 87', }, }, }, ], }, }; ``` ### New `experiments.pureFunctions` for function-level tree shaking Rspack 2.0 adds an experimental [`experiments.pureFunctions`](/config/experiments.md#experimentspurefunctions) switch for finer-grained, pure-function-based tree shaking across modules. After enabling it, you can choose one of these entry points depending on your code ownership: - Use [module.parser.javascript.pureFunctions](/config/module-parser.md#javascriptpurefunctions) to manually mark top-level exported functions in matched third-party modules such as packages in `node_modules`. - Use `/*#__NO_SIDE_EFFECTS__*/` on function definitions when you can modify the source code directly. ```js title="rspack.config.mjs" export default { experiments: { pureFunctions: true, }, module: { rules: [ { test: /node_modules\/some-library\/index.js/, parser: { pureFunctions: ['isString'], }, }, ], }, }; ``` For more details, see the [pureFunctions section](/guide/optimization/tree-shaking.md#purefunctions) and the [NO\_SIDE\_EFFECTS annotation](/guide/optimization/tree-shaking.md#no_side_effects-annotation) in the [tree shaking guide](/guide/optimization/tree-shaking.md). ## Output configuration changes ### Moved output library options - `output.libraryTarget`: moved to [output.library.type](/config/output.md#outputlibrarytype) - `output.libraryExport`: moved to [output.library.export](/config/output.md#outputlibraryexport) - `output.umdNamedDefine`: moved to [output.library.umdNamedDefine](/config/output.md#outputlibraryumdnameddefine) - `output.auxiliaryComment`: moved to [output.library.auxiliaryComment](/config/output.md#outputlibraryauxiliarycomment) ### Changed default value of output.chunkLoadingGlobal The default value of [output.chunkLoadingGlobal](/config/output.md#outputchunkloadingglobal) changed from `webpackChunk${output.uniqueName}` to `rspackChunk${output.uniqueName}`. If your application depends on the old name, configure it explicitly: ```js title="rspack.config.mjs" export default { output: { chunkLoadingGlobal: 'webpackChunkMyApp', }, }; ``` ### Changed default value of output.hotUpdateGlobal The default value of [output.hotUpdateGlobal](/config/output.md#outputhotupdateglobal) changed from `webpackHotUpdate${output.uniqueName}` to `rspackHotUpdate${output.uniqueName}`. If your application depends on the old name, configure it explicitly: ```js title="rspack.config.mjs" export default { output: { hotUpdateGlobal: 'webpackHotUpdateMyApp', }, }; ``` ### Changed default value of output.bundlerInfo.force The default value of [output.bundlerInfo.force](/config/output.md#outputbundlerinfo) changed from `true` to `false`. In Rspack 2.0, `__rspack_version__` and `__rspack_unique_id__` are injected on demand by default instead of always being added as runtime modules. If your application depends on the previous always-injected behavior, configure it explicitly: ```js title="rspack.config.mjs" export default { output: { bundlerInfo: { force: true, }, }, }; ``` ### Changed default fallback value of output.trustedTypes.policyName The fallback value of [output.trustedTypes.policyName](/config/output.md#outputtrustedtypes) changed from `'webpack'` to `'rspack'`. `policyName` still defaults to `output.uniqueName`, and the fallback is only used when `uniqueName` is not set. If your project relies on the old fallback, update your CSP configuration or set it explicitly: ```js title="rspack.config.mjs" export default { output: { trustedTypes: { policyName: 'webpack', }, }, }; ``` ### Removed output.charset The `output.charset` configuration has been removed. It only added a `charset` attribute to generated ` ``` ```js title="rspack.config.mjs" export default { externals: { dayjs: 'dayjs', }, }; ``` In this case, the `dayjs` module is removed from the bundle and resolved from the external environment at runtime, so code like this still works: ```js import dayjs from 'dayjs'; console.log(dayjs().format('YYYY-MM-DD')); ``` In the configuration above, the key `dayjs` under `externals` matches the module specifier in `import dayjs from 'dayjs'`, meaning that module should not be bundled. The value `dayjs` is then used to access the global variable at runtime. In this basic configuration, the default [externalsType](#externalstype) is `var`, which means Rspack reads it from the global scope. In a browser, this usually means accessing `window.dayjs`. ### String In the example above, the value of `externals` uses the string form. The meaning of that string depends on [externalsType](#externalstype). In general, the string can represent: - a **global variable name** for types such as [`'var'`](#externalstypevar), [`'window'`](#externalstypewindow), [`'global'`](#externalstypeglobal), and [`'this'`](#externalstypethis) - or a **module name** for types such as [`'module'`](#externalstypemodule) and [`'commonjs'`](#externalstypecommonjs) #### Shorthand syntax If you only need to declare one external, you can use the shorter form: ```js title="rspack.config.mjs" export default { externals: 'lodash', // equivalent to externals: { lodash: 'lodash' } }; ``` #### Matching rules String externals use **exact matching**. For example, the configuration below matches `react-dom`, but it does not match subpath imports such as `react-dom/client`: ```js title="rspack.config.mjs" export default { externals: { 'react-dom': 'react-dom', }, externalsType: 'module-import', }; ``` If you want those subpath imports to be externalized as well, list them explicitly: ```js title="rspack.config.mjs" export default { externals: { 'react-dom': 'react-dom', 'react-dom/client': 'react-dom/client', }, externalsType: 'module-import', }; ``` If you need to match a family of similar import specifiers, use a [regular expression](#regexp) instead. #### Specifying the external type You can also specify the external type explicitly with the `${externalsType} ${libraryName}` syntax. This overrides the default value from [externalsType](#externalstype). For example, if the external dependency is provided as an ES module: ```js title="rspack.config.mjs" export default { externals: { react: 'module-import react', }, }; ``` ### string\[]\{#string-array} ```js title="rspack.config.mjs" export default { externals: { subtract: ['./math', 'subtract'], }, }; ``` `subtract: ['./math', 'subtract']` allows you select part of a module, where `./math` is the module and your bundle only requires the subset under the `subtract` variable. When the `externalsType` is `commonjs`, this example would translate to `require('./math').subtract;` while when the `externalsType` is `window`, this example would translate to `window["./math"]["subtract"];` Similar to the [string syntax](#string), you can specify the external library type with the `${externalsType} ${libraryName}` syntax, in the first item of the array, for example: ```js title="rspack.config.mjs" export default { externals: { subtract: ['commonjs ./math', 'subtract'], }, }; ``` ### object :::warning An object with `{ root, commonjs, commonjs2, amd, ... }` is only allowed for [`library.type: 'umd'`](/config/output.md#outputlibrarytype) and [`externalsType: 'umd'`](#externalstype). It's not allowed for other library targets. ::: ```js title="rspack.config.mjs" export default { externals: { // When `library.type: 'umd'` and `externalsType: 'umd'`, the following format must be strictly followed: lodash: { root: '_', // indicates global variable commonjs: 'lodash', commonjs2: 'lodash', amd: 'lodash', }, }, }; ``` This syntax is used to describe all the possible ways that an external library can be made available. `lodash` here is available as `lodash` under AMD and CommonJS module systems but available as `_` in a global variable form. `subtract` here is available via the property `subtract` under the global `math` object (e.g. `window['math']['subtract']`). ### function - **Type:** - `function ({ context, request, contextInfo, getResolve }, callback)` - `function ({ context, request, contextInfo, getResolve }) => promise` It might be useful to define your own function to control the behavior of what you want to externalize from Rspack. [webpack-node-externals](https://www.npmjs.com/package/webpack-node-externals), for example, excludes all modules from the `node_modules` directory and provides options to allowlist packages. Here're arguments the function can receive: - `ctx` (`object`): Object containing details of the file. - `ctx.context` (`string`): The directory of the file which contains the import. - `ctx.request` (`string`): The import path being requested. - `ctx.contextInfo` (`object`): Contains information about the issuer (e.g. the layer and compiler) - `ctx.getResolve`: Get a resolve function with the current resolver options. - `callback` (`function (err, result, type)`): Callback function used to indicate how the module should be externalized. The callback function takes three arguments: - `err` (`Error`): Used to indicate if there has been an error while externalizing the import. If there is an error, this should be the only parameter used. - `result` (`string | string[] | object | boolean`): Describes the external module. - `string | string[] | object`: Describes the external module with the other external formats ([`string`](#string), [`string[]`](#string-array), or [`object`](#object)). - `boolean`: Passing `true` externalizes the dependency using the original request path as the external module name. Passing `false` tells Rspack to skip the remaining external configuration and bundle the dependency instead. - `type` (`string`): Optional parameter that indicates the module [external type](#externalstype) (if it has not already been indicated in the `result` parameter). As an example, to externalize all imports where the import path matches a regular expression you could do the following: ```js title="rspack.config.mjs" export default { externals: [ function ({ context, request }, callback) { if (/^yourregex$/.test(request)) { // Externalize to a commonjs module using the request path return callback(null, 'commonjs ' + request); } // Continue without externalizing the import callback(); }, ], }; ``` Other examples using different module formats: ```js title="rspack.config.mjs" export default { externals: [ function (ctx, callback) { // The external is a `commonjs2` module located in `@scope/library` callback(null, '@scope/library', 'commonjs2'); }, ], }; ``` ```js title="rspack.config.mjs" export default { externals: [ function (ctx, callback) { // The external is a global variable called `nameOfGlobal`. callback(null, 'nameOfGlobal'); }, ], }; ``` ```js title="rspack.config.mjs" export default { externals: [ function (ctx, callback) { // The external is a named export in the `@scope/library` module. callback(null, ['@scope/library', 'namedexport'], 'commonjs'); }, ], }; ``` ```js title="rspack.config.mjs" export default { externals: [ function (ctx, callback) { // The external is a UMD module callback(null, { root: 'componentsGlobal', commonjs: '@scope/components', commonjs2: '@scope/components', amd: 'components', }); }, ], }; ``` ### RegExp You can also use a regular expression to match modules that should be externalized. Any module specifier that matches the pattern will be excluded from the output bundle. ```js title="rspack.config.mjs" export default { externals: /react-dom/i, }; ``` In this example, any module specifier matching `react-dom` will be externalized, including `react-dom` and `react-dom/client`. ### Combining syntaxes Sometimes you may want to use a combination of the above syntaxes. This can be done in the following manner: ```js title="rspack.config.mjs" export default { externals: [ { // String react: 'react', // Object lodash: { commonjs: 'lodash', amd: 'lodash', root: '_', // indicates global variable }, // [string] subtract: ['./math', 'subtract'], }, // Function function ({ context, request }, callback) { if (/^yourregex$/.test(request)) { return callback(null, 'commonjs ' + request); } callback(); }, // Regex /^(jquery|\$)$/i, ], }; ``` :::warning [Default type](#externalstype) will be used if you specify `externals` without a type e.g. `externals: { react: 'react' }` instead of `externals: { react: 'commonjs-module react' }`. ::: ## externalsType - **Type:** `string` `externalsType` determines how Rspack loads external dependencies by default. When using the `'amd'`, `'umd'`, `'system'`, or `'jsonp'` type, [`output.library.type`](/config/output.md#outputlibrarytype) must be set to the same value. For example, only an `'amd'` library can use an `'amd'` external. Set `externalsType` explicitly when an external dependency needs a loading format different from the inferred value. ### Default value The default value is inferred in this order: - If [`output.library`](/config/output.md#outputlibrary) is configured with a type other than `'modern-module'`, `externalsType` defaults to [`output.library.type`](/config/output.md#outputlibrarytype). - Otherwise, if [`output.module`](/config/output.md#outputmodule) is `true`, it defaults to `'module-import'`. - Otherwise, it defaults to `'var'`. For backward compatibility, [`output.library.type: 'modern-module'`](/config/output.md#outputlibrarytype) currently skips the first rule and falls through to the `output.module` rule. Set `externalsType: 'modern-module'` explicitly to opt in to modern module externals. ### Supported values The following types are supported: - `'amd'` - `'amd-require'` - `'assign'` - same as `'var'` - [`'commonjs'`](#externalstypecommonjs) - `'commonjs2'` - `'commonjs-module'` - `'commonjs-static'` - [`'global'`](#externalstypeglobal) - [`'module'`](#externalstypemodule) - [`'import'`](#externalstypeimport) - uses `import()` to load a native ECMAScript module (async module) - [`'module-import'`](#externalstypemodule-import) - [`'modern-module'`](#externalstypemodern-module) - [`'commonjs-import'`](#externalstypecommonjs-import) - `'jsonp'` - [`'node-commonjs'`](#externalstypenode-commonjs) - [`'promise'`](#externalstypepromise) - same as `'var'` but awaits the result (async module) - [`'self'`](#externalstypeself) - `'system'` - [`'script'`](#externalstypescript) - [`'this'`](#externalstypethis) - `'umd'` - `'umd2'` - [`'var'`](#externalstypevar) - [`'window'`](#externalstypewindow) ```js title="rspack.config.mjs" export default { externalsType: 'promise', }; ``` ### externalsType.commonjs Specify the default type of externals as `'commonjs'`. Rspack will generate code like `const X = require('...')` for externals used in a module. **Example** ```js import fs from 'fs-extra'; ``` ```js title="rspack.config.mjs" export default { externalsType: 'commonjs', externals: { 'fs-extra': 'fs-extra', }, }; ``` Will generate into something like: ```js const fs = require('fs-extra'); ``` Note that there will be a `require()` in the output bundle. ### externalsType.global Specify the default type of externals as `'global'`. Rspack will read the external as a global variable on the [`globalObject`](/config/output.md#outputglobalobject). **Example** ```js import jq from 'jquery'; jq('.my-element').animate(/* ... */); ``` ```js title="rspack.config.mjs" export default { externalsType: 'global', externals: { jquery: '$', }, output: { globalObject: 'global', }, }; ``` Will generate into something like ```js const jq = global['$']; jq('.my-element').animate(/* ... */); ``` ### externalsType.module Specify the default type of externals as `'module'`. Rspack will generate code like `import * as X from '...'` for externals used in a module. Make sure to enable [`output.module`](/config/output.md#outputmodule). **Example** ```js import jq from 'jquery'; jq('.my-element').animate(/* ... */); ``` ```js title="rspack.config.mjs" export default { output: { module: true, }, externalsType: 'module', externals: { jquery: 'jquery', }, }; ``` Will generate into something like ```js import * as __rspack_external_jquery from 'jquery'; const jq = __rspack_external_jquery['default']; jq('.my-element').animate(/* ... */); ``` Note that there will be an `import` statement in the output bundle. ### externalsType.import Specify the default type of externals as `'import'`. Rspack will generate code like `import('...')` for externals used in a module. **Example** ```js async function foo() { const jq = await import('jquery'); jq('.my-element').animate(/* ... */); } ``` ```js title="rspack.config.mjs" export default { externalsType: 'import', externals: { jquery: 'jquery', }, }; ``` Will generate into something like ```js var __webpack_modules__ = { jquery: (module) => { module.exports = import('jquery'); }, }; // Rspack runtime... async function foo() { const jq = await Promise.resolve(/* import() */).then( __webpack_require__.bind(__webpack_require__, 'jquery'), ); jq('.my-element').animate(/* ... */); } ``` Note that there will be an `import()` statement in the output bundle. ### externalsType\['module-import'] Specify the default type of externals as `'module-import'`. This combines [`'module'`](#externalstypemodule) and [`'import'`](#externalstypeimport). Rspack will automatically detect the type of import syntax, setting it to `'module'` for static imports and `'import'` for dynamic imports. **Example** ```js import { attempt } from 'lodash'; async function foo() { const jq = await import('jquery'); attempt(() => jq('.my-element').animate(/* ... */)); } ``` ```js title="rspack.config.mjs" export default { externalsType: 'module-import', externals: { lodash: 'lodash', jquery: 'jquery', }, }; ``` Will generate into something like ```js import * as __rspack_external_lodash from 'lodash'; const lodash = __rspack_external_jquery; var __webpack_modules__ = { jquery: (module) => { module.exports = import('jquery'); }, }; // Rspack runtime... async function foo() { const jq = await Promise.resolve(/* import() */).then( __webpack_require__.bind(__webpack_require__, 'jquery'), ); (0, lodash.attempt)(() => jq('.my-element').animate(/* ... */)); } ``` Note that there will be an `import` or `import()` statement in the output bundle. When a module is not imported via `import` or `import()`, Rspack will use `"module"` externals type as fallback. If you want to use a different type of externals as fallback, you can specify it with a function in the `externals` option. For example: ```js title="rspack.config.mjs" export default { externalsType: 'module-import', externals: [ function ({ request, dependencyType }, callback) { if (dependencyType === 'commonjs') { return callback(null, `node-commonjs ${request}`); } callback(); }, ], }; ``` ### externalsType\['modern-module'] Specify the default type of externals as `'modern-module'`. For compatibility, Rspack does not enable this automatically when [`output.library.type`](/config/output.md#outputlibrarytype) is `'modern-module'` yet. Configure `externalsType: 'modern-module'` explicitly to opt in. This will become the default for `modern-module` libraries in the next major version. For static ESM imports, Rspack renders the external like [`'module'`](#externalstypemodule), using a static `import` statement. For dynamic `import()`, Rspack renders the external like [`'module-import'`](#externalstypemodule-import), using `import()`. For CommonJS `require()`, Rspack chooses the CommonJS external variant from the target. Node-like targets render the external like [`'node-commonjs'`](#externalstypenode-commonjs) and create a `require` function with `createRequire` in the generated ESM output. Other targets render it like [`'commonjs'`](#externalstypecommonjs), preserving a bare `require()` call. **Example** ```js title="src/index.js" import { readFile } from 'node:fs/promises'; const path = require('node:path'); export async function loadConfig(file) { const os = await import('node:os'); const content = await readFile(file, 'utf-8'); return { content, dirname: path.dirname(file), platform: os.platform(), }; } ``` ```js title="rspack.config.mjs" export default { target: 'node', output: { library: { type: 'modern-module', }, }, externalsType: 'modern-module', externals: ['node:fs/promises', 'node:path', 'node:os'], }; ``` Because this example targets Node.js, the generated ESM output keeps the static import as an `import` statement, keeps the dynamic import as `import()`, and renders the `require()` external through `createRequire`: ```js import { createRequire as __rspack_createRequire } from 'node:module'; import { readFile } from 'node:fs/promises'; const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); const path = __rspack_createRequire_require('node:path'); async function loadConfig(file) { const os = await import('node:os'); // ... } export { loadConfig }; ``` ### externalsType\['commonjs-import'] Specify the default type of externals as `'commonjs-import'`. This combines [`'commonjs'`](#externalstypecommonjs) and [`'import'`](#externalstypeimport). Rspack will automatically detect the type of import syntax, setting dynamic import to `'import'` and leaving others to `'commonjs'`. This is useful when building a Node.js application that target Node.js version higher than `13.2.0`, which supports both [`import()` expressions](https://nodejs.org/api/esm.html#import-expressions) and `require()`. :::note `commonjs-import` type is only available of Rspack, and not applicable for webpack. ::: **Example** ```js import { attempt } from 'lodash'; async function foo() { const jq = await import('jquery'); attempt(() => jq('.my-element').animate(/* ... */)); } ``` ```js title="rspack.config.mjs" export default { externalsType: 'commonjs-import', externals: { lodash: 'lodash', jquery: 'jquery', }, }; ``` Will generate into something like ```js var __webpack_modules__ = { lodash: function (module) { module.exports = require('lodash'); }, jquery: function (module) { module.exports = import('jquery'); }, }; // Rspack runtime... async function foo() { const jq = await Promise.resolve(/* import() */).then( __webpack_require__.bind(__webpack_require__, 'jquery'), ); (0, lodash__rspack_import_0__.attempt)(() => jq('.my-element').animate(/* ... */), ); } ``` Note that there will be an `import()` statement in the output bundle. ### externalsType\['node-commonjs'] Specify the default type of externals as `'node-commonjs'`. Rspack will import [`createRequire`](https://nodejs.org/api/module.html#module_module_createrequire_filename) from `'module'` to construct a require function for loading externals used in a module. **Example** ```js import jq from 'jquery'; jq('.my-element').animate(/* ... */); ``` ```js title="rspack.config.mjs" export default { externalsType: 'node-commonjs', externals: { jquery: 'jquery', }, }; ``` Will generate into something like ```js import { createRequire } from 'node:module'; const jq = createRequire(import.meta.url)('jquery'); jq('.my-element').animate(/* ... */); ``` Note that there will be an `import` statement in the output bundle. ### externalsType.promise Specify the default type of externals as `'promise'`. Rspack will read the external as a global variable (similar to [`'var'`](#externalstypepromise)) and `await` for it. **Example** ```js import jq from 'jquery'; jq('.my-element').animate(/* ... */); ``` ```js title="rspack.config.mjs" export default { externalsType: 'promise', externals: { jquery: '$', }, }; ``` Will generate into something like ```js const jq = await $; jq('.my-element').animate(/* ... */); ``` ### externalsType.self Specify the default type of externals as `'self'`. Rspack will read the external as a global variable on the `self` object. **Example** ```js import jq from 'jquery'; jq('.my-element').animate(/* ... */); ``` ```js title="rspack.config.mjs" export default { externalsType: 'self', externals: { jquery: '$', }, }; ``` Will generate into something like ```js const jq = self['$']; jq('.my-element').animate(/* ... */); ``` ### externalsType.script Specify the default type of externals as `'script'`. Rspack will load the external as a script exposing predefined global variables with HTML ` ``` ## output.cssChunkFilename - **Type:** `string | ((pathData: PathData, assetInfo?: AssetInfo) => string)` - **Default:** Determined by [`output.chunkFilename`](/config/output.md#outputchunkfilename) when it is not a function, otherwise `'[id].css'`. This option determines the name of non-initial CSS output files on disk. See [`output.filename`](/config/output.md#outputfilename) option for details on the possible values. For a string `output.chunkFilename`, Rspack replaces its `.js`, `.mjs`, or `.cjs` extension with `.css`, preserving any query string. For a function, the default is `'[id].css'`; the function is not called to derive the CSS filename. You **must not** specify an absolute path here. However, feel free to include folders separated by `'/'`. This specified path combines with the [`output.path`](#outputpath) value to pinpoint the location on the disk. ## output.cssFilename - **Type:** `string | ((pathData: PathData, assetInfo?: AssetInfo) => string)` - **Default:** Derived from [`output.filename`](#outputfilename) when it is a string, otherwise `'[id].css'`. This option determines the name of CSS output files on disk. See [`output.filename`](/config/output.md#outputfilename) option for details on the possible values. For a string `output.filename`, Rspack replaces its `.js`, `.mjs`, or `.cjs` extension with `.css`, preserving any query string. If none of these extensions is present, the string is unchanged. | `output.filename` | Default `output.cssFilename` | | ------------------------ | ---------------------------- | | `'scripts/[name].js'` | `'scripts/[name].css'` | | `'[name].mjs?version=1'` | `'[name].css?version=1'` | | A function | `'[id].css'` | When using a function for JavaScript filenames, configure CSS filenames separately if you need named CSS assets: ```js title="rspack.config.mjs" export default { output: { filename: () => 'scripts/[name].js', cssFilename: 'styles/[name].css', }, }; ``` You **must not** specify an absolute path here. However, feel free to include folders separated by `'/'`. This specified path combines with the [`output.path`](#outputpath) value to pinpoint the location on the disk. ## output.devtoolFallbackModuleFilenameTemplate - **Type:** ```ts type DevtoolFallbackModuleFilenameTemplate = string | ((context: ModuleFilenameTemplateContext) => string); ``` - **Default:** `undefined` A fallback is used when the template string or function above yields duplicates. See [`output.devtoolModuleFilenameTemplate`](/config/output.md#outputdevtoolmodulefilenametemplate). ## output.devtoolModuleFilenameTemplate - **Type:** ```ts type DevtoolModuleFilenameTemplate = string | ((context: ModuleFilenameTemplateContext) => string); ``` - **Default:** `webpack://[namespace]/[resource-path]?[loaders]'` This option is only used when [`devtool`](/config/devtool.md) uses an option that requires module names. Customize the names used in each source map's `sources` array. This can be done by passing a template string or function. For example, when using `devtool: 'eval'`. ```js title="rspack.config.mjs" export default { output: { devtoolModuleFilenameTemplate: 'webpack://[namespace]/[resource-path]?[loaders]', }, }; ``` The following substitutions are available in template strings | Template | Description | | ------------------------- | --------------------------------------------------------------------------------------------------------------------- | | \[absolute-resource-path] | The absolute filename | | \[relative-resource-path] | Resource path relative to the source map file’s directory, or to the emitted asset’s directory for inline source maps | | \[all-loaders] | Automatic and explicit loaders and params up to the name of the first loader | | \[hash] | The hash of the module identifier | | \[id] | The module identifier | | \[loaders] | Explicit loaders and params up to the name of the first loader | | \[resource] | The path used to resolve the file and any query params used on the first loader | | \[resource-path] | The path used to resolve the file without any query params | | \[namespace] | The modules namespace. This is usually the library name when building as a library, empty otherwise | When using a function, the same options are available camel-cased via the `info` parameter: ```js title="rspack.config.mjs" export default { output: { devtoolModuleFilenameTemplate: (info) => { return `webpack:///${info.resourcePath}?${info.loaders}`; }, }, }; ``` If multiple modules would result in the same name, [`output.devtoolFallbackModuleFilenameTemplate`](#outputdevtoolfallbackmodulefilenametemplate) is used instead for these modules. ## output.devtoolNamespace - **Type:** `string` - **Default:** `undefined` This option determines the module's namespace used with the [`output.devtoolModuleFilenameTemplate`](#outputdevtoolmodulefilenametemplate). When not specified, it will default to the value of: [`output.uniqueName`](#outputuniquename). It's used to prevent source file path collisions in sourcemaps when loading multiple libraries built with Rspack. For example, if you have 2 libraries, with namespaces `library1` and `library2`, which both have a file `./src/index.js` (with potentially different contents), they will expose these files as `webpack://library1/./src/index.js` and `webpack://library2/./src/index.js`. ## output.enabledChunkLoadingTypes - **Type:** `('jsonp' | 'import-scripts' | 'require' | 'async-node' | string)[]` - **Default:** Determined by [`output.chunkLoading`](#outputchunkloading), [`output.workerChunkLoading`](#outputworkerchunkloading) and Entry's chunkLoading config. List of chunk loading types enabled for use by entry points. Will be automatically filled by Rspack. Only needed when using a function as entry option and returning chunkLoading option from there. ```js title="rspack.config.mjs" export default { output: { enabledChunkLoadingTypes: ['jsonp', 'require'], }, }; ``` ## output.enabledLibraryTypes - **Type:** `string[]` - **Default:** Determined by [output.library](#outputlibrary) and [Entry](/config/entry.md) List of library types enabled for use by entry points. ```js title="rspack.config.mjs" export default { output: { enabledLibraryTypes: ['module'], }, }; ``` ## output.enabledWasmLoadingTypes - **Type:** `('...' | 'fetch' | 'async-node' | 'universal')[]` - **Default:** Determined by [`output.wasmLoading`](#outputwasmloading) and [`output.workerWasmLoading`](#outputworkerwasmloading) List of Wasm loading types enabled for use by entry points. ```js title="rspack.config.mjs" export default { output: { enabledWasmLoadingTypes: ['fetch'], }, }; ``` ## output.environment - **Type:** ```ts type Environment = { /** The environment supports arrow functions ('() => { ... }'). */ arrowFunction?: boolean; /** The environment supports async function and await ('async function () { await ... }'). */ asyncFunction?: boolean; /** The environment supports BigInt as literal (123n). */ bigIntLiteral?: boolean; /** The environment supports const and let for variable declarations. */ const?: boolean; /** The environment supports computed property names in object literals ('{ [expr]: value }'). */ computedProperty?: boolean; /** The environment supports destructuring ('{ a, b } = obj'). */ destructuring?: boolean; /** The environment supports 'document' variable. */ document?: boolean; /** The environment supports an async import() function to import ECMAScript modules. */ dynamicImport?: boolean; /** The environment supports an async import() when creating a worker, only for web targets at the moment. */ dynamicImportInWorker?: boolean; /** The environment supports `import.meta.dirname` and `import.meta.filename`. */ importMetaDirnameAndFilename?: boolean; /** The environment supports 'for of' iteration ('for (const x of array) { ... }'). */ forOf?: boolean; /** The environment supports 'globalThis'. */ globalThis?: boolean; /** The environment supports { fn() {} } */ methodShorthand?: boolean; /** The environment supports ECMAScript Module syntax to import ECMAScript modules (import ... from '...'). */ module?: boolean; /** * Determines if the node: prefix is generated for core module imports in environments that support it. * This is only applicable to Rspack runtime code. * */ nodePrefixForCoreModules?: boolean; /** The environment supports optional chaining ('obj?.a' or 'obj?.()'). */ optionalChaining?: boolean; /** The environment supports logical assignment ('a ||= b'). */ logicalAssignment?: boolean; /** The environment supports template literals. */ templateLiteral?: boolean; }; ``` `output.environment` specifies which ECMAScript language features and host environment capabilities Rspack is allowed to use when generating its runtime code. This setting affects only code emitted by Rspack itself, such as runtime helpers. It does not downgrade your application source code. ### Default behavior By default, `output.environment` is automatically inferred from your [target](/config/target.md) configuration. Rspack evaluates `target` to determine which features your target environment supports. For example: - If the target browsers support arrow functions, Rspack will use arrow functions in the runtime to produce more compact output. - If `target` specifies a particular Node.js version, Rspack will infer the supported syntax from that version’s capabilities. In general, you do not need to configure this option manually. You would override it only when you want to explicitly enforce or restrict specific features. Manual configuration replaces the inferred values and gives you direct control over the syntax used in the generated runtime. ### Example Suppose `target` is set to `['web', 'es2018']`. In this case, Rspack will infer that `const` is supported and enable it by default. You can disable it by setting `output.environment.const: false`. Rspack will then emit runtime code that uses `var` declarations instead. ```js title="rspack.config.mjs" export default { target: ['web', 'es2018'], output: { environment: { const: false, }, }, }; ``` ## output.filename - **Type:** `string | ((pathData: PathData, assetInfo?: AssetInfo) => string)` - **Default:** When [`output.module`](#outputmodule) is `true`, it is `'[name].mjs'`, otherwise it is `'[name].js'`. This option determines the name of each output bundle. The bundle is written to the directory specified by the [`output.path`](#outputpath) option. For a single [`entry`](/config/entry.md) point, this can be a static name. ```js title="rspack.config.mjs" export default { output: { filename: 'bundle.js', }, }; ``` However, when creating multiple bundles via more than one entry point, code splitting, or various plugins, you should use one of the following substitutions to give each bundle a unique name... :::info Description of other cases where multiple bundles can be split Rspack performs code splitting optimizations on user input code, which may include, but are not limited to, code splitting, bundle splitting, or splitting implemented through other plugins. These splitting actions can result in multiple bundles being generated, so the filenames of the bundles need to be generated dynamically. ::: Use [Entry](/config/entry.md) name: ```js title="rspack.config.mjs" export default { output: { filename: '[name].bundle.js', }, }; ``` Using internal chunk id: ```js title="rspack.config.mjs" export default { output: { filename: '[id].bundle.js', }, }; ``` Using hashes generated from the generated content: ```js title="rspack.config.mjs" export default { output: { filename: '[contenthash].bundle.js', }, }; ``` Combining multiple substitutions: ```js title="rspack.config.mjs" export default { output: { filename: '[name].[contenthash].bundle.js', }, }; ``` :::tip See [Filename placeholders](/config/filename-placeholders.md) for more information. ::: Using the function to return the filename: ```js title="rspack.config.mjs" export default { output: { filename: (pathData) => { return pathData.chunk.name === 'main' ? '[name].js' : '[name]/[name].js'; }, }, }; ``` Note this option is called filename but you are still allowed to use something like `'js/[name]/bundle.js'` to create a folder structure. Note this option does not affect output files for on-demand-loaded chunks. It only affects output files that are initially loaded. For on-demand-loaded chunk files, the [`output.chunkFilename`](#outputchunkfilename) option is used. Files created by loaders also aren't affected. In this case, you would have to try the specific loader's available options. ## output.globalObject - **Type:** `string` - **Default:** `'self'` When targeting a library, especially when `library.type` is `'umd'`, this option indicates what global object will be used to mount the library. To make UMD build available on both browsers and Node.js, set `output.globalObject` option to `'this'`. Defaults to `self` for Web-like targets. The return value of your entry point will be assigned to the global object using the value of `output.library.name`. Depending on the value of the `type` option, the global object could change respectively, e.g., `self`, `global`, or `globalThis`. For example: ```js title="rspack.config.mjs" export default { output: { library: { name: 'myLib', type: 'umd', }, filename: 'myLib.js', globalObject: 'this', }, }; ``` ## output.hashDigest - **Type:** `string` - **Default:** `'hex'` The encoding to use when generating the hash. Using `'base64'` for filenames might be problematic since it has the character `/` in its alphabet. Likewise `'latin1'` could contain any character. ## output.hashDigestLength - **Type:** `number` - **Default:** `16` The prefix length of the hash digest to use, see [Hash length](/config/filename-placeholders.md#hash-length) for more details. ```js title="rspack.config.mjs" export default { output: { hashDigestLength: 8, }, }; ``` ## output.hashFunction - **Type:** `'md4' | 'xxhash64' | 'sha256'` - **Default:** `'xxhash64'` The hashing algorithm to use. ```js title="rspack.config.mjs" export default { output: { hashFunction: 'xxhash64', }, }; ``` ## output.hashSalt - **Type:** `string` - **Default:** `undefined` An optional salt to update the hash. ## output.hotUpdateChunkFilename - **Type:** `string` - **Default:** When [`output.module`](#outputmodule) is `true`, it is `'[id].[fullhash].hot-update.mjs'`, otherwise it is `'[id].[fullhash].hot-update.js'`. Customize the filenames of hot update chunks. See [`output.filename`](#outputfilename) option for details on the possible values. The only placeholders allowed here are `[id]` and `[fullhash]`. For example: ```js title="rspack.config.mjs" export default { output: { hotUpdateChunkFilename: '[id].[fullhash].hot-update.js', }, }; ``` :::tip Typically you don't need to change `output.hotUpdateChunkFilename`. ::: ## output.hotUpdateGlobal - **Type:** `string` - **Default:** `"rspackHotUpdate" + output.uniqueName` Only used when [`target`](/config/target.md) is set to `'web'`, which uses JSONP for loading hot updates. A JSONP function is used to asynchronously load hot-update chunks. For details see [`output.chunkLoadingGlobal`](#outputchunkloadingglobal). ## output.hotUpdateMainFilename - **Type:** `string` - **Default:** When [`output.module`](#outputmodule) is `true`, it is `'[runtime].[fullhash].hot-update.json.mjs'`, otherwise it is `'[runtime].[fullhash].hot-update.json'`. Customize the main hot update filename. `[fullhash]` and `[runtime]` are available as placeholder. :::tip Typically you don't need to change `output.hotUpdateMainFilename`. ::: ## output.iife - **Type:** `boolean` - **Default:** `false` when [`output.module`](#outputmodule) is `true`, otherwise `true`. Tells Rspack to add [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) wrapper around emitted code. ```js title="rspack.config.mjs" export default { output: { iife: true, }, }; ``` ## output.importFunctionName - **Type:** `string` - **Default:** `'import'` The name of the native `import()` function. Can be used for polyfilling, e.g. with [`dynamic-import-polyfill`](https://github.com/GoogleChromeLabs/dynamic-import-polyfill). ```js title="rspack.config.mjs" export default { output: { importFunctionName: '__import__', }, }; ``` ## output.importMetaName - **Type:** `string` - **Default:** `'import.meta'` The name of the native `import.meta` object (can be exchanged for a polyfill). ```js title="rspack.config.mjs" export default { output: { importMetaName: 'pseudoImport.meta', }, }; ``` ## output.library Output a library exposing the exports of your entry point. - **Type:** `string | string[] | object` Let's take a look at an example. ```js title="rspack.config.mjs" export default { entry: './src/index.js', output: { library: 'MyLibrary', }, }; ``` Say you have exported a function in your `src/index.js` entry: ```js export function hello(name) { console.log(`hello ${name}`); } ``` Now the variable `MyLibrary` will be bound with the exports of your entry file, and here's how to consume the Rspack bundled library: ```html ``` In the above example, we're passing a single entry file to `entry`, however, Rspack can accept [many kinds of entry point](/config/entry.md), e.g., an `array`, or an `object`. 1. If you provide an `array` as the `entry` point, only the last one in the array will be exposed. ```js title="rspack.config.mjs" export default { entry: ['./src/a.js', './src/b.js'], // only exports in b.js will be exposed output: { library: 'MyLibrary', }, }; ``` 2. If an `object` is provided as the `entry` point, all entries can be exposed using the `array` syntax of `library`: ```js title="rspack.config.mjs" export default { entry: { a: './src/a.js', b: './src/b.js', }, output: { filename: '[name].js', library: ['MyLibrary', '[name]'], // name is a placeholder here }, }; ``` Assuming that both `a.js` and `b.js` export a function `hello`, here's how to consume the libraries: ```html ``` ### output.library.amdContainer - **Type:** `string` Use a container(defined in global space) for calling `define`/`require` functions in an AMD module. :::warning Note that the value of `amdContainer` **must be** set as a global variable. ::: ```js title="rspack.config.mjs" export default { output: { library: { amdContainer: 'window["clientContainer"]', type: 'amd', // or 'amd-require' }, }, }; ``` Which will result in the following bundle: ```js window['clientContainer'].define(/*define args*/); // or 'amd-require' window['clientContainer'].require(/*require args*/); ``` ### output.library.name Specify a name for the library. - **Type:** `string | string[] | {amd?: string, commonjs?: string, root?: string | string[]}` ```js title="rspack.config.mjs" export default { output: { library: { name: 'MyLibrary', }, }, }; ``` ### output.library.type Configure how the library will be exposed. - **Type:** `string` Types included by default are `'var'`, `'module'`, `'modern-module'`, `'system'`, `'assign'`, `'assign-properties'`, `'this'`, `'window'`, `'self'`, `'global'`, `'commonjs'`, `'commonjs2'`, `'commonjs-module'`, `'commonjs-static'`, `'amd'`, `'amd-require'`, `'umd'`, `'umd2'`, `'jsonp'`, but others might be added by plugins. For the following examples, we'll use `_entry_return_` to indicate the values returned by the entry point. #### Expose a variable These options assign the return value of the entry point (e.g. whatever the entry point exported) to the name provided by [`output.library.name`](#outputlibraryname) at whatever scope the bundle was included at. ##### type: 'var' ```js title="rspack.config.mjs" export default { output: { library: { name: 'MyLibrary', type: 'var', }, }, }; ``` When your library is loaded, the **return value of your entry point** will be assigned to a variable: ```js var MyLibrary = _entry_return_; // In a separate script with `MyLibrary` loaded… MyLibrary.doSomething(); ``` ##### type: 'assign' ```js title="rspack.config.mjs" export default { output: { library: { name: 'MyLibrary', type: 'assign', }, }, }; ``` This will generate an implied global which has the potential to reassign an existing value (use with caution): ```js MyLibrary = _entry_return_; ``` Be aware that if `MyLibrary` isn't defined earlier your library will be set in global scope. ##### type: 'assign-properties' ```js title="rspack.config.mjs" export default { output: { library: { name: 'MyLibrary', type: 'assign-properties', }, }, }; ``` Similar to [`type: 'assign'`](#type-assign) but a safer option as it will reuse `MyLibrary` if it already exists: ```js // only create MyLibrary if it doesn't exist MyLibrary = typeof MyLibrary === 'undefined' ? {} : MyLibrary; // then copy the return value to MyLibrary // similarly to what Object.assign does // for instance, you export a `hello` function in your entry as follow export function hello(name) { console.log(`Hello ${name}`); } // In another script with MyLibrary loaded // you can run `hello` function like so MyLibrary.hello('World'); ``` #### Expose via object assignment These options assign the return value of the entry point (e.g. whatever the entry point exported) to a specific object under the name defined by [`output.library.name`](#outputlibraryname). ##### type: 'this' ```js title="rspack.config.mjs" export default { output: { library: { name: 'MyLibrary', type: 'this', }, }, }; ``` The **return value of your entry point** will be assigned to `this` under the property named by `output.library.name`. The meaning of `this` is up to you: ```js this['MyLibrary'] = _entry_return_; // In a separate script this.MyLibrary.doSomething(); MyLibrary.doSomething(); // if `this` is window ``` ##### type: 'window' ```js title="rspack.config.mjs" export default { output: { library: { name: 'MyLibrary', type: 'window', }, }, }; ``` The **return value of your entry point** will be assigned to the `window` object using the `output.library.name` value. ```js window['MyLibrary'] = _entry_return_; window.MyLibrary.doSomething(); ``` ##### type: 'global' ```js title="rspack.config.mjs" export default { output: { library: { name: 'MyLibrary', type: 'global', }, }, }; ``` The **return value of your entry point** will be assigned to the global object using the `output.library.name` value. Depending on the [`target`](/config/target.md) value, the global object could change respectively, e.g., `self`, `global` or `globalThis`. ```js global['MyLibrary'] = _entry_return_; global.MyLibrary.doSomething(); ``` ##### type: 'commonjs' ```js title="rspack.config.mjs" export default { output: { library: { name: 'MyLibrary', type: 'commonjs', }, }, }; ``` The **return value of your entry point** will be assigned to the `exports` object using the `output.library.name` value. As the name implies, this is used in CommonJS environments. ```js exports['MyLibrary'] = _entry_return_; require('MyLibrary').doSomething(); ``` :::warning Note that not setting a `output.library.name` will cause all properties returned by the entry point to be assigned to the given object; there are no checks against existing property names. ::: #### Module definition systems These options will result in a bundle that comes with a complete header to ensure compatibility with various module systems. The `output.library.name` option will take on a different meaning under the following `output.library.type` options. ##### type: 'module' ```js title="rspack.config.mjs" export default { output: { library: { // do not specify a `name` here type: 'module', }, }, }; ``` Output ES modules. This is the more compatibility-oriented ESM library path: Rspack still uses the regular chunk / runtime rendering pipeline and then converts the entry exports into `export` statements. It fits simpler ESM library output, or cases where you mainly want webpack-style `module` semantics. ##### type: 'modern-module' ```js title="rspack.config.mjs" export default { output: { library: { // do not specify a `name` here type: 'modern-module', }, }, }; ``` This configuration enables Rspack's dedicated rendering pipeline for ESM libraries. It emits direct `import` / `export` statements and supports library-oriented tree shaking, scope hoisting, code splitting, and [`output.library.preserveModules`](#outputlibrarypreservemodules). :::tip `module` vs `modern-module` - `module` stays on the regular chunk / runtime rendering pipeline and is closer to webpack-compatible ESM semantics. - `modern-module` is handled by a dedicated ESM library plugin that owns chunk rendering, linking, scope hoisting, and splitChunks behavior, making it a better fit for publishable tree-shakable, code-split ESM libraries. - `modern-module` currently exists as a separate type to fill the ESM library capability gap; once it is mature enough, the long-term direction is to converge it with `module` into a single `library.type`. - `preserveModules` is only available with `modern-module`. - When `output.library` is configured and `output.module = true`, Rspack currently defaults `output.library.type` to `modern-module` if you don't specify one explicitly. - Do not mix `modern-module` with other library types in the same compilation, because it also changes chunk loading, chunk rendering, and scope-hoisting behavior. ::: ##### type: 'commonjs2' ```js title="rspack.config.mjs" export default { output: { library: { // note there's no `name` here type: 'commonjs2', }, }, }; ``` The **return value of your entry point** will be assigned to the `module.exports`. As the name implies, this is used in Node.js (CommonJS) environments: ```js module.exports = _entry_return_; require('MyLibrary').doSomething(); ``` If we specify `output.library.name` with `type: commmonjs2`, the return value of your entry point will be assigned to the `module.exports.[output.library.name]`. :::tip Wondering the difference between CommonJS and CommonJS2 is? While they are similar, there are some subtle differences between them that are not usually relevant in the context of Rspack. (For further details, please [read this issue](https://github.com/webpack/webpack/issues/1114).) ::: ##### type: 'commonjs-static' ```js title="rspack.config.mjs" export default { output: { library: { // note there's no `name` here type: 'commonjs-static', }, }, }; ``` Individual exports will be set as properties on `module.exports`. The "static" in the name refers to the output being statically analysable, and thus named exports are importable into ESM via Node.js: Input: ```js export function doSomething() {} ``` Output: ```js function doSomething() {} exports.doSomething = __webpack_exports__.doSomething; ``` Consumption (CommonJS): ```js const { doSomething } = require('./output.cjs'); // doSomething => [Function: doSomething] ``` Consumption (ESM): ```js import { doSomething } from './output.cjs'; // doSomething => [Function: doSomething] ``` :::tip This is useful when source code is written in ESM and the output should be compatible with both CJS and ESM. For further details, please [read this issue](https://github.com/webpack/webpack/issues/14998) or [this article](https://dev.to/jakobjingleheimer/configuring-commonjs-es-modules-for-nodejs-12ed) (specifically, [this section](https://dev.to/jakobjingleheimer/configuring-commonjs-es-modules-for-nodejs-12ed#publish-only-a-cjs-distribution-with-property-exports)). ::: :::tip How To Choose A CommonJS `library.type` | Type | Writes To | Better Fit | | ----------------- | ------------------- | --------------------------------------------------------------------------------------- | | `commonjs` | `exports[...]` | Compatibility with legacy configs that intentionally write to the `exports` object | | `commonjs2` | `module.exports` | General Node.js / CJS library output; the preferred choice for most new configs | | `commonjs-module` | `module.exports` | Currently equivalent to `commonjs2`, mainly for historical webpack config compatibility | | `commonjs-static` | `exports.foo = ...` | When you want Node.js ESM to be able to perform named imports from the CJS output | Rspack keeps these spellings primarily for webpack ecosystem compatibility and does not currently deprecate them at the config level. For new projects, prefer `commonjs2` or `commonjs-static` in most cases; reach for `commonjs` / `commonjs-module` mainly when migrating existing configs or when you explicitly need `exports` assignment semantics. ::: ##### type: 'amd' This will expose your library as an AMD module. AMD modules require that the entry chunk (e.g. the first script loaded by the ` ``` By default, the plugin injects scripts with `defer` into ``. If an entry also produces CSS, the corresponding `` tags are inserted into ``. With multiple entry points, the HTML includes assets from all of them. ### Generate multiple HTML files To generate a separate HTML file for each entry point, register multiple `rspack.HtmlRspackPlugin` instances: - Use `filename` to name each HTML file. - Use `chunks` to select the entry-point assets included in each HTML file. The following configuration emits `foo.html` and `bar.html`. Each file contains the assets required by its matching entry point, including runtime and shared assets. ```js title="rspack.config.mjs" export default { entry: { foo: './foo.js', bar: './bar.js', }, plugins: [ new rspack.HtmlRspackPlugin({ filename: 'foo.html', chunks: ['foo'], }), new rspack.HtmlRspackPlugin({ filename: 'bar.html', chunks: ['bar'], }), ], }; ``` ### Module scripts When [`output.module`](/config/output.md#outputmodule) is enabled and `scriptLoading` is not set, the plugin emits ` ``` ### Production minification In production mode (`mode: 'production'`), the plugin minifies the generated HTML when `minify` is not set. In other modes, HTML is minified only when `minify` is enabled explicitly. ```js title="rspack.config.mjs" export default { mode: 'production', plugins: [new rspack.HtmlRspackPlugin()], }; ``` ### Use a template file If `src/index.ejs` exists in the Rspack [`context`](/config/context.md), the plugin uses it as the template automatically. Otherwise, it uses the built-in template. To customize the HTML structure, you can also use `template` to specify an HTML file. The plugin injects the required JavaScript, CSS, and favicon tags into it. ```html title="index.html" <%= htmlRspackPlugin.options.title %> ``` ```js title="rspack.config.mjs" export default { plugins: [ new rspack.HtmlRspackPlugin({ title: 'My HTML Template', template: 'index.html', }), ], }; ``` ### Use template string You can also provide the HTML template directly through `templateContent`: ```js title="rspack.config.mjs" export default { plugins: [ new rspack.HtmlRspackPlugin({ title: 'My HTML Template', templateContent: ` <%= htmlRspackPlugin.options.title %> `, }), ], }; ``` ### Use template function For dynamically generated template content, use a function in either of these forms: - Pass the function directly to `templateContent`: ```js title="rspack.config.mjs" export default { plugins: [ new rspack.HtmlRspackPlugin({ title: 'My HTML Template', templateContent: ({ htmlRspackPlugin }) => ` ${htmlRspackPlugin.options.title} `, }), ], }; ``` - Specify a `.js` or `.cjs` file in `template`: ```js title="template.js" module.exports = ({ htmlRspackPlugin }) => ` ${htmlRspackPlugin.options.title} `; ``` ```js title="rspack.config.mjs" export default { plugins: [ new rspack.HtmlRspackPlugin({ title: 'My HTML Template', template: 'template.js', }), ], }; ``` ### Template parameters Use `templateParameters` to customize the values passed when rendering an HTML template. Templates receive the following serializable parameters by default: - `htmlRspackPlugin`: Data exposed by the plugin - `htmlRspackPlugin.options`: Normalized plugin options - `htmlRspackPlugin.tags`: Generated tags prepared for insertion - `htmlRspackPlugin.tags.headTags`: List of ``, ``, ``, `<link>`, and `<script>` tags for injection in `<head>` - `htmlRspackPlugin.tags.bodyTags`: List of `<script>` tags for injection in `<body>` - `htmlRspackPlugin.files`: Asset URLs selected for the current HTML file - `htmlRspackPlugin.files.js`: Selected JavaScript asset URLs - `htmlRspackPlugin.files.css`: Selected CSS asset URLs - `htmlRspackPlugin.files.favicon`: Generated favicon URL when `favicon` is configured - `htmlRspackPlugin.files.publicPath`: Effective public path used for asset URLs - `rspackConfig`: Selected Rspack settings - `rspackConfig.mode`: Current build mode - `rspackConfig.output.publicPath`: Effective public path for the current HTML file, including a [`publicPath`](#publicpath) override - `rspackConfig.output.crossOriginLoading`: Configured cross-origin loading value When a JavaScript function renders the template, it can also access the Rspack `compilation` object. That object is not passed when `templateParameters` is `false` or a function. In a built-in template, use EJS-style interpolation to read these parameters: ```js title="rspack.config.mjs" export default { mode: 'development', plugins: [ new rspack.HtmlRspackPlugin({ title: 'My application', templateContent: ` <!doctype html> <html> <head></head> <body> <h1><%- htmlRspackPlugin.options.title %></h1> <p>Mode: <%- rspackConfig.mode %></p> </body> </html> `, }), ], }; ``` In a JavaScript template function, the parameters are passed as an ordinary JavaScript object: ```js title="rspack.config.mjs" export default { plugins: [ new rspack.HtmlRspackPlugin({ templateContent: ({ htmlRspackPlugin }) => ` <!doctype html> <html> <head></head> <body> <p>Scripts: ${htmlRspackPlugin.files.js.join(', ')}</p> </body> </html> `, }), ], }; ``` In templates rendered by the built-in engine, call `toHtml()` to convert a tag or tag list to HTML. In JavaScript template functions, tags and tag lists provide `toString()` and can be interpolated directly. :::warning If the template inserts `htmlRspackPlugin.tags` manually, set `inject` to `false`; otherwise, the plugin inserts those tags twice. ::: :::info Differences Compared with HtmlWebpackPlugin: - Template paths do not support loader syntax such as `loader!./template.html` - The `compilation` object is only available when [using a template function](#use-template-function), with the `templateParameters` restrictions described above ::: ## Options Pass the following options to `new rspack.HtmlRspackPlugin()`. All examples reuse the `rspack` import from the first example. ### title - **Type:** `string` - **Default:** `undefined` Sets the `<title>` of the generated HTML. When automatic injection is enabled, the plugin replaces an existing `<title>` in the template or adds one to `<head>`. When omitted, a custom template keeps its own title. The built-in template uses `rspack`. Setting [`inject`](#inject) to `false` prevents `title` from being applied automatically, but the value remains available as `htmlRspackPlugin.options.title`. ```js new rspack.HtmlRspackPlugin({ title: 'My application', }); ``` Generated HTML fragment: ```html <title>My application ``` ### filename - **Type:** ```ts type HtmlFilenameFunction = (entry: string) => string; type HtmlFilename = string | HtmlFilenameFunction; ``` - **Default:** `'index.html'` Sets the HTML asset path and filename relative to [`output.path`](/config/output.md#outputpath). When omitted, the plugin emits `index.html` in the output directory. - **String:** Emits the HTML at the specified path. The value can include a subdirectory and filename placeholders such as `[name]` and `[contenthash]`. A `[name]` placeholder emits one HTML file for each statically configured entry. ```js new rspack.HtmlRspackPlugin({ filename: 'pages/index.html', }); ``` - **Function:** Calls the function once for each statically configured entry, passing its name as the argument. The return value becomes the corresponding HTML filename. ```js export default { entry: { app: './src/app.js', admin: './src/admin.js', }, plugins: [ new rspack.HtmlRspackPlugin({ filename: (entry) => `pages/${entry}.html`, }), ], }; ``` The `[name]` and function forms do not support a function-valued Rspack [`entry`](/config/entry.md). They only control HTML filenames; every generated file still receives the same entry assets selected by [`chunks`](#chunks) and [`excludeChunks`](#excludechunks). Register separate plugin instances when each page needs a different asset set. ### template - **Type:** `string` - **Default:** `undefined` Sets the template file. Relative paths are resolved from the Rspack [`context`](/config/context.md). [`templateContent`](#templatecontent) takes precedence when both options are set. When omitted, the plugin looks for `src/index.ejs` in `context` and falls back to its built-in HTML document if the file does not exist. - **HTML file:** Reads the file as text, renders it with the built-in [template syntax](#template-syntax), and injects the generated tags. ```html title="index.html" <%= htmlRspackPlugin.options.title %> ``` ```js new rspack.HtmlRspackPlugin({ title: 'My application', template: './index.html', }); ``` - **JavaScript module:** A path ending in `.js` or `.cjs` is loaded as a CommonJS module. Its exported function receives the template parameters and returns the HTML string, either directly or through a promise. ```js title="template.cjs" module.exports = ({ htmlRspackPlugin }) => ` ${htmlRspackPlugin.options.title} `; ``` ```js new rspack.HtmlRspackPlugin({ title: 'My application', template: './template.cjs', }); ``` ### templateContent - **Type:** ```ts type TemplateRenderFunction = ( params: Record, ) => string | Promise; type TemplateContent = string | TemplateRenderFunction; ``` - **Default:** `undefined` Provides the template directly without reading a file. When set, it takes precedence over [`template`](#template) and the default template lookup. - **String:** Renders the string with the built-in [template syntax](#template-syntax), then injects the generated tags. ```js new rspack.HtmlRspackPlugin({ templateContent: ` My application `, }); ``` - **Function:** Calls the function with the final template parameters. The returned string becomes the HTML template result and is not processed as EJS. The function can be asynchronous. ```js new rspack.HtmlRspackPlugin({ title: 'My application', templateContent: ({ htmlRspackPlugin }) => ` ${htmlRspackPlugin.options.title} `, }); ``` When omitted, the plugin first uses [`template`](#template) if it is set. Otherwise, it looks for `src/index.ejs` and then falls back to the built-in document. ### templateParameters - **Type:** ```ts type TemplateParamFunction = ( params: Record, ) => Record | Promise>; type TemplateParameters = Record | boolean | TemplateParamFunction; ``` - **Default:** `undefined` Controls the parameters passed to an HTML template or template function. The built-in values are described in [Template parameters](#template-parameters). - **Object:** Merges the object's string properties into the built-in parameters. Properties with the same name replace the built-in value. ```js new rspack.HtmlRspackPlugin({ templateContent: '
<%= environment %>
', templateParameters: { environment: 'production', }, }); ``` - **Boolean:** `true` preserves the built-in parameters and is equivalent to omitting the option. `false` passes an empty object to the template. ```js new rspack.HtmlRspackPlugin({ templateContent: () => '
Static page
', templateParameters: false, }); ``` - **Function:** Calls the function with the serializable built-in parameters and uses its returned object as the complete final parameter object. Return the original properties when the template still needs them. The function can be asynchronous. ```js new rspack.HtmlRspackPlugin({ templateContent: ({ buildName }) => `
${buildName}
`, templateParameters: (params) => ({ ...params, buildName: 'documentation', }), }); ``` The `compilation` parameter is available only to a JavaScript template function when `templateParameters` is omitted, `true`, or an object. It is not passed to string templates, a `templateParameters` function, or a template function when `templateParameters` is `false`. ### inject - **Type:** `boolean | 'head' | 'body'` - **Default:** `true` Controls automatic insertion of the tags generated by the plugin. When injection is enabled, stylesheets, the title, ``, ``, and favicon tags are inserted into ``. The `'head'` and `'body'` values change only the placement of ` ``` - **`'defer'`:** Adds the boolean `defer` attribute. With the default `inject`, scripts are inserted into ``. ```js new rspack.HtmlRspackPlugin({ scriptLoading: 'defer', }); ``` Generated HTML fragment: ```html ``` - **`'module'`:** Adds `type="module"`. Module scripts are deferred by browsers, and the default `inject` inserts them into ``. ```js new rspack.HtmlRspackPlugin({ scriptLoading: 'module', }); ``` Generated HTML fragment: ```html ``` - **`'systemjs-module'`:** Adds `type="systemjs-module"`. The default `inject` inserts these scripts into ``. ```js new rspack.HtmlRspackPlugin({ scriptLoading: 'systemjs-module', }); ``` Generated HTML fragment: ```html ``` ### chunks - **Type:** `string[]` - **Default:** `undefined` Selects entry points whose JavaScript and CSS files are included in the HTML. Each value is compared with an entry point name using exact string equality; it does not match an arbitrary chunk ID, asset filename, or module path. Unknown names are ignored. When omitted, every entry point is selected before [`excludeChunks`](#excludechunks) is applied. Selecting an entry point also includes the runtime and shared files required by that entry. With the default [`chunksSortMode: 'auto'`](#chunkssortmode), `chunks` first limits the entry points and `excludeChunks` then removes matches. With `'manual'`, a provided `chunks` array instead becomes the final ordered entry list. If `chunks` is omitted, `excludeChunks` still filters the compilation's entry point order. ```js export default { entry: { app: './src/app.js', admin: './src/admin.js', }, plugins: [ new rspack.HtmlRspackPlugin({ chunks: ['app'], }), ], }; ``` ### excludeChunks - **Type:** `string[]` - **Default:** `undefined` Excludes entry points from the generated HTML. Each value is compared with an entry point name using exact string equality; it does not match asset filenames, module paths, or non-entry chunks. Unknown names have no effect. In the default [`chunksSortMode: 'auto'`](#chunkssortmode), exclusions are applied after [`chunks`](#chunks), so an entry present in both arrays is excluded. With `'manual'`, a provided `chunks` array is the final ordered list and `excludeChunks` is not applied; when `chunks` is omitted, exclusions still apply to the compilation's entry point order. If `excludeChunks` is omitted, no selected entry point is excluded. ```js export default { entry: { app: './src/app.js', admin: './src/admin.js', }, plugins: [ new rspack.HtmlRspackPlugin({ excludeChunks: ['admin'], }), ], }; ``` ### chunksSortMode - **Type:** `'auto' | 'manual'` - **Default:** `'auto'` Controls the order in which selected entry points contribute their files to the generated tags. - **`'auto'`:** Uses the compilation's entry point order after applying `chunks` and `excludeChunks`. ```js new rspack.HtmlRspackPlugin({ chunksSortMode: 'auto', }); ``` - **`'manual'`:** Uses the order of [`chunks`](#chunks), ignoring unknown entry names. When `chunks` is omitted, it uses the compilation's entry point order after applying [`excludeChunks`](#excludechunks). When `chunks` is present, `excludeChunks` is not applied. ```js new rspack.HtmlRspackPlugin({ chunks: ['admin', 'app'], chunksSortMode: 'manual', }); ``` ### minify - **Type:** `boolean` - **Default:** `true` in production mode, otherwise `false` Controls whether the generated HTML is minified after template rendering and tag injection. An explicit value overrides the mode-dependent default. ```js new rspack.HtmlRspackPlugin({ minify: false, }); ``` ### favicon - **Type:** `string` - **Default:** `undefined` Sets the path of a favicon file. Relative paths are resolved from the Rspack [`context`](/config/context.md). The plugin emits the file at the output root using its basename and generates a `` tag whose URL follows [`publicPath`](#publicpath). When omitted, no favicon asset or tag is generated. With [`inject: false`](#inject), the asset is still emitted and exposed as `htmlRspackPlugin.files.favicon`, but the `` tag is not inserted automatically. ```js new rspack.HtmlRspackPlugin({ favicon: './src/favicon.ico', }); ``` Generated HTML fragment: ```html ``` ### meta - **Type:** ```ts type HtmlMeta = Record>; ``` - **Default:** `{}` Creates additional `` tags in ``. Each top-level key becomes the default `name` attribute. The built-in template's `` is independent of this option. When the object is empty or the option is omitted, no additional meta tags are generated. [`inject: false`](#inject) prevents them from being inserted automatically. - **String value:** Uses the top-level key as `name` and the string as `content`. ```js new rspack.HtmlRspackPlugin({ meta: { viewport: 'width=device-width,initial-scale=1', }, }); ``` Generated HTML fragment: ```html ``` - **Object value:** Adds every property as an attribute. A `name` property overrides the name derived from the top-level key. ```js new rspack.HtmlRspackPlugin({ meta: { viewport: { name: 'viewport', content: 'width=device-width,initial-scale=1', 'data-origin': 'rspack', }, }, }); ``` Generated HTML fragment: ```html ``` ### hash - **Type:** `boolean` - **Default:** `undefined` If `true`, appends the Rspack compilation hash as a query string to generated JavaScript, CSS, and favicon URLs. This changes references in the HTML, not the emitted asset filenames. When omitted or `false`, the plugin leaves those URLs unchanged. ```js new rspack.HtmlRspackPlugin({ hash: true, }); ``` ## Template syntax The built-in template engine supports EJS-style interpolation and basic control flow, but it does not execute arbitrary JavaScript. The following examples show the commonly used forms. #### Escaped output `<%-` Escapes the content within the interpolation: ```html title="ejs"

Hello, <%- name %>.

Hello, <%- 'the Most Honorable ' + name %>.

``` ```json title="locals" { "name": "Rspack" } ``` ```html title="html"

Hello, Rspack<y>.

Hello, the Most Honorable Rspack<y>.

``` #### Unescaped output `<%=` Does not escape the content within the interpolation: ```html title="ejs"

Hello, <%- myHtml %>.

Hello, <%= myHtml %>.

Hello, <%- myMaliciousHtml %>.

Hello, <%= myMaliciousHtml %>.

``` ```json title="locals" { "myHtml": "Rspack", "myMaliciousHtml": "

" } ``` ```html title="html"

Hello, <strong>Rspack</strong>.

Hello, Rspack.

Hello, </p><script>document.write()</script><p>.

Hello,

.

``` #### Control statements The following example combines `for in` iteration with an `if` condition: ```txt title="ejs" <% for tag in htmlRspackPlugin.tags.headTags { %> <% if tag.tagName=="script" { %> <%= toHtml(tag) %> <% } %> <% } %> ``` ## Hooks HtmlRspackPlugin exposes hooks for modifying generated tags and HTML. Call `rspack.HtmlRspackPlugin.getCompilationHooks` to access them: Hook data exposes the original constructor options as `data.plugin.options`. Additional custom fields are preserved there for hook consumers but do not affect HTML generation by themselves. ```js title="rspack.config.mjs" const HtmlModifyPlugin = { apply(compiler) { compiler.hooks.compilation.tap('HtmlModifyPlugin', (compilation) => { const hooks = rspack.HtmlRspackPlugin.getCompilationHooks(compilation); // hooks.beforeAssetTagGeneration.tapPromise() // hooks.alterAssetTags.tapPromise() // hooks.alterAssetTagGroups.tapPromise() // hooks.afterTemplateExecution.tapPromise() // hooks.beforeEmit.tapPromise() // hooks.afterEmit.tapPromise() }); }, }; export default { plugins: [new rspack.HtmlRspackPlugin(), HtmlModifyPlugin], }; ``` ### beforeAssetTagGeneration This hook runs after the plugin collects asset URLs from the compilation and before it creates tags. Modify `assets.js`, `assets.css`, or `assets.favicon` to add or replace URLs used to create tags. Values added by the hook are used as-is: the hook does not prepend `publicPath` or emit the referenced files. - **Type:** `AsyncSeriesWaterfallHook<[BeforeAssetTagGenerationData]>` - **Parameters:** ```ts type BeforeAssetTagGenerationData = { assets: { publicPath: string; js: Array; css: Array; favicon?: string; jsIntegrity?: Array; cssIntegrity?: Array; }; outputName: string; plugin: { options: HtmlRspackPluginOptions; }; }; ``` :::warning Only changes to `assets.js`, `assets.css`, and `assets.favicon` affect the tags generated automatically by the plugin. Other fields do not affect automatic tag generation, but templates can still read them through `htmlRspackPlugin.files`. ::: The following code adds the URL `extra-script.js`, which produces a `` tag in the final HTML. ```js title="rspack.config.mjs" const AddScriptPlugin = { apply(compiler) { compiler.hooks.compilation.tap('AddScriptPlugin', (compilation) => { const hooks = rspack.HtmlRspackPlugin.getCompilationHooks(compilation); hooks.beforeAssetTagGeneration.tapPromise( 'AddScriptPlugin', async (data) => { data.assets.js.push('extra-script.js'); }, ); }); }, }; export default { plugins: [new rspack.HtmlRspackPlugin(), AddScriptPlugin], }; ``` ### alterAssetTags This hook runs after asset tags are created and before they are assigned to `` or ``. Modify `assetTags` to add, remove, or update tags. - **Type:** `AsyncSeriesWaterfallHook<[AlterAssetTagsData]>` - **Parameters:** ```ts type HtmlTag = { tagName: string; attributes: Record; voidTag: boolean; innerHTML?: string; asset?: string; }; type AlterAssetTagsData = { assetTags: { scripts: Array; styles: Array; meta: Array; }; publicPath: string; outputName: string; plugin: { options: HtmlRspackPluginOptions; }; }; ``` :::warning Only changes to `assetTags` affect the generated HTML. Changes to other fields are ignored by this plugin. ::: Attribute names are normalized to lowercase. Attribute values are handled as follows: - **`true`:** Adds a valueless attribute, for example ``. - **String:** Adds an attribute with that value, for example ``. - **`false`, `undefined`, or `null`:** Removes the attribute. The following code adds the `specialAttribute` attribute to every ``: ```js title="rspack.config.mjs" const InjectContentPlugin = { apply(compiler) { compiler.hooks.compilation.tap('InjectContentPlugin', (compilation) => { const hooks = rspack.HtmlRspackPlugin.getCompilationHooks(compilation); hooks.afterTemplateExecution.tapPromise( 'InjectContentPlugin', async (data) => { data.html = data.html.replace('', 'Injected by plugin'); }, ); }); }, }; export default { plugins: [ new rspack.HtmlRspackPlugin({ inject: 'body', }), InjectContentPlugin, ], }; ``` ### beforeEmit This hook runs immediately before the HTML asset is emitted and is the final chance to modify its content. - **Type:** `AsyncSeriesWaterfallHook<[BeforeEmitData]>` - **Parameters:** ```ts type BeforeEmitData = { html: string; outputName: string; plugin: { options: HtmlRspackPluginOptions; }; }; ``` :::warning Only changes to `html` affect the emitted asset. Changes to other fields are ignored by this plugin. ::: The following code adds `Injected by plugin` at the end of ``. The final sequence is `Injected by plugin`: ```js title="rspack.config.mjs" const InjectContentPlugin = { apply(compiler) { compiler.hooks.compilation.tap('InjectContentPlugin', (compilation) => { const hooks = rspack.HtmlRspackPlugin.getCompilationHooks(compilation); hooks.beforeEmit.tapPromise('InjectContentPlugin', async (data) => { data.html = data.html.replace('', 'Injected by plugin'); }); }); }, }; export default { plugins: [ new rspack.HtmlRspackPlugin({ inject: 'body', }), InjectContentPlugin, ], }; ``` ### afterEmit This hook runs after the HTML asset is emitted and is intended for notification only. - **Type:** `AsyncSeriesWaterfallHook<[AfterEmitData]>` - **Parameters:** ```ts type AfterEmitData = { outputName: string; plugin: { options: HtmlRspackPluginOptions; }; }; ``` --- url: /plugins/subresource-integrity-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # SubresourceIntegrityPlugin [Added in v1.7.0](https://github.com/web-infra-dev/rspack/releases/tag/v1.7.0)Rspack only The `rspack.SubresourceIntegrityPlugin` is a plugin for enabling Subresource Integrity in Rspack. > In versions 1.2.4 to 1.6.8, you can use `rspack.experiments.SubresourceIntegrityPlugin`. ## What is SRI Subresource Integrity (SRI) is a security feature that enables browsers to verify that resources they fetch (for example, from a CDN) are delivered without unexpected manipulation. It works by allowing you to provide a cryptographic hash that a fetched resource must match. For ` <% } %> <% for _ in htmlRspackPlugin.files.css { %> <% } %> ``` With [`html-webpack-plugin`](https://github.com/jantimon/html-webpack-plugin), you can inject them like this: ```ejs title="index.ejs" <% for (let index in htmlWebpackPlugin.files.js) { %> <% } %> <% for (let index in htmlWebpackPlugin.files.css) { %> <% } %> ``` ### Without HTML plugin The `integrity` can also be obtained from `stats.assets`. For example: ```js compiler.hooks.done.tap('MyPlugin', (stats) => { const integrityValues = stats .toJson() .assets.map((asset) => [asset.name, asset.integrity]); }); ``` :::tip Note that when you add the `integrity` attribute on your `link` and `script` tags, you're also required to set the `crossorigin` attribute. It is recommended to set this attribute to the same value as the Rspack `output.crossOriginLoading` configuration option. ::: ## Options ### hashFuncNames - **Type:** `Array<"sha256" | "sha384" | "sha512">` - **Default:** `["sha384"]` An array of strings, each specifying the name of a hash function to be used for calculating integrity hash values. Only supports `sha256`, `sha384`, and `sha512` yet. > See [SRI: Cryptographic hash functions](http://www.w3.org/TR/SRI/#cryptographic-hash-functions) for more details. ### enabled - **Type:** `"auto" | boolean` - **Default:** `"auto"` - `auto` is the default value, which means the plugin is enabled when [Rspack mode](/config/mode.md) is `production` or `none`, and disabled when it is `development`. - `true` means the plugin is enabled in any mode. - `false` means the plugin is disabled in any mode. ### htmlPlugin - **Type:** `string` - **Default:** `"HtmlRspackPlugin"` The path to the HTML plugin, defaults to `"HtmlRspackPlugin"` which means the native HTML plugin of Rspack. If you are using the `html-webpack-plugin`, you can set this option to the path of it. It is recommended to set the absolute path to make sure the plugin can be found. ## More information You can find more information about Subresource Integrity in the following resources: - [webpack-subresource-integrity](https://github.com/waysact/webpack-subresource-integrity/blob/main/webpack-subresource-integrity/README.md) - [MDN: Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) --- url: /plugins/compact-hashed-chunk-ids-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # CompactHashedChunkIdsPlugin [Added in v2.2.1](https://github.com/web-infra-dev/rspack/releases/tag/v2.2.1)Rspack only `CompactHashedChunkIdsPlugin` hashes chunk contents and assigns the shortest available prefix of each encoded hash. Compared with `deterministic`, it produces more compact ids that preserve stability while reducing bundle size and improving runtime indexing performance. Every character uses `0-9a-z`, making chunk ids safe for case-insensitive file systems. An id is extended only when its shorter prefix is already used. :::warning Deprecated alias `CompatHashedChunkIdsPlugin` was available in Rspack 2.2.0. It is deprecated and was renamed to `CompactHashedChunkIdsPlugin` in Rspack 2.2.1. The old name remains available as a compatibility alias. ::: `optimization.chunkIds: 'compact-hashed'` uses this plugin internally. Use the plugin directly when you need to customize the minimum encoded id length. ## Examples ```js title="rspack.config.mjs" import rspack from '@rspack/core'; export default { optimization: { chunkIds: false, }, plugins: [ new rspack.ids.CompactHashedChunkIdsPlugin({ minLength: 1, }), ], }; ``` ## Options ### minLength - **Type:** `number` - **Default:** `1` - **Range:** Integer from `1` to `13` The minimum encoded id length. Rspack extends an id one character at a time when its hash prefix is already used. Increasing `minLength` expands the initial id space, reducing prefix collisions and making generated output and caching more stable. The tradeoff is that chunk ids become longer. --- url: /plugins/compact-hashed-module-ids-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # CompactHashedModuleIdsPlugin [Added in v2.2.1](https://github.com/web-infra-dev/rspack/releases/tag/v2.2.1)Rspack only `CompactHashedModuleIdsPlugin` hashes module identifiers and assigns the shortest available prefix of each encoded hash. Compared with `deterministic`, it produces more compact ids that preserve stability while reducing bundle size and improving runtime indexing performance. The first character uses `a-zA-Z`, and subsequent characters use `a-zA-Z0-9`. An id is extended only when its shorter prefix is already used. :::warning Deprecated alias `CompatHashedModuleIdsPlugin` was available in Rspack 2.2.0. It is deprecated and was renamed to `CompactHashedModuleIdsPlugin` in Rspack 2.2.1. The old name remains available as a compatibility alias. ::: :::warning The generated module ids are case-sensitive and may contain uppercase letters. On case-insensitive file systems, avoid using `[id]` as the only distinguishing placeholder in [Asset module filenames](/config/output.md#outputassetmodulefilename) or [WebAssembly module filenames](/config/output.md#outputwebassemblymodulefilename). Prefer `[contenthash]`, or include it alongside `[id]`. ::: [`optimization.moduleIds: 'compact-hashed'`](/config/optimization.md#optimizationmoduleids) uses this plugin internally. Use the plugin directly when you need to customize the minimum encoded id length. ## Examples ```js title="rspack.config.mjs" import rspack from '@rspack/core'; export default { optimization: { moduleIds: false, }, plugins: [ new rspack.ids.CompactHashedModuleIdsPlugin({ minLength: 1, }), ], }; ``` ## Options ### minLength - **Type:** `number` - **Default:** `1` - **Range:** Integer from `1` to `11` The minimum encoded id length. Rspack extends an id one character at a time when its hash prefix is already used. Increasing `minLength` expands the initial id space, reducing prefix collisions and making generated output and caching more stable. The tradeoff is that module ids become longer. --- url: /plugins/css-chunking-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # CssChunkingPlugin [Added in v1.4.0](https://github.com/web-infra-dev/rspack/releases/tag/v1.4.0)Rspack only `CssChunkingPlugin` is a plugin specifically designed for CSS code splitting. It ensures that the loading order of styles matches the import order in your source code, avoiding UI issues caused by incorrect CSS order. > This plugin is inspired by Next.js's [CSS Chunking](https://nextjs.org/docs/app/api-reference/config/next-config-js/cssChunking) feature, thanks to the Next.js team for their innovation. ## Examples ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { plugins: [ new rspack.experiments.CssChunkingPlugin({ // ...options }), ], }; ``` :::tip After enabling CssChunkingPlugin, SplitChunksPlugin will no longer process CSS modules. This means that options like `optimization.splitChunks` will no longer handle CSS modules, and all CSS module code splitting logic will be handled entirely by CssChunkingPlugin. ::: ## Options ### strict - **Type:** `boolean` - **Default:** `false` Whether to strictly preserve the import order of CSS modules. ### minSize The minimum size (in bytes) for a generated chunk. ### maxSize The maximum size (in bytes) for a generated chunk. Chunks larger than maxSize will be split into smaller parts, each with a size of at least minSize. ## Mode comparison ### Normal mode (strict: false, default) ```js new rspack.experiments.CssChunkingPlugin({ strict: false, }); ``` - If CSS modules are imported in different orders throughout the project, they are considered to have no dependencies between them. - Allow merging independent CSS modules into the same chunk to reduce the number of chunks. ### Strict mode (strict: true) ```js new rspack.experiments.CssChunkingPlugin({ strict: true, }); ``` - Strictly ensures that the execution order of CSS modules matches the import order in the source code. ### Example `a.css` and `b.css` are imported in `foo.js` and `bar.js` with different sequences: ```js // foo.js import './a.css'; import './b.css'; // bar.js import './b.css'; import './a.css'; ``` Regular Mode (strict: false): Considers `a.css` and `b.css` to have no dependency relationship and doesn't enforce execution order, thus merging them into the same chunk. Strict Mode (strict: true): Strictly maintains execution order consistent with import sequence, therefore packaging `a.css` and `b.css` into separate chunks ## Differences from SplitChunksPlugin `SplitChunksPlugin` does not consider the import order of modules when splitting code. For JavaScript modules, this is not an issue because execution order is determined at runtime via function calls. However, for CSS modules, the execution order is entirely determined by their order in the output files and cannot be controlled at runtime. If the order changes, it may cause style issues. For example, importing the following CSS modules: ```js import './a.css'; import './b.css'; import './c.css'; ``` `SplitChunksPlugin` may split them into the following chunks to satisfy `maxSize` or other constraints: ``` chunk-1: b.css chunk-2: a.css, c.css // may be split due to large size ``` This results in the execution order being b.css → a.css → c.css, which violates the original import order and may cause style errors. `CssChunkingPlugin` first splits all CSS modules, then determines which can be merged based on the import order in the source code. Modules that cannot be merged are split into separate chunks to ensure style correctness. :::tip Because CssChunkingPlugin prioritizes preserving style execution order, it may split more chunks than SplitChunksPlugin. ::: --- url: /plugins/deterministic-module-ids-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # DeterministicModuleIdsPlugin `DeterministicModuleIdsPlugin` assigns short numeric ids to modules based on their module identifiers. The ids are stable between compilations, which makes the plugin useful for long-term caching. `optimization.moduleIds: 'deterministic'` uses this plugin internally. Use the plugin directly when you need to customize the deterministic id generation behavior. ## Examples ```js title="rspack.config.mjs" import rspack from '@rspack/core'; export default { optimization: { moduleIds: false, }, plugins: [ new rspack.ids.DeterministicModuleIdsPlugin({ maxLength: 4, }), ], }; ``` ## Options ### context - **Type:** `string` - **Default:** `compiler.context` The context used to create relative module identifiers before ids are generated. ### test - **Type:** `(module: Module) => boolean` - **Default:** `undefined` Selects which modules should receive deterministic ids from this plugin. When omitted, all modules that need ids are included. ```js title="rspack.config.mjs" import rspack from '@rspack/core'; export default { optimization: { moduleIds: false, }, plugins: [ new rspack.ids.DeterministicModuleIdsPlugin({ test: (module) => module.type.startsWith('css'), }), ], }; ``` ### maxLength - **Type:** `number` - **Default:** `3` The maximum id length in digits used as the starting id space. The generated numeric id space starts at `10 ** maxLength`. ### salt - **Type:** `number` - **Default:** `0` The hash salt used when generating ids. Change this value to try a different hash starting value in the same id space. ### fixedLength - **Type:** `boolean` - **Default:** `false` When enabled, Rspack does not increase the id length to find a larger id space. ### failOnConflict - **Type:** `boolean` - **Default:** `false` When enabled, Rspack reports an error if deterministic id assignment produces conflicts. By default, Rspack resolves conflicts by retrying with a larger id space. ## Usage with optimization.moduleIds For the common long-term caching setup, prefer the built-in optimization option: ```js title="rspack.config.mjs" export default { optimization: { moduleIds: 'deterministic', }, }; ``` Use `DeterministicModuleIdsPlugin` directly only when you need the options above. This page is adapted from [webpack documentation](https://webpack.js.org/configuration/optimization/#optimizationmoduleids) under the [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), with modifications. --- url: /plugins/dll-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # DllPlugin The `DllPlugin` is used in a separate rspack configuration exclusively to create a dll-only-bundle. ## Examples ```js new rspack.DllPlugin({ path: path.resolve(__dirname, 'manifest.json'), name: '[name]_dll_lib', }); ``` The Plugin will create a `manifest.json` which is written to the given path. It contains mappings from require and import requests to module ids. The `manifest.json` is used by the [DllReferencePlugin](/plugins/dll-reference-plugin.md) Combine this plugin with `output.library` options to expose the dll function. ## Options ```ts type DllPluginOptions = { context?: string; entryOnly?: boolean; format?: boolean; name?: string; path: string; type?: string; }; ``` ### context - **Type:** `string` - **Default:** The Rspack compiler context Sets the context used for requests in the manifest file. ### entryOnly - **Type:** `boolean` - **Default:** `true` If `true`, only entry modules are exposed. ### format - **Type:** `boolean` - **Default:** `false` Controls whether the generated manifest JSON is formatted for readability. ### name - **Type:** `string` - **Default:** `undefined` Sets the name of the exposed DLL function. Configure it to match the DLL bundle's `output.library` name. ### path - **Type:** `string` Sets the absolute output path of the manifest JSON file. This option is required. ### type - **Type:** `string` - **Default:** `undefined` Sets the external type of the DLL bundle. Configure it to match `output.library.type`. This page is adapted from [webpack documentation](https://webpack.js.org/plugins/dll-plugin/) under the [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), with modifications. --- url: /plugins/dll-reference-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # DllReferencePlugin The `DllReferencePlugin` is used to reference the dll-only-bundle to require pre-built dependencies. ## Examples ### Basic example ```js new rspack.DllReferencePlugin({ // Manifest should be generated by DllPlugin manifest: require('../lib/manifest.json'), name: '[name]_dll_lib', }); ``` Application require dependencies will reference to pre-built using `DllPlugin`. ### With scope The content of the dll is accessible under a module prefix when set scope. ```js new rspack.DllReferencePlugin({ // Manifest should be generated by DllPlugin manifest: require('../lib/manifest.json'), name: '[name]_dll_lib', scope: 'xyz', }); ``` Access via `require('xzy/abc')`, you can require `abc` from another pre-built lib. ## Options - **Types:** ```ts type DllReferencePluginOptionsContent = { /** * Module info. */ [k: string]: { /** * Meta information about the module. */ buildMeta?: { [k: string]: any; }; /** * Information about the provided exports of the module. */ exports?: string[] | true; /** * Module ID. */ id?: string | number; }; }; type DllReferencePluginOptionsManifest = { /** * The mappings from module specifier to module info. */ content: DllReferencePluginOptionsContent; /** * The name where the dll is exposed (external name). */ name?: string; /** * The type how the dll is exposed (external type). */ type?: DllReferencePluginOptionsSourceType; }; /** * The type how the dll is exposed (external type). */ type DllReferencePluginOptionsSourceType = | 'var' | 'assign' | 'this' | 'window' | 'global' | 'commonjs' | 'commonjs2' | 'commonjs-module' | 'amd' | 'amd-require' | 'umd' | 'umd2' | 'jsonp' | 'system'; type DllReferencePluginOptions = | { /** * Context of requests in the manifest (or content property) as absolute path. */ context?: string; /** * Extensions used to resolve modules in the dll bundle (only used when using 'scope'). */ extensions?: string[]; /** * An object containing content and name or a string to the absolute path of the JSON manifest to be loaded upon compilation. */ manifest: string | DllReferencePluginOptionsManifest; /** * The name where the dll is exposed (external name, defaults to manifest.name). */ name?: string; /** * Prefix which is used for accessing the content of the dll. */ scope?: string; /** * How the dll is exposed (libraryTarget, defaults to manifest.type). */ sourceType?: DllReferencePluginOptionsSourceType; /** * The way how the export of the dll bundle is used. */ type?: 'require' | 'object'; } | { /** * The mappings from module specifier to module info. */ content: DllReferencePluginOptionsContent; /** * Context of requests in the manifest (or content property) as absolute path. */ context?: string; /** * Extensions used to resolve modules in the dll bundle (only used when using 'scope'). */ extensions?: string[]; /** * The name where the dll is exposed (external name). */ name: string; /** * Prefix which is used for accessing the content of the dll. */ scope?: string; /** * How the dll is exposed (libraryTarget). */ sourceType?: DllReferencePluginOptionsSourceType; /** * The way how the export of the dll bundle is used. */ type?: 'require' | 'object'; }; ``` ### content - **Type:** `DllReferencePluginOptionsContent` - **Default:** `undefined` Provides the mappings from module requests to module metadata directly. When this form is used instead of `manifest`, `name` is required. ### context - **Type:** `string` - **Default:** `undefined` Sets the absolute context used to match module requests against keys in `manifest` or `content`. When using a manifest generated with a custom `DllPlugin.context`, set this option to the same path. ### extensions - **Type:** `string[]` - **Default:** `['', '.js', '.json', '.wasm']` Sets the extensions used to resolve modules in the DLL bundle when `scope` is configured. ### manifest - **Type:** `string | DllReferencePluginOptionsManifest` - **Default:** `undefined` Provides either a manifest object or the absolute path to a JSON manifest generated by `DllPlugin`. Use this option instead of `content`. ### name - **Type:** `string` - **Default:** `manifest.name` Sets the external name under which the DLL is exposed. It is required when `content` is provided directly. ### scope - **Type:** `string` - **Default:** `undefined` Sets the module prefix used to access content from the DLL. ### sourceType - **Type:** `DllReferencePluginOptionsSourceType` - **Default:** `manifest.type`, or `'var'` when no type is provided Sets how the DLL is exposed, corresponding to its library type. ### type - **Type:** `'require' | 'object'` - **Default:** `'require'` Controls how exports from the DLL bundle are consumed. This plugin references a dll manifest file to map dependency names to module ids, then require them as needed. This page is adapted from [webpack documentation](https://webpack.js.org/plugins/dll-plugin/#dllreferenceplugin) under the [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), with modifications. --- url: /plugins/lightning-css-minimizer-rspack-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # LightningCssMinimizerRspackPlugin Rspack only This plugin uses [lightningcss](https://lightningcss.dev/) to minify CSS assets. See [optimization.minimizer](/config/optimization.md#optimizationminimizer). ## Examples ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { optimization: { minimizer: [new rspack.LightningCssMinimizerRspackPlugin()], }, }; ``` ## Options ### include - **Type:** `string | RegExp | (string | RegExp)[]` - **Default:** `undefined` Use this to specify which files should be minified, it matches the path of the output files. ### exclude - **Type:** `string | RegExp | (string | RegExp)[]` - **Default:** `undefined` Use this to specify which files should be excluded from minification, it matches the path of the output files. ### test - **Type:** `string | RegExp | (string | RegExp)[]` - **Default:** `undefined` Use this to provide a pattern that CSS files are matched against. If the output filename matches the given pattern, it will be minified, otherwise it won't be. ### removeUnusedLocalIdents - **Type:** `boolean` - **Default:** `true` Whether to automatically remove the unused local idents of CSS Modules, including unused CSS class names, ids, and @keyframe names. The declarations of these will be removed. For example, in the following CSS Modules, class names a and b are exported, but only class name a is used in the js file: ```css title=index.module.css .a { color: red; } .b { color: blue; } ``` ```js title=index.js import * as styles from './index.module.css'; document.body.className = styles.a; ``` At this point, the information that class name b is unused will be obtained via Rspack's tree shaking feature and provided to lightningcss. During minimization, the declaration for class name b will be removed from the CSS output, resulting in the following final output: ```css .a{color: red} ``` ### minimizerOptions Configuration passed to Lightning CSS for minification. Below are the configurations supported, `targets` configuration is plain browserslist query, for other detailed usage, please refer to [Lightning CSS documentation](https://lightningcss.dev/transpilation.html) :::info 1. The `targets` option is resolved in the following priority order: - User-specified `targets` in plugin options (highest priority) - Targets derived from Rspack's [`target`](/config/target.md) configuration when using browserslist-related targets (e.g., `browserslist` or `browserslist:modern`), since Lightning CSS only supports browser-related targets, non-browser targets like `node` will not provide default targets for this plugin. - Falls back to `"fully supports es6"` if neither is available The fallback ensures that minification does not introduce advanced syntax that could cause browser incompatibility (minification might turn lower-level syntax into advanced syntax because it is shorter). 2. The `exclude` option is configured with all features by default. We usually do syntax degradation in [builtin:lightningcss-loader](/guide/features/builtin-lightningcss-loader.md) or other loaders, so this plugin excludes all features by default to avoid syntax downgrading during the minimize process. We recommend and encourage users to configure their own `targets` to achieve the best minification results. ::: ```ts type Targets = { android?: string; chrome?: string; edge?: string; firefox?: string; ie?: string; ios_saf?: string; opera?: string; safari?: string; samsung?: string; }; type LightningCssMinimizerOptions = { errorRecovery?: boolean; targets?: string[] | string | Targets; include?: LightningcssFeatureOptions; exclude?: LightningcssFeatureOptions; drafts?: Drafts; nonStandard?: NonStandard; pseudoClasses?: PseudoClasses; unusedSymbols?: Set; }; type LightningcssFeatureOptions = { nesting?: boolean; notSelectorList?: boolean; dirSelector?: boolean; langSelectorList?: boolean; isSelector?: boolean; textDecorationThicknessPercent?: boolean; mediaIntervalSyntax?: boolean; mediaRangeSyntax?: boolean; customMediaQueries?: boolean; clampFunction?: boolean; colorFunction?: boolean; oklabColors?: boolean; labColors?: boolean; p3Colors?: boolean; hexAlphaColors?: boolean; spaceSeparatedColorNotation?: boolean; fontFamilySystemUi?: boolean; doublePositionGradients?: boolean; vendorPrefixes?: boolean; logicalProperties?: boolean; selectors?: boolean; mediaQueries?: boolean; color?: boolean; }; ``` --- url: /plugins/limit-chunk-count-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # LimitChunkCountPlugin While writing your code, you may have already added many code split points to load stuff on demand. After compiling you might notice that some chunks are too small - creating larger HTTP overhead. `LimitChunkCountPlugin` can post-process your chunks by merging them. ## Examples Limit the compilation to five chunks: ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { plugins: [ new rspack.optimize.LimitChunkCountPlugin({ maxChunks: 5, }), ], }; ``` ## Options ### maxChunks - **Type:** `number` Limit the maximum number of chunks using a value greater than or equal to `1`. Using `1` will prevent any additional chunks from being added as the entry/main chunk is also included in the count. ```js new rspack.optimize.LimitChunkCountPlugin({ maxChunks: 5, }); ``` This page is adapted from [webpack documentation](https://webpack.js.org/plugins/limit-chunk-count-plugin/) under the [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), with modifications. --- url: /plugins/runtime-chunk-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # RuntimeChunkPlugin `RuntimeChunkPlugin` creates separate runtime chunks and controls how they are named. [`optimization.runtimeChunk`](/config/optimization.md#optimizationruntimechunk) applies this plugin internally. ## Examples This configuration extracts the runtime used by two entry points into `runtime.js`: ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { entry: { app: './src/app.js', admin: './src/admin.js', }, output: { filename: '[name].js', }, plugins: [ new rspack.optimize.RuntimeChunkPlugin({ name: 'runtime', }), ], }; ``` Rspack emits `app.js`, `admin.js`, and the shared `runtime.js`. Keeping the runtime separate allows entry bundles to be cached independently from runtime changes. ## Options ### name Used to configure the name of the runtime chunk; it can be a string or a function that returns a string, where the function parameter is the name of the entry. - **Type:** `string | ((entrypoint: { name: string }) => string)` ```js new rspack.optimize.RuntimeChunkPlugin({ name: ({ name }) => `runtime~${name}`, }); ``` --- url: /plugins/split-chunks-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # SplitChunksPlugin SplitChunksPlugin is a built-in plugin that splits code into multiple [chunks](/misc/glossary.md#chunk) to optimize application loading performance and achieve better caching strategies and parallel loading. SplitChunksPlugin can be configured through the [optimization.splitChunks](/config/optimization.md#optimizationsplitchunks) option, and you typically don't need to manually register this plugin. ## Default behavior Rspack has a built-in configuration for `SplitChunksPlugin` that works well for most scenarios. By default it only affects on-demand chunks, because changing initial chunks would affect the script tags the HTML file should include to run the project. Rspack ships with two default cache groups: - `default`: extract modules shared by at least 2 chunks. - `defaultVendors`: extract modules from `node_modules`. Rspack will automatically split chunks based on these conditions: - New chunk can be shared OR modules are from the node\_modules folder - New chunk would be bigger than 20kb (before min+gz) - Maximum number of parallel requests when loading chunks on demand would be lower or equal to 30 - Maximum number of parallel requests at initial page load would be lower or equal to 30 When trying to fulfill the last two conditions, bigger chunks are preferred. ## Examples The default value is `chunks: 'async'`, but for most production applications it is recommended to start with: ```js title="rspack.config.mjs" export default { optimization: { splitChunks: { chunks: 'all', }, }, }; ``` while keeping the default cache groups. This usually deduplicates both initial and async chunks without changing JavaScript execution semantics. Rspack's runtime still loads only the chunks reachable from the current entry or runtime. ## Options Rspack provides a set of options for developers that want more control over this functionality. :::warning The default configuration was chosen to fit web performance best practices, but the optimal strategy for your project might differ. If you're changing the configuration, you should measure the effect of your changes to ensure there's a real benefit. ::: ### optimization.splitChunks This configuration object represents the default behavior of the `SplitChunksPlugin`. ```js title="rspack.config.mjs" export default { //... optimization: { splitChunks: { chunks: 'async', minChunks: 1, minSize: 20000, maxAsyncRequests: 30, maxInitialRequests: 30, cacheGroups: { defaultVendors: { test: /[\\/]node_modules[\\/]/, priority: -10, reuseExistingChunk: true, }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true, }, }, }, }, }; ``` :::warning When files paths are processed by Rspack, they always contain `/` on UNIX systems and `\` on Windows. That's why using `[\\/]` in `{cacheGroup}.test` fields is necessary to represent a path separator. `/` or `\` in `{cacheGroup}.test` will cause issues when used cross-platform. ::: :::warning Passing an entry name to `{cacheGroup}.test` and using a name of an existing chunk for `{cacheGroup}.name` is no longer allowed. ::: ### splitChunks.cacheGroups Cache groups can inherit and/or override any options from `splitChunks.{cacheGroup}.*`; but `test`, `priority` and `reuseExistingChunk` can only be configured on cache group level. To disable any of the default cache groups, set them to `false`. ```js title="rspack.config.mjs" export default { //... optimization: { splitChunks: { cacheGroups: { default: false, }, }, }, }; ``` ### splitChunks.chunks #### splitChunks.cacheGroups.\{cacheGroup}.chunks - **Type:** ```ts type OptimizationSplitChunksChunks = 'initial' | 'async' | 'all' | RegExp | ((chunk: Chunk) => boolean); ``` - **Default:** `'async'` This option controls which chunks should be selected for code splitting. When a string is provided, the possible values are `all`, `async` and `initial`. - `all`: Split all types of chunks, including [initial chunks](/misc/glossary.md#initial-chunk) and [async chunks](/misc/glossary.md#async-chunk). - `initial`: Only split initial chunks. - `async`: Only split async chunks. Generally, setting it to `all` can help reduce duplicate modules being bundled, as it means chunks can be shared between initial chunks and async chunks. For most production applications, `chunks: 'all'` is the recommended starting point. What often hurts the result is not `chunks: 'all'` itself, but broad manual cache groups combined with a fixed [`name`](#splitchunksname). ```js title="rspack.config.mjs" export default { optimization: { splitChunks: { // include all types of chunks chunks: 'all', }, }, }; ``` :::tip Before Rspack v1.6.2, projects using [Module Federation](/guide/advanced/module-federation.md) with exposes could not enable `chunks: 'all'`, as it would break remote module splitting. Starting from v1.6.2, Module Federation works seamlessly with `chunks: 'all'`. ::: The `chunks` option can be set to a regular expression, which is a shorthand for `(chunk) => typeof chunk.name === "string" && regex.test(chunk.name)`. ```js title="rspack.config.mjs" export default { optimization: { splitChunks: { // equivalent to `chunks: (chunk) => typeof chunk.name === "string" && /foo/.test(chunk.name)` chunks: /foo/, }, }, }; ``` The `chunks` option can be set to a function for more fine-grained control. The function receives a `chunk` parameter, and returning `true` means the chunk participates in splitting (modules within it may be extracted into new chunks), while returning `false` means the chunk doesn't participate in splitting (remains as is). ```js title="rspack.config.mjs" export default { optimization: { splitChunks: { chunks(chunk) { // exclude `foo` chunk return chunk.name !== 'foo'; }, }, }, }; ``` :::warning Using the function type of `chunks` will significantly reduce build performance, as the function needs to be called for each module, resulting in huge cross-language communication overhead between Rust and JavaScript. Therefore, we do not recommend using the function type. ::: You can configure `chunks` individually for each cacheGroup, for example: ```js title="rspack.config.mjs" export default { optimization: { splitChunks: { cacheGroups: { groupA: { chunks: 'all', }, groupB: { chunks: 'initial', }, groupC: { chunks: 'async', }, }, }, }, }; ``` ### splitChunks.maxAsyncRequests - **Type:** `number` - **Default:** `30` Maximum number of parallel requests when on-demand loading. ### splitChunks.maxInitialRequests - **Type:** `number` - **Default:** `30` Maximum number of parallel requests at an entry point. ### splitChunks.enforceSizeThreshold #### splitChunks.cacheGroups.\{cacheGroup}.enforceSizeThreshold - **Type:** `number | Record` - **Default:** `50000` in production and `30000` in others Set a size threshold that lets Rspack continue splitting once a candidate chunk is large enough. When a candidate reaches this threshold, Rspack ignores request-limit checks such as [`splitChunks.maxAsyncRequests`](#splitchunksmaxasyncrequests) and [`splitChunks.maxInitialRequests`](#splitchunksmaxinitialrequests). Compared with [`splitChunks.cacheGroups.{cacheGroup}.enforce`](#splitchunkscachegroupscachegroupenforce), this is more targeted: only sufficiently large candidates are forced to keep splitting, while smaller ones still follow the normal heuristics. When configured with a `number`, the same threshold is applied to all size types defined in [`splitChunks.defaultSizeTypes`](#splitchunksdefaultsizetypes). The object form lets you set different thresholds per size type. ```js title="rspack.config.mjs" export default { optimization: { splitChunks: { enforceSizeThreshold: 80 * 1000, cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, enforceSizeThreshold: 120 * 1000, }, }, }, }, }; ``` ### splitChunks.minChunks #### splitChunks.cacheGroups.\{cacheGroup}.minChunks - **Type:** `number` - **Default:** `1` The minimum times must a module be shared among chunks before splitting. ### splitChunks.hidePathInfo - **Type:** `boolean` - **Default:** defaults to `true` if `options.mode` is `'production'`, otherwise defaults to `false` Prevents exposing path info when creating names for parts splitted by maxSize. ### splitChunks.minSize #### splitChunks.cacheGroups.\{cacheGroup}.minSize - **Type:** `number | Record` - **Default:** `20000` in production and `10000` in others When using the `number` type of configuration, the same `minSize` will be configured for all module types defined in [`splitChunks.defaultSizeTypes`](/plugins/split-chunks-plugin.md#splitchunksdefaultsizetypes). ```js title="rspack.config.mjs" export default { //... optimization: { splitChunks: { minSize: 100 * 1000, }, }, }; ``` When configured with the object form, different `minSize` can be set for different types of module types defined in `splitChunks.defaultSizeTypes`. ```js title="rspack.config.mjs" export default { //... optimization: { splitChunks: { minSize: { javascript: 100 * 1000, css: 300 * 1000, }, }, }, }; ``` For example, the above configuration means that the minimum size of javascript modules in the split chunks needs to be at least 100KB, and the minimum size of css modules needs to be at least 300KB. ### splitChunks.minSizeReduction #### splitChunks.cacheGroups.\{cacheGroup}.minSizeReduction - **Type:** `number | Record` - **Default:** `0` If there are several small modules in the build output, developers may not want to generate separate chunks for them even if their total size exceeds the `minSize` threshold. In this case, you can use the `minSizeReduction` parameter to set the minimum size reduction threshold required for module splitting. The calculation rule for this parameter is: splitting will only occur when the total size reduction across all parent chunks after splitting the module is not less than the specified value. Assuming the following scenario, suppose there is a 40KB module that is referenced by 2 chunks, and we set `minSizeReduction: 100`. If we were to split this module, each parent chunk would be reduced by 40KB, resulting in a total reduction of `40KB × 2 = 80KB`. As this is less than 100KB, the split will not be triggered. If a module still appears duplicated after lowering `minSize`, check `minSizeReduction` before assuming splitChunks is not working. ```js title="rspack.config.mjs" export default { //... optimization: { splitChunks: { minSizeReduction: 100 * 1000, }, }, }; ``` ### splitChunks.maxSize `number | Record = 0` Using `maxSize` (either globally `optimization.splitChunks.maxSize` per cache group `optimization.splitChunks.cacheGroups[x].maxSize` or for the fallback cache group `optimization.splitChunks.fallbackCacheGroup.maxSize`) tells Rspack to try to split chunks bigger than `maxSize` bytes into smaller parts. Parts will be at least `minSize` (next to `maxSize`) in size. The algorithm is deterministic and changes to the modules will only have local effects. So that it is usable when using long term caching and doesn't require records. `maxSize` is only a hint and could be violated when modules are bigger than `maxSize` or splitting would violate `minSize`. Rspack groups modules for `maxSize` using deterministic path-derived keys, so modules with similar paths tend to stay together. In practice, prefer `maxSize` when the problem is "this shared chunk is too large". It is usually a better fit than forcing a broad fixed [`name`](#splitchunksname). When the chunk has a name already, each part will get a new name derived from that name. Depending on the value of `optimization.splitChunks.hidePathInfo` it will add a key derived from the first module name or a hash of it. `maxSize` option is intended to be used with HTTP/2 and long term caching. It increases the request count for better caching. It could also be used to decrease the file size for faster rebuilding. :::tip `maxSize` takes higher priority than `maxInitialRequest/maxAsyncRequests`. Actual priority is `maxInitialRequest/maxAsyncRequests < maxSize < minSize`. ::: :::tip Setting the value for `maxSize` sets the value for both `maxAsyncSize` and `maxInitialSize`. ::: ### splitChunks.maxAsyncSize `number | Record` Like `maxSize`, `maxAsyncSize` can be applied globally (`splitChunks.maxAsyncSize`), to cacheGroups (`splitChunks.cacheGroups.{cacheGroup}.maxAsyncSize`), or to the fallback cache group (`splitChunks.fallbackCacheGroup.maxAsyncSize`). The difference between `maxAsyncSize` and `maxSize` is that `maxAsyncSize` will only affect on-demand loading chunks. ### splitChunks.maxInitialSize `number | Record` Like `maxSize`, `maxInitialSize` can be applied globally (`splitChunks.maxInitialSize`), to cacheGroups (`splitChunks.cacheGroups.{cacheGroup}.maxInitialSize`), or to the fallback cache group (`splitChunks.fallbackCacheGroup.maxInitialSize`). The difference between `maxInitialSize` and `maxSize` is that `maxInitialSize` will only affect initial load chunks. ### splitChunks.fallbackCacheGroup - **Type:** ```ts type FallbackCacheGroup = { chunks?: 'initial' | 'async' | 'all' | RegExp | ((chunk: Chunk) => boolean); minSize?: number; maxSize?: number; maxAsyncSize?: number; maxInitialSize?: number; automaticNameDelimiter?: string; }; ``` Configures options for modules that are not selected by any cache group. The fallback cache group uses the same sizing behavior as the corresponding global `splitChunks` options, but only for the remaining modules after cache group matching. ```js title="rspack.config.mjs" export default { optimization: { splitChunks: { fallbackCacheGroup: { minSize: 10_000, maxSize: 50_000, }, }, }, }; ``` ### splitChunks.automaticNameDelimiter - **Type:** `string` - **Default:** `-` By default Rspack will generate names using origin and name of the chunk (e.g. vendors-main.js). This option lets you specify the delimiter to use for the generated names. ### splitChunks.name #### splitChunks.cacheGroups.\{cacheGroup}.name - **Type:** ```ts type SplitChunksName = false | string | SplitChunksNameFunction; type SplitChunksNameFunction = ( module: Module, chunks: Chunk[], cacheGroupKey: string, ) => string | undefined; ``` - **Default:** `false` Also available for each cacheGroup: `splitChunks.cacheGroups.{cacheGroup}.name`. The name of the split chunk. Providing `false` will keep the same name of the chunks so it doesn't change names unnecessarily. It is the recommended value for production builds. Providing a string allows you to use a custom name. Specifying a string will merge all common modules and vendors into a single chunk. This might lead to bigger initial downloads and slow down page loads. When `name` is a function, Rspack calls it with these parameters: - `module`: the module that is being considered for the split chunk. You can use methods such as `module.identifier()` to derive a stable name from its request or resource path. - `chunks`: the chunks that currently contain this module and were selected by the cache group. Each item is a `Chunk` object, so common properties such as `chunk.name` are available. - `cacheGroupKey`: the key of the cache group that matched the module, for example `vendors` for `cacheGroups.vendors`. The function should return the split chunk name. Return `undefined` to let Rspack fall back to automatic naming for that module group. For example, you can name vendor chunks by the cache group key and by the selected chunk names: ```js title="rspack.config.mjs" export default { optimization: { splitChunks: { chunks: 'all', cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, name(module, chunks, cacheGroupKey) { const chunkNames = chunks .map((chunk) => chunk.name) .filter(Boolean) .sort() .join('~'); return `${cacheGroupKey}-${chunkNames || 'shared'}`; }, }, }, }, }, }; ``` You can also derive a chunk name from the package that provided the matched module: ```js title="rspack.config.mjs" export default { optimization: { splitChunks: { chunks: 'all', cacheGroups: { npmPackage: { test: /[\\/]node_modules[\\/]/, name(module, chunks, cacheGroupKey) { const identifier = module.identifier(); const match = identifier.match( /[\\/]node_modules[\\/]((?:@[^\\/]+[\\/])?[^\\/]+)/, ); const packageName = match ? match[1].replace(/[\\/]/g, '-') : 'misc'; return `${cacheGroupKey}-${packageName}`; }, }, }, }, }, }; ``` `name` is not only a filename customization. It also changes grouping behavior: when different chunk combinations hit the same cache group and resolve to the same name, Rspack will merge them into the same named split chunk candidate. This can improve cache hit rate, but it can also force a page to fetch modules from unrelated dependency chains. If your goal is only to hint chunk identity or filenames, prefer [`splitChunks.cacheGroups.{cacheGroup}.idHint`](#splitchunkscachegroupscachegroupidhint) and leave `name` unset. If the `splitChunks.name` matches an [entry point](/config/entry.md) name, the entry point will be removed. :::info `splitChunks.cacheGroups.{cacheGroup}.name` can be used to move modules into a chunk that is a parent of the source chunk. For example, use `name: "entry-name"` to move modules into the `entry-name` chunk. You can also use on demand named chunks, but you must be careful that the selected modules are only used under this chunk. ::: ### splitChunks.filename #### splitChunks.cacheGroups.\{cacheGroup}.filename - **Type:** `string | function` Allows to override the filename when and only when it's an initial chunk. All placeholders available in output.filename are also available here. ```js title="rspack.config.mjs" export default { //... optimization: { splitChunks: { cacheGroups: { defaultVendors: { filename: 'vendors-[name].js', // or filename: (pathData, assetInfo) => { return `${pathData.chunk.name}-bundle.js`; }, }, }, }, }, }; ``` ### splitChunks.usedExports - **Type:** `boolean` - **Default:** Value of [optimization.usedExports](/config/optimization.md#optimizationusedexports) Enabling this configuration, the splitting of chunks will be grouped based on the usage of modules exports in different runtimes, ensuring the optimal loading size in each runtime. For example, if there are three entry points named `foo`, `bar`, and `baz`, they all depend on the same module called `shared`. However, `foo` and `bar` depend on the export `value1` from `shared`, while `baz` depends on the export `value2` from `shared`. ```js title=foo.js import { value1 } from 'shared'; value1; ``` ```js title=bar.js import { value1 } from 'shared'; value1; ``` ```js title=baz.js import { value2 } from 'shared'; value2; ``` In the default strategy, the `shared` module appears in 3 chunks. If it meets the [minSize for splitting](/plugins/split-chunks-plugin.md#splitchunksminsize), then the `shared` module should be extracted into a separate chunk. ``` chunk foo, chunk bar \ chunk shared (exports value1 and value2) / chunk baz ``` However, this would result in none of the three entry points having the optimal loaded size. Loading the `shared` module from the `foo` and `bar` entries would unnecessarily load the export `value2`, while loading from the `baz` entry would unnecessarily load the export `value1`. When the `splitChunks.usedExports` optimization is enabled, it analyzes which exports of the `shared` module are used in different entries. It finds that the exports used in `foo` and `bar` are different from those in `baz`, resulting in the creation of two distinct chunks, one corresponding to the entries `foo` and `bar`, and the other corresponding to the entry `baz`. ``` chunk foo, chunk bar \ chunk shared-1 (exports only value1) chunk baz \ chunk shared-2 (exports only value2) ``` This option only changes how splitChunks groups modules across runtimes. It does not replace tree shaking and does not decide whether unused exports are removed. ### splitChunks.defaultSizeTypes - **Type:** `string[]` - **Default:** `["javascript", "css", "unknown"]` When calculating the size of chunks, only the sizes of javascript modules and built-in css modules are taken into account by default. For example, when configuring `minSize: 300`, both javascript modules and css modules need to meet the requirement in order to be split. You can configure additional module types, for example, if you want WebAssembly modules to be split as well: ```js title="rspack.config.mjs" export default { optimization: { splitChunks: { defaultSizeTypes: ['wasm', '...'], }, }, }; ``` ### splitChunks.cacheGroups Cache groups can inherit and/or override any options from `splitChunks.*`; but `test`, `priority` and `reuseExistingChunk` can only be configured on cache group level. To disable any of the default cache groups, set them to `false`. ```js title="rspack.config.mjs" export default { //... optimization: { splitChunks: { cacheGroups: { default: false, }, }, }, }; ``` #### splitChunks.cacheGroups.\{cacheGroup}.priority - **Type:** `number` - **Default:** `-20` A module can belong to multiple cache groups. The optimization will prefer the cache group with a higher `priority`. The default groups have a negative priority to allow custom groups to take higher priority (default value is `0` for custom groups). #### splitChunks.cacheGroups.\{cacheGroup}.test - **Type:** `RegExp | string | (module: Module, { chunkGraph: ChunkGraph, moduleGraph: ModuleGraph }) => boolean` Controls which modules are selected by this cache group. Omitting it selects all modules. It can match the absolute module resource path or chunk names. When a chunk name is matched, all modules in the chunk are selected. :::warning Using the function type of `test` will significantly reduce build performance, as the function needs to be called for each module, resulting in huge cross-language communication overhead between Rust and JavaScript. Therefore, we do not recommend using the function type. ::: #### splitChunks.cacheGroups.\{cacheGroup}.enforce - **Type:** `boolean` Tells Rspack to ignore `splitChunks.minSize`, splitChunks`.minChunks`, `splitChunks.maxAsyncRequests` and `splitChunks.maxInitialRequests` options and always create chunks for this cache group. #### splitChunks.cacheGroups.\{cacheGroup}.idHint - **Type:** `string` Sets the hint for chunk id. It will be added to chunk's filename. #### splitChunks.cacheGroups.\{cacheGroup}.reuseExistingChunk - **Type:** `boolean` - **Default** `false` Whether to reuse existing chunks when possible. If so, after splitting, the newly created chunk contains modules that are exactly the same as those in the original chunk, the original chunk will be reused, and no new chunk will be generated, which may affect the final filename of the chunk. For example: ``` chunk Foo: [ module A, module B ] chunk Bar: [ module B ] cacheGroup: { test: /B/, chunks: 'all' } ``` In chunks Foo and Bar, the module B, due to the configuration of cacheGroup, will be split into a new chunk that only contains module B. This new chunk is identical in terms of the modules it contains with chunk Bar, so chunk Bar can be directly reused. If the setting of reuseExistingChunk is set to `false`, then the module B in chunks Bar and Foo will be moved to a new chunk, and chunk Bar, since it no longer contains any modules, will be deleted as an empty chunk. #### splitChunks.cacheGroups.\{cacheGroup}.type - **Types:** `string | RegExp` Allows to assign modules to a cache group by module type. #### splitChunks.cacheGroups.\{cacheGroup}.layer - **Type:** `string | RegExp | ((layer?: string) => boolean)` Assigns modules to a cache group by module layer. This is useful when [entry](/config/entry.md#entrydescriptionlayer) or [rule](/config/module-rules.md#ruleslayer) layers are used to separate modern, legacy, server, or client code paths. ```js title="rspack.config.mjs" export default { optimization: { splitChunks: { cacheGroups: { modern: { layer: 'modern', chunks: 'all', }, }, }, }, }; ``` ## FAQ ### Why are modules still duplicated? Common reasons include: - the shared candidate is too small to satisfy [`splitChunks.minSize`](#splitchunksminsize) - the split does not satisfy [`splitChunks.minSizeReduction`](#splitchunksminsizereduction) - the candidate does not satisfy [`splitChunks.minChunks`](#splitchunksminchunks) - [`splitChunks.maxAsyncRequests`](#splitchunksmaxasyncrequests) or [`splitChunks.maxInitialRequests`](#splitchunksmaxinitialrequests) rejects the split - `chunks`, `test`, or custom cache groups do not actually select the same chunk combination Very small duplicates are often intentional. Extracting them into an extra chunk can be worse than keeping them duplicated. ### Does splitChunks affect JavaScript execution order? No. `splitChunks` changes chunk topology, but JavaScript loading and execution order are still guaranteed by the runtime dependency graph. ### Does splitChunks affect tree shaking? No. Tree shaking decides what code is kept. `splitChunks` only decides how kept modules are partitioned into chunks. ### Can splitChunks affect CSS order? Yes, potentially. This caveat is about extracted CSS, not JavaScript execution order. In extracted CSS flows such as `mini-css-extract-plugin` or Rspack's [Built-in CSS support](/guide/languages/css.md#built-in-css-support), changing chunk groups with splitChunks can also change final CSS order. See [Deep dive into webpack CSS order issue](https://github.com/orgs/web-infra-dev/discussions/12) for background. If CSS order is the primary concern, also review [CssChunkingPlugin](/plugins/css-chunking-plugin.md). This page is adapted from [webpack documentation](https://webpack.js.org/configuration/optimization/) under the [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), with modifications. --- url: /plugins/swc-js-minimizer-rspack-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # SwcJsMinimizerRspackPlugin Rspack only This plugin is used to minify JavaScript files using [SWC](https://swc.rs/). ## Examples Use this plugin via [optimization.minimizer](/config/optimization.md#optimizationminimizer): ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { optimization: { minimizer: [ new rspack.SwcJsMinimizerRspackPlugin({ // options }), new rspack.LightningCssMinimizerRspackPlugin(), ], }, }; ``` :::tip When `optimization.minimizer` is set, the default minimizers are disabled, so we need to add [LightningCssMinimizerRspackPlugin](/plugins/lightning-css-minimizer-rspack-plugin.md) to minify CSS files. ::: ## Options ### test - **Type:** `string | RegExp | Array` - **Default:** `\.[cm]?js(\?.*)?$` Specify the files to be minimized. You can use regular expressions or file path strings, and only the files that match will be minimized. For example, the build generates `/dist/foo.[hash].js` and some other JS files, we only minify `foo.js`: ```js new rspack.SwcJsMinimizerRspackPlugin({ test: /dist\/foo\.\w+\.js$/, }); ``` ### include - **Type:** `string | RegExp | Array` - **Default:** `undefined` Same as `test`, specify the files to be minimized. ```js new rspack.SwcJsMinimizerRspackPlugin({ include: /dist\/foo\.\w+\.js$/, }); ``` ### exclude - **Type:** `string | RegExp | Array` - **Default:** `undefined` Specify the files to be excluded. You can use regular expressions or file path strings, and the files that match will not be minimized. For example, the build generates `/dist/foo.[hash].js` and some other JS files, we exclude the minimization of `foo.js`: ```js new rspack.SwcJsMinimizerRspackPlugin({ exclude: /dist\/foo\.\w+\.js$/, }); ``` ### extractComments - **Type:** ```ts type ExtractCommentsOptions = | boolean | RegExp | { condition?: boolean | RegExp | undefined; banner?: string | boolean | undefined; }; ``` - **Default:** `undefined` Whether comments shall be extracted to a separate file. If the original file is named `foo.js`, then the comments will be stored to `foo.js.LICENSE.txt`. #### Boolean form If value is `true`, it is equivalent to `/@preserve|@lic|@cc_on|^\**!/` regexp condition and remove remaining comments. ```js new rspack.SwcJsMinimizerRspackPlugin({ extractComments: { condition: /@preserve|@lic|@cc_on|^\**!/, }, }); ``` If value is `false`, all comments will be removed. ```js new rspack.SwcJsMinimizerRspackPlugin({ extractComments: false, }); ``` #### Regular expression form If value is `RegExp`, all comments that match the given expression will be extracted to the separate file. ```js new rspack.SwcJsMinimizerRspackPlugin({ extractComments: /@preserve|@lic|@cc_on|^\**!/, }); ``` #### Object form If value is `object`, it can use `condition` and `banner` to customize the extraction. ```js new rspack.SwcJsMinimizerRspackPlugin({ extractComments: { // add comments that match the condition will be extracted condition: /@preserve|@lic|@cc_on|^\**!/, // add banner to the top of the `*.LICENSE.txt` file // If `true`, use the default banner `/*! LICENSE: {relative} */` // If `false`, no banner will be added // If `string`, use the given banner banner: true, }, }); ``` ### minimizerOptions - **Type:** ```ts type MinimizerOptions = { minify?: boolean; module?: boolean; ecma?: 5 | 2015 | 2016 | string | number; mangle?: TerserMangleOptions | boolean; compress?: TerserCompressOptions | boolean; format?: JsFormatOptions & ToSnakeCaseProperties; }; ``` - **Default:** ```js const defaultOptions = { minify: true, mangle: true, ecma: 5, // or derived from Rspack's target configuration compress: { passes: 2, } format: { comments: false, }, }; ``` :::tip Default ecma from Rspack target If `ecma` is not specified, `SwcJsMinimizerRspackPlugin` will automatically derive a default value from Rspack's [`target`](/config/target.md) configuration. Otherwise, it defaults to `5`. This means you can rely on your Rspack `target` configuration without manually specifying the same ecma version in the plugin options. ::: Similar to the `jsc.minify` option of SWC, please refer to [SWC - Minification](https://swc.rs/docs/configuration/minification) for all available options. For example, disable `mangle` to avoid mangling variable names: ```js new rspack.SwcJsMinimizerRspackPlugin({ minimizerOptions: { mangle: false, }, }); ``` For example, set a higher `passes` to run more compression passes. In some cases this may result in a smaller bundle size, but the more passes that are run, the more time it takes to compress. ```js new rspack.SwcJsMinimizerRspackPlugin({ minimizerOptions: { compress: { passes: 4, }, }, }); ``` --- url: /plugins/context-replacement-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # ContextReplacementPlugin `ContextReplacementPlugin` changes which modules dynamic `require`, dynamic `import()`, and [`require.context()`](/api/runtime-api/module-methods.md#requirecontext) calls can load, and where Rspack looks for them. Rspack represents these requests as [context modules](/misc/glossary.md#context-module). For example, `import('./locales/' + name + '.js')` creates a context module. Use [`resourceRegExp`](#resourceregexp) to select the context modules to modify. `ContextReplacementPlugin` can replace their search directory, recursive behavior, request-matching regular expression, or request map. Omitted arguments keep the original values, and other context modules are unchanged. The plugin also suppresses the `Critical dependency` warning for matched contexts. ## Examples ### Limit the modules in a context Suppose `src/locales` contains `en.js`, `fr.js`, and `zh.js`, and the entry loads a locale dynamically: ```js title="src/index.js" export const loadLocale = (name) => import(`./locales/${name}.js`); ``` The following configuration searches only the top level of `src/locales` and includes only the English and Chinese locale modules: ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { entry: './src/index.js', plugins: [ new rspack.ContextReplacementPlugin( /[/\\]locales$/, false, /^\.\/(en|zh)\.js$/, ), ], }; ``` The generated context map contains only these request keys: ```js title="dist/main.js (simplified)" const localeRequestMap = { './en.js': 'module-id-for-en', './zh.js': 'module-id-for-zh', }; ``` ## Options The plugin accepts positional arguments, so their order matters. ### resourceRegExp - **Type:** `RegExp` - **Required:** Yes Selects the context modules to modify. Before resolution, Rspack tests the expression against the context request, such as `./locales`. After resolution, it tests the same expression against the resolved context resource directory, which is normally an absolute path. At each matching phase, Rspack applies the replacement arguments supported by that phase. A context that does not match at either phase is unchanged. Use a regular expression that accounts for both `/` and `\` when matching directory separators. If no other arguments are passed, Rspack keeps the inferred resource, recursive flag, and request regular expression, but still removes the critical dependency warning from a matched context. ```js new rspack.ContextReplacementPlugin(/[/\\]locales$/); ``` ### newContentResource - **Type:** `string` - **Default:** `undefined` Replaces the resource directory from which a matched context resolves modules. When `resourceRegExp` matches before resolution, this value replaces the context request and is resolved as the new request. When `resourceRegExp` matches the resolved resource, an absolute value replaces that resource directly, while a relative value is resolved from the previous resource directory. Pass `newContentResource` as the second argument. If it is omitted, Rspack keeps the inferred resource. When it is followed by [`newContentCreateContextMap`](#newcontentcreatecontextmap), the replacement resource is also the base directory for the map's compile-time requests. ```js new rspack.ContextReplacementPlugin( /[/\\]src[/\\]locales$/, '../translated-locales', ); ``` For a context originally resolved to `src/locales`, this example changes the resource to the sibling directory `src/translated-locales`. ### newContentRecursive - **Type:** `boolean` - **Default:** `undefined` Replaces the recursive flag used when Rspack discovers modules under the context resource. Set it to `true` to search subdirectories or `false` to search only the resource directory itself. If omitted, Rspack keeps the recursive behavior inferred from the original context. This flag controls which directories Rspack scans before [`newContentRegExp`](#newcontentregexp) filters the generated request keys. It is not used with [`newContentCreateContextMap`](#newcontentcreatecontextmap), because an explicit map replaces directory scanning. - **Without resource replacement:** Pass the boolean as the second argument. ```js new rspack.ContextReplacementPlugin(/[/\\]locales$/, false); ``` - **With resource replacement:** Pass the resource string second and the boolean third. ```js new rspack.ContextReplacementPlugin( /[/\\]src[/\\]locales$/, '../translated-locales', false, ); ``` ### newContentRegExp - **Type:** `RegExp` - **Default:** `undefined` Replaces the regular expression used to select request keys while Rspack scans the context resource. It is tested against context-relative requests such as `./en.js`, not absolute file paths. This expression replaces the inferred expression; the two expressions are not combined. If omitted, Rspack keeps the inferred expression. [`newContentRecursive`](#newcontentrecursive) first determines which directories are scanned, then `newContentRegExp` filters the request keys found in those directories. This argument is not used with [`newContentCreateContextMap`](#newcontentcreatecontextmap), because the map supplies the complete set of request keys. - **Without resource or recursive replacement:** Pass the regular expression as the second argument. ```js new rspack.ContextReplacementPlugin(/[/\\]locales$/, /^\.\/(en|zh)\.js$/); ``` - **With recursive replacement only:** Pass the boolean second and the regular expression third. ```js new rspack.ContextReplacementPlugin( /[/\\]locales$/, false, /^\.\/(en|zh)\.js$/, ); ``` - **With resource replacement:** Pass the resource string second, a boolean third, and the regular expression fourth. The boolean cannot be skipped. ```js new rspack.ContextReplacementPlugin( /[/\\]src[/\\]locales$/, '../translated-locales', false, /^\.\/(en|zh)\.js$/, ); ``` ### newContentCreateContextMap - **Type:** `Record` - **Default:** `undefined` Supplies the complete request map for a matched context. Each property key is a runtime request accepted by the context, and its value is the compile-time request resolved from `newContentResource`. Only keys in this map are available at runtime. Resource queries and fragments from the context are appended to the mapped compile-time requests. Pass the map as the third argument after a `newContentResource` string. This form replaces automatic directory scanning, so it is an alternative to `newContentRecursive` and `newContentRegExp`. If the map is omitted, Rspack discovers modules using the current resource, recursive flag, and request regular expression. Rspack installs the map after resolving the context. Therefore, `resourceRegExp` must match the resource seen after resolution; matching only the pre-resolution request is not sufficient. ```js new rspack.ContextReplacementPlugin( /[/\\]src[/\\]locales$/, '../translated-locales', { './en.js': './en.js', './default.js': './en.js', }, ); ``` For a context originally resolved to `src/locales`, this example loads modules from `src/translated-locales`. At runtime, both `./en.js` and `./default.js` load the compile-time request `./en.js` from that replacement resource. This page is adapted from [webpack documentation](https://webpack.js.org/plugins/context-replacement-plugin/) under the [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), with modifications. --- url: /plugins/define-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # DefinePlugin The `DefinePlugin` replaces variables in your code with other values or expressions at compile time. This can be useful for allowing different behavior between development builds and production builds. If you perform logging in your development build but not in the production build you might use a global constant to determine whether logging takes place. That's where `DefinePlugin` shines, set it and forget it rules for development and production builds. ## Examples ### Basic use case Each key passed into `DefinePlugin` is an identifier or multiple identifiers joined with `.`. - If the value is a string it will be used as a code fragment. - If the value isn't a string, it will be stringified (including functions). - If the value is an object all keys are defined the same way. - If you prefix `typeof` to the key, it's only defined for typeof calls. The values will be inlined into the code allowing a minification pass to remove the redundant conditional. ```js new rspack.DefinePlugin({ PRODUCTION: JSON.stringify(true), VERSION: JSON.stringify('5fa3b9'), BROWSER_SUPPORTS_HTML5: true, TWO: '1+1', 'typeof window': JSON.stringify('object'), 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), }); ``` ```js console.log('Running App version ' + VERSION); if (!BROWSER_SUPPORTS_HTML5) require('html5shiv'); ``` :::warning When defining values for `process` prefer `'process.env.NODE_ENV': JSON.stringify('production')` over `process: { env: { NODE_ENV: JSON.stringify('production') } }`. Using the latter will overwrite the `process` object which can break compatibility with some modules that expect other values on the process object to be defined. ::: :::tip Note that because the plugin does a direct text replacement, the value given to it must include **actual quotes** inside of the string itself. Typically, this is done either with alternate quotes, such as `'"production"'`, or by using `JSON.stringify('production')`. ::: ```js if (!PRODUCTION) { console.log('Debug info'); } if (PRODUCTION) { console.log('Production log'); } ``` After passing through Rspack with no minification results in: ```js if (!true) { console.log('Debug info'); } if (true) { console.log('Production log'); } ``` and then after a minification pass results in: ```js console.log('Production log'); ``` ### Feature flags Enable/disable features in production/development build using [feature flags](https://en.wikipedia.org/wiki/Feature_toggle). ```js new rspack.DefinePlugin({ NICE_FEATURE: JSON.stringify(true), EXPERIMENTAL_FEATURE: JSON.stringify(false), }); ``` ### Service URLs Use a different service URL in production/development builds: ```js new rspack.DefinePlugin({ SERVICE_URL: JSON.stringify('https://dev.example.com'), }); ``` ## Options - **Type:** ```ts type CodeValue = RecursiveArrayOrRecord; type CodeValuePrimitive = null | undefined | RegExp | Function | string | number | boolean | bigint; type RecursiveArrayOrRecord = | { [index: string]: RecursiveArrayOrRecord } | Array> | T; type DefinePluginOptions = Record; ``` Maps identifiers or property paths to the code fragments that replace them at compile time. Each key in the object is one definition, such as `DEBUG` or `process.env.NODE_ENV`. ## Use `JSON.stringify` Use `JSON.stringify` when you want to inject a literal value rather than a code fragment. Common cases include: - Injecting string constants such as environment names, versions, or API endpoints. - Injecting objects or arrays that should be read directly in application code. - Injecting string values from environment variables such as `process.env.*`. This is because string values passed to `DefinePlugin` are inserted directly as code and do not get quotes added automatically. ```js new rspack.DefinePlugin({ MODE: 'production', MODE_STRINGIFIED: JSON.stringify('production'), }); ``` ```js const mode = MODE; const modeStringified = MODE_STRINGIFIED; // Turns into const mode = production; const modeStringified = 'production'; ``` In the example above, `MODE` is treated as the identifier `production` instead of the string `'production'`, which will usually cause a runtime error. `MODE_STRINGIFIED` is replaced with a valid string literal, making it the safer option. If you need to inject an object or array, `JSON.stringify` is also recommended: ```js new rspack.DefinePlugin({ APP_INFO: JSON.stringify({ name: 'demo', features: ['a', 'b'], }), }); ``` This makes `APP_INFO` a usable object literal in the generated code. By contrast, `APP_INFO: { ... }` would be treated by `DefinePlugin` as a nested definition config and processed recursively, rather than being injected as an object literal into application code. This page is adapted from [webpack documentation](https://webpack.js.org/plugins/define-plugin/) under the [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), with modifications. --- url: /plugins/entry-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # EntryPlugin Adds an entry chunk on compilation. The chunk is named `options.name` and contains only one module (plus dependencies). The module is resolved from `entry` in `context` (absolute path). ## Examples Register an entry from a plugin: ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { plugins: [ new rspack.EntryPlugin(process.cwd(), './src/index.js', { name: 'main' }), ], }; ``` ## Options ### context The module is resolved from `entry` in `context` (absolute path). - **Type:** `string` ### entry The module path for the entry module. - **Type:** `string` ### options To adjust settings related to the entry module. - **Type:** ```ts type EntryOptions = | string | (Omit & { /** * The name of the entry chunk. */ name?: string; }); ``` If `options` is a string, its value will be used as `name`. Refer to [Entry description object](/config/entry.md#entry-description-object) for all available options. ## Global entry When the plugin's `name` option is set to `undefined`, the entry is treated as a global entry. It's automatically injected into: 1. All regular entry chunks 2. All asynchronous entries (for example, worker chunks created with `new Worker()`) This allows you to inject global runtime code, such as the dev server's HMR runtime or the initialization logic for module federation. ```js new rspack.EntryPlugin(context, './global-runtime.js', { name: undefined }); ``` --- url: /plugins/environment-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # EnvironmentPlugin `EnvironmentPlugin` is shorthand for defining selected [`process.env`](https://nodejs.org/api/process.html#process_process_env) values with [`DefinePlugin`](/plugins/define-plugin.md). It reads environment variables when Rspack builds and replaces the corresponding `process.env.*` expressions in your bundled code. ## Examples ### Basic usage Pass environment variable names as separate arguments or as an array. The following calls are equivalent: ```js new rspack.EnvironmentPlugin('NODE_ENV', 'DEBUG'); new rspack.EnvironmentPlugin(['NODE_ENV', 'DEBUG']); ``` Both configurations create definitions equivalent to: ```js new rspack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), 'process.env.DEBUG': JSON.stringify(process.env.DEBUG), }); ``` If a requested variable is missing and has no default value, compilation fails with an `EnvVariableNotDefinedError`. ### Using default values Pass an object to provide a default value for each variable. A default is used only when the corresponding key is `undefined` in `process.env` when the build starts. ```js new rspack.EnvironmentPlugin({ NODE_ENV: 'development', DEBUG: false, }); ``` `EnvironmentPlugin` serializes default values with `JSON.stringify` before passing them to `DefinePlugin`. As a result, JSON-compatible defaults preserve their types: the `false` default above is injected as a boolean rather than a string. Use `undefined` for a variable that must be provided during the build. If it is missing, compilation fails. Use `null` to provide an optional variable with a `null` fallback. For example, suppose `entry.js` contains: ```js if (process.env.NODE_ENV === 'production') { console.log('Welcome to production'); } if (process.env.DEBUG) { console.log('Debugging output'); } ``` If `NODE_ENV=production` is set for the build and `DEBUG` is unset, the replacements are equivalent to: ```js if ('production' === 'production') { // process.env.NODE_ENV comes from the environment console.log('Welcome to production'); } if (false) { // process.env.DEBUG uses the default value console.log('Debugging output'); } ``` If `DEBUG=false` is set and `NODE_ENV` is unset, the replacements are equivalent to: ```js if ('development' === 'production') { // process.env.NODE_ENV uses the default value console.log('Welcome to production'); } if ('false') { // process.env.DEBUG comes from the environment console.log('Debugging output'); } ``` :::tip Environment variables read from `process.env` are always strings. Setting `DEBUG=false` injects the string `'false'`, not the boolean `false`. ::: ### Using Git metadata Default values can also be computed while loading the Rspack configuration. This example exposes the version and author date of the current Git commit: ```js import { execFileSync } from 'node:child_process'; function git(...args) { return execFileSync('git', args, { encoding: 'utf8' }).trim(); } new rspack.EnvironmentPlugin({ GIT_VERSION: git('describe', '--always'), GIT_AUTHOR_DATE: git('log', '-1', '--format=%aI'), }); ``` ### Loading `.env` files `EnvironmentPlugin` does not read `.env` files by itself. To load variables from a file, use a third-party plugin such as [`dotenv-webpack`](https://github.com/mrsteele/dotenv-webpack): ```text title=".env" PUBLIC_API_ORIGIN=https://api.example.com FEATURE_ENABLED=true ``` ```js import Dotenv from 'dotenv-webpack'; new Dotenv({ path: './.env', }); ``` Only load values that are safe to embed in client-side code, because injected values can be read from the generated bundle. ## Options - **Type:** ```ts declare class EnvironmentPlugin { constructor(...keys: string[]); constructor(keys: string[]); constructor(defaultValues: Record); } ``` Use either string form when every selected variable is required. Use the object form to provide default values; assigning `undefined` still marks that variable as required. This page is adapted from [webpack documentation](https://webpack.js.org/plugins/environment-plugin/) under the [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), with modifications. --- url: /plugins/externals-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # ExternalsPlugin This plugin allows you to specify external dependencies that should not be bundled into the output files. This is particularly useful for libraries that are already available globally or managed by other scripts. The [`externalsType`](/config/externals.md#externalstype) and [`externals`](/config/externals.md#externals) configurations leverage the plugin internally. Therefore, you can utilize the respective functionality directly through these configuration options without needing to use the plugin separately. ## Examples Externalize React as a CommonJS dependency: ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { plugins: [new rspack.ExternalsPlugin('commonjs', ['react'])], }; ``` ## Options ### type **Type:** ```ts type ExternalsType = | 'var' | 'module' | 'assign' | 'this' | 'window' | 'self' | 'global' | 'commonjs' | 'commonjs2' | 'commonjs-module' | 'commonjs-static' | 'amd' | 'amd-require' | 'umd' | 'umd2' | 'jsonp' | 'system' | 'promise' | 'import' | 'module-import' | 'modern-module' | 'commonjs-import' | 'script' | 'node-commonjs'; ``` Specifies the default type for the `externals`. For more details, refer to [externalsType](/config/externals.md#externalstype). ### externals **Type:** ```ts type Externals = ExternalItem[] | ExternalItem; type ExternalItem = | RegExp | string | ( | (( data: ExternalItemFunctionData, callback: (err?: Error | null, result?: ExternalItemValue) => void, ) => void) | ((data: ExternalItemFunctionData) => Promise) ); type ExternalItemValue = | string[] | boolean | string | { [k: string]: any; }; type ExternalItemFunctionData = { context?: string; contextInfo?: ModuleFactoryCreateDataContextInfo; getResolve?: ( options?: ResolveOptions, ) => | (( context: string, request: string, callback: (err?: Error, result?: string) => void, ) => void) | ((context: string, request: string) => Promise); request?: string; }; type ModuleFactoryCreateDataContextInfo = { issuer: string; compiler: string; }; ``` **Prevent bundling** of certain `import`ed packages and instead retrieve these _external dependencies_ at runtime. For more details, refer to [externals](/config/externals.md#externals). --- url: /plugins/ignore-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # IgnorePlugin This plugin ignores selected module references, so files referenced by matching `import` or `require` statements are not included in the bundle. ## How it works Rspack examines each module reference before resolution. For a direct `import` or `require`, it checks the unresolved module specifier. For a dynamic lookup such as `require('./locale/' + name)`, it checks the context path extracted from the expression. Rspack ignores the module reference when the configured regular expression matches this value or the filter function returns `true`. Other module references are resolved and bundled normally. `IgnorePlugin` does not replace an ignored module with an empty module. Instead, Rspack skips resolving it and does not generate the corresponding module. If the bundle executes the code generated for the matching `import` or `require`, that code throws an error whose `code` is `MODULE_NOT_FOUND` at runtime. Before using the plugin, make sure this code will not run in the target environment, or that the referencing code already handles a missing module. Use [`resourceRegExp`](#resourceregexp) or [`checkResource`](#checkresource) to select module references to ignore. To limit a regular-expression rule by the referencing module's directory, combine [`contextRegExp`](#contextregexp) with [`resourceRegExp`](#resourceregexp). ## Common use cases Use `IgnorePlugin` only when omitting the referenced module is safe. Common cases include: - Removing groups of resources that a library discovers dynamically, such as Moment.js locale modules that the application does not use. - Excluding optional or environment-specific modules when their code path will not run, or when the referencing code handles a missing module. - Restricting an ignore rule to references from a particular package or directory, so the same module specifier can still resolve elsewhere. ## Examples ### Ignore a specific import The following configuration ignores every module reference whose unresolved module specifier is exactly `./optional-feature`, regardless of the referencing module's directory: ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { entry: './src/index.js', plugins: [ new rspack.IgnorePlugin({ resourceRegExp: /^\.\/optional-feature$/, }), ], }; ``` For example, the entry contains this static import: ```js title="src/index.js" import './optional-feature'; ``` Because `contextRegExp` is omitted, the rule applies to module references from every directory. Other module specifiers are resolved normally. Rspack does not generate a module for `./optional-feature` or replace it with an empty module. The generated JavaScript does not retain the original `import` syntax. Instead, Rspack emits a missing-module expression at the corresponding position. When the entry evaluates this expression, it throws an error whose `code` is `MODULE_NOT_FOUND`: ```js title="dist/main.js (simplified)" Object( (function __rspack_missing_module() { const error = new Error("Cannot find module './optional-feature'"); error.code = 'MODULE_NOT_FOUND'; throw error; })(), ); ``` This example deliberately demonstrates the runtime failure caused by executing an ignored static import. ### Ignore Moment.js locales Moment.js loads locales dynamically with `require('./locale/' + name)`. Rspack extracts `./locale` as the context path for this expression. To ignore the lookup only when the referencing module is in a directory ending in `moment`, configure both `resourceRegExp` and `contextRegExp`: ```js new rspack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/, }); ``` The entry can import Moment.js normally: ```js title="src/index.js" import moment from 'moment'; console.log(moment().format()); ``` Rspack tests `resourceRegExp` against the extracted context path `./locale`, not the resolved path `moment/locale`. Because both regular expressions match, the emitted bundle keeps Moment.js itself but contains no modules from `moment/locale`: ```js title="dist/main.js (simplified)" // Moment.js core is included in the bundle. // No moment/locale/*.js modules are included. ``` ## Options ### resourceRegExp - **Type:** `RegExp` - **Default:** `undefined` Rspack tests `resourceRegExp` before resolution. For a direct module reference, the tested value is the unresolved module specifier. For a dynamic module lookup, it is the context path extracted from the expression. For example, `import './optional-feature'` is tested as `./optional-feature`, while `require('./locale/' + name)` is tested as `./locale`. Neither value is a resolved absolute path. When the expression matches and `contextRegExp` is omitted, Rspack does not generate the referenced module, regardless of the referencing module's directory. When `contextRegExp` is set, both expressions must match. If `resourceRegExp` is omitted, provide `checkResource`; omitting both is not valid according to the public options type. ```js new rspack.IgnorePlugin({ resourceRegExp: /^\.\/optional-feature$/, }); ``` ### contextRegExp - **Type:** `RegExp` - **Default:** `undefined` Tests the referencing module's directory (`context`), normally an absolute path. Rspack evaluates this expression only after `resourceRegExp` matches, and skips module generation only when both expressions match. If omitted, a `resourceRegExp` match applies regardless of the referencing module's directory. `contextRegExp` has no effect without `resourceRegExp`; use the `context` parameter of `checkResource` when using the function form. ```js new rspack.IgnorePlugin({ resourceRegExp: /^\.\/optional-feature$/, contextRegExp: /[/\\]legacy$/, }); ``` ### checkResource - **Type:** ```ts (resource: string, context: string) => boolean; ``` - **Default:** `undefined` Runs before Rspack resolves each module reference. `resource` is the same value tested by `resourceRegExp`: the unresolved module specifier for a direct reference, or the extracted context path for a dynamic lookup. `context` is the referencing module's directory. Return `true` to stop resolution and module generation. Return `false` to continue processing. This is the function-based alternative to `resourceRegExp` and `contextRegExp`. If it is omitted, provide `resourceRegExp`. To restrict a function match by the referencing module's directory, test `context` inside the function. Rspack evaluates `checkResource` before the regular expression options. If both forms are supplied, returning `true` takes priority and stops resolution and module generation immediately. Returning `false` lets Rspack evaluate `resourceRegExp` and `contextRegExp` next. Normal resolution continues only when neither form ignores the module reference. ```js new rspack.IgnorePlugin({ checkResource(resource, context) { return resource === './optional-feature' && /[/\\]legacy$/.test(context); }, }); ``` --- url: /plugins/javascript-modules-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # JavascriptModulesPlugin Handles the bundling of JavaScript, usually used to access the [hooks of the JavascriptModulesPlugin](/api/plugin-api/javascript-modules-plugin-hooks.md): ## Examples ```js title="rspack.config.mjs" class MyJsMinimizerPlugin { apply(compiler) { compiler.hooks.compilation.tap(MyJsMinimizerPlugin.name, (compilation) => { // Access the chunkHash hooks of JavascriptModulesPlugin const hooks = compiler.rspack.javascript.JavascriptModulesPlugin.getCompilationHooks( compilation, ); // Since the JS chunk has been optimized and its content has changed, the chunk hash for the JS chunk needs to be updated hooks.chunkHash.tap(MyJsMinimizerPlugin.name, (chunk, hash) => { hash.update(`minimized by ${MyJsMinimizerPlugin.name}`); }); // Optimize the JS chunk compilation.hooks.processAssets.tap( MyJsMinimizerPlugin.name, (assets) => { optimize(assets); }, ); }); } } export default { plugins: [new MyJsMinimizerPlugin()], }; ``` ## Static methods ### `getChunkFilenameTemplate` [Added in v2.2.2](https://github.com/web-infra-dev/rspack/releases/tag/v2.2.2) ```ts function getChunkFilenameTemplate( chunk: Chunk, outputOptions: Output, ): Filename | undefined; ``` Returns the filename template that is used to render the JavaScript file of the given chunk, resolved in this order: 1. `chunk.filenameTemplate`, if the chunk carries its own template (for example a chunk produced by a `splitChunks` cache group with `filename` set). 2. [`output.filename`](/config/output.md#outputfilename), if the chunk can be initial. 3. [`output.chunkFilename`](/config/output.md#outputchunkfilename) otherwise. ```js class MyPlugin { apply(compiler) { const { JavascriptModulesPlugin } = compiler.rspack.javascript; compiler.hooks.compilation.tap('MyPlugin', (compilation) => { compilation.hooks.afterSeal.tap('MyPlugin', () => { for (const chunk of compilation.chunks) { const template = JavascriptModulesPlugin.getChunkFilenameTemplate( chunk, compilation.outputOptions, ); const filename = compilation.getPath(template, { chunk }); console.log(filename); } }); }); } } ``` :::info Difference from webpack Hot update chunks are not currently supported because they are not yet exposed to the JavaScript side. ::: --- url: /plugins/module-federation-plugin.md --- > For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt. # ModuleFederationPlugin `ModuleFederationPlugin` enables Module Federation in Rspack. This plugin implements the Module Federation 1.5 specification. If you want to learn more about the core concepts, usage, and best practices of Module Federation, please refer to the [Module Federation Guide](/guide/advanced/module-federation.md). ## Install dependencies This plugin depends on the runtime package [@module-federation/runtime-tools](https://www.npmjs.com/package/@module-federation/runtime-tools), which provides runtime support for Module Federation. Please install it first: ```sh [npm] npm add @module-federation/runtime-tools ``` ```sh [yarn] yarn add @module-federation/runtime-tools ``` ```sh [pnpm] pnpm add @module-federation/runtime-tools ``` ```sh [bun] bun add @module-federation/runtime-tools ``` ```sh [deno] deno add npm:@module-federation/runtime-tools ``` ## Examples ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { output: { // set uniqueName explicitly to make HMR works uniqueName: 'app', }, plugins: [ new rspack.container.ModuleFederationPlugin({ name: 'app', }), ], }; ``` ## Options ### implementation - Type: `string` Provide a path as the implementation for Module Federation 1.5 runtime, which defaults to [@module-federation/runtime-tools](https://github.com/module-federation/universe/tree/main/packages/runtime-tools). ### runtimePlugins - Type: ```ts type RuntimePlugins = string[] | [plugin: string, options: Record][]; ``` Provide the plugins required to run Module Federation 1.5, which can extend its behavior and capabilities. Use an array of module paths, or an array of `[modulePath, options]` tuples when a plugin needs options. ### name - Type: `string` Define the unique name exposed to other containers in the current build. This name will exist as a global variable for the remote container. ### filename - Type: `string` Specify the filename of the remote container entry file. Other containers will load the exposed modules through this file. ### runtime - Type: `string | false` Define the runtime chunk for remote container entry. ### library - Type: [`LibraryOptions`](/config/output.md#outputlibrary) Define the output format of remote container entry. The default libraryType is "var". ### shareScope - Type: `string | string[]` Define the namespace for shared dependencies in the current container. By configuring share scopes between different containers, the sharing behavior of modules can be controlled, including determining which modules are shared between different containers. The default share scope is `"default"`. ### shareStrategy - Type: `'version-first' | 'loaded-first'` Control the loading strategy of shared dependencies: - `'version-first'`: Version takes precedence. After setting, all _remotes_ entry files will be automatically loaded and **register** the corresponding shared dependencies to ensure that all shared dependency versions can be obtained. This strategy is recommended when there are strict version requirements. - `'loaded-first'`: reuse first. After setting, the _remotes_ entry file will not be automatically loaded (it will only be loaded when needed), and registered shared dependencies will be reused first. This strategy is recommended when there are no strict requirements on the version and performance is required. ### remoteType - Type: [`ExternalsType`](/config/externals.md#externalstype) Defines how to load remote containers, defaulting to `"script"`, which loads via the `