--- url: /misc/branding/guideline.md --- # Branding guideline Here you can find the branding guideline, assets and license for the project. ## The name When used standalone, Rspack should always be written as Rspack, not rspack or RSPACK or RSPack. However, lowercase letters can be used in command lines or package names, such as `@rspack/cli`. ## Rspack logo Rspack logo is a small crab as fast as lightning, representing fast compilation of Rspack. ## Design resources You can find all of Rspack's design resources under the [rstack-design-resources](https://github.com/rspack-contrib/rstack-design-resources) repository. The design resources of Rspack are licensed under the [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en) license. --- url: /guide/start/introduction.md --- # Introduction Rspack (pronounced as `/'ɑrespæk/`, ) is a high performance JavaScript bundler written in Rust. It offers strong compatibility with the webpack ecosystem, allowing for seamless replacement of webpack, and provides 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. This in turn may pose steep migration costs for legacy projects that try to migrate 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, etc. 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 is now what we consider production-ready as 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](/guide/compatibility/plugin.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, perhaps because the authors did not have deep knowledge of webpack internals, or simply because the hook system by nature limits interaction of algorithms. 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 for build times than ordinary bundling. Rspack incorporates a specialized incremental compilation strategy to address this requirement. ### Compared with Vite [Vite](https://vitejs.dev/) offers a great developer experience, but its reliance on [Rollup](https://rollupjs.org/) for production builds faces similar performance costs as other JavaScript-based algorithms. The same tradeoffs of webpack versus Rollup also apply, for example missing flexibility of the [optimization.splitChunks](/config/optimization.md#optimizationsplitchunks) feature. ### 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](https://turbo.build/) 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 Rspack and Rollup are both bundling tools, but they focus on different areas. Rollup is more suitable for bundling libraries, while Rspack is more suitable for bundling applications. Therefore, Rspack has optimized many features for bundling applications, such as HMR and Bundle splitting. Rollup produces ESM outputs that are more friendly to libraries than Rspack. There are also many tools in the community that encapsulate Rollup to some extent and provide more friendly support for bundling applications, such as vite and wmr. Currently, Rspack has better production build performance than rollup. ### Compared with Parcel The overall architecture of Rspack shares many similarities with [Parcel](https://parceljs.org/). For example, both treat CSS assets as first-class citizens 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 innovatively designed features like the Unified Graph and making HTML a first-class citizen. Rspack also plans to support these features in the future. ## Next step 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 --- # 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. ## Setup environment Rspack supports using [Node.js](https://nodejs.org/), [Deno](https://deno.com/), or [Bun](https://bun.sh/) as the runtime. ### Node.js For Node.js, please install Node.js >= 16, it is recommended to use the Node.js LTS version. Check the current Node.js version with the following command: ```bash node -v ``` If you do not have Node.js installed in current environment, or the installed version is too low, you can use [nvm](https://github.com/nvm-sh/nvm) or [fnm](https://github.com/Schniz/fnm) to install. Here is an example of how to install via nvm: ```bash # Install Node.js LTS nvm install --lts # Switch to Node.js LTS nvm use --lts ``` ## 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.dev/) to create new projects, simply run the following command: > For more information, refer to [Rsbuild - Quick start](https://rsbuild.dev/guide/start/quick-start). ### Using the Rspack CLI Rspack CLI is a tool comparable to webpack CLI, offering the basic `serve` and `build` commands. Rsbuild supports Node.js >= 16, but Rspack CLI requires Node.js version >= 18.12.0. Run the following command to create an Rspack CLI project: Then follow the prompts in your terminal. ### Quick creation [create-rspack](https://www.npmjs.com/package/create-rspack) and [create-rsbuild](https://www.npmjs.com/package/create-rsbuild) provides some CLI flags. By setting these CLI flags, you can skip the interactive selection steps and create the project with one command. For example, to create a React project in the `my-project` directory with one command: ```bash # Rspack CLI npx create-rspack --dir my-project --template react # Rsbuild npx create-rsbuild --dir my-project --template react # Using abbreviations npx create-rsbuild -d my-project -t react ``` ## Online examples We provide an online example based on Rsbuild. The example gives an intuitive feel for the build performance of Rspack and the development experience of Rsbuild: * [Rsbuild CodeSandbox example](https://codesandbox.io/p/github/rspack-contrib/rsbuild-codesandbox-example) ## 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: Update your build scripts to use Rspack CLI: ```js title="package.json" { "scripts": { "dev": "rspack dev", "build": "rspack build" } } ``` 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 stack, you can refer to the following guides: * [Migrating from webpack to Rspack](/guide/migration/webpack.md) * [Migrating from webpack to Rsbuild](https://rsbuild.dev/guide/migration/webpack) * [Migrating from Create React App to Rsbuild](https://rsbuild.dev/guide/migration/cra) * [Migrating from Vue CLI to Rsbuild](https://rsbuild.dev/guide/migration/vue-cli) * [Migrating from Vite to Rsbuild](https://rsbuild.dev/guide/migration/vite) * [Migrating from Tsup to Rslib](https://lib.rsbuild.dev/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/rspack-contrib/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 --- # Ecosystem ## Rstack toolchain Rstack is a high-performance, unified JavaScript toolchain based on Rspack, developed and maintained by the Rspack team. ### 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. ### 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. ### 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. ### Rsdoctor Build analyzer [Rsdoctor](https://github.com/web-infra-dev/rsdoctor) 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](https://github.com/web-infra-dev/rstest) 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. ## Community integrations ### Angular Rspack Build tool Angular [Angular Rspack](https://github.com/nrwl/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/en/) 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. ### 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/tech/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. ### Storybook UI development [Storybook Rsbuild](https://storybook.rsbuild.dev/) allows you to use Rsbuild as the build tool for Storybook, and provides UI framework integrations like React and Vue. ## More Visit [awesome-rspack](https://github.com/web-infra-dev/awesome-rspack) to discover more projects within the Rspack ecosystem. --- url: /guide/features/plugin.md --- # 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-contrib/webpack-bundle-analyzer) in Rspack configuration: ```js title="rspack.config.mjs" import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; export default { plugins: [ new BundleAnalyzerPlugin({ // options }), ], }; ``` ```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 [Plugin compat](/guide/compatibility/plugin.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): ```js title="rspack.config.mjs" import Components from 'unplugin-vue-components/rspack'; export default { plugins: [ Components({ // options }), ], }; ``` ```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.dev) 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.dev/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). ```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!'); }); } } ``` ```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!'); }); } } ``` --- url: /guide/features/loader.md --- # Loader In bundling terminology, a loader is like a plugin but tasked with transforming file contents. You can use loaders to transform arbitrary input files into file types that are natively supported by Rspack. :::tip A loader performs pre-processing of resources, whereas a configuration [Rule.type](/config/module.md#ruletype) describes post-processing of resources whose type is natively supported by Rspack. ::: Rspack has supported most community loaders. If you find an unsupported loader, please feel free to communicate with us through [GitHub Issues](https://github.com/web-infra-dev/rspack/issues). ## Developing a loader Refer to [Loader API - Examples](/api/loader-api/examples.md) to learn how to develop a loader. ## Example ### Using Less CSS is a first-class citizen of Rspack, so processing of CSS files is natively supported. For `Less` files, you need to use an external [less-loader](https://github.com/webpack-contrib/less-loader) to transform the contents of the 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-contrib/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.md#rule) match, with the loaders executed in right-to-left order. For example, you can use [less-loader](https://github.com/webpack-contrib/less-loader) to do the transformation between Less to CSS types and [postcss-loader](https://github.com/webpack-contrib/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 [Rule.use](/config/module.md#ruleuse) 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/dev-server.md --- # Dev server Rspack CLI comes with a built-in `@rspack/dev-server` for development and debugging. Its capabilities are similar to `webpack-dev-server`, including features like hot module replacement (HMR), proxy server and more. :::tip `webpack-dev-server@5` is used in `@rspack/dev-server`, which has some differences from `webpack-dev-server@4`. * The minimum supported Node.js version for webpack-dev-server v5 is 18.12.0. * Several configuration options have changed. Please refer to the [webpack-dev-server v5 migration guide](https://github.com/webpack/webpack-dev-server/blob/master/migration-v5.md). ::: ### 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 Rspack has a built-in simple proxy server. You can enable the proxy server by configuring the `devServer.proxy` option in Rspack configuration. The devServer internally uses [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) to implement the proxy function. 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 --- # Asset modules Assets (e.g. images, fonts, videos, etc.) are first-class citizens of Rspack, 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. ## 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.md#moduleparserasset) to modify the global configuration, or use [`Rule.parser. dataUrlCondition`](/config/module.md#ruleparserdataurlcondition) 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-contrib/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 --- # 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 `__webpack_public_path__` in your JavaScript code. The `__webpack_public_path__` 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/rspack-contrib/rstack-examples/tree/main/rspack/vue). ## Vue 2 Rspack has completed compatibility with Vue2 (using vue-loader@15). Please make sure to turn off `experiments.css` when configuring Vue2 projects or use `Rule.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: /\.ts$/, // add this rule when you use TypeScript in Vue SFC loader: 'builtin:swc-loader', options: { jsc: { parser: { syntax: 'typescript', }, }, }, type: 'javascript/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/rspack-contrib/rstack-examples/tree/main/rspack/vue2) and [example-vue2-ts](https://github.com/rspack-contrib/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): ### 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/rspack-contrib/rstack-examples/tree/main/rspack/vue3-jsx) of Vue JSX for reference. --- url: /guide/tech/next.md --- # 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: :::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.js` or `next.config.ts`: ```ts import withRspack from 'next-rspack'; import type { NextConfig } from 'next'; const nextConfig: NextConfig = { /* config options here */ }; export default withRspack(nextConfig); ``` ```ts const withRspack = require('next-rspack'); /** @type {import('next').NextConfig} */ const nextConfig = { /* config options here */ }; module.exports = 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.js`, modify Rspack's configuration by adding the following callback function: ```js title="next.config.js" module.exports = { 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.js" const withPlugins = require('next-compose-plugins'); const withRspack = require('next-rspack'); module.exports = withPlugins([ [withRspack], // your other plugins here ]); ``` --- url: /guide/tech/nestjs.md --- # NestJS Rspack not only supports building frontend projects but also supports building Node.js App like NestJS. Rspack provides NestJS [example](https://github.com/rspack-contrib/rstack-examples/tree/main/rspack/nestjs) for reference. ## 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, special handling is usually required. node-loader can be used to handle addon packaging very well. ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.node$/, use: [ { loader: 'node-loader', options: { name: '[path][name].[ext]', }, }, ], }, ], }, }; ``` --- url: /guide/tech/solid.md --- # 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.dev/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/rspack-contrib/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/tech/svelte.md --- # 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.dev/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/rspack-contrib/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/optimization/analysis.md --- # Bundle analysis ## webpack-bundle-analyzer Rspack's Command Line Interface (CLI) supports bundle analysis out-of-box via the `--analyze` option. It uses [webpack-bundle-analyzer](https://www.npmjs.com/package/webpack-bundle-analyzer) behind the scenes. ```sh $ rspack build --analyze ``` ## 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://statoscope.tech/): ```sh $ rspack build --json stats.json ``` ## Rsdoctor's bundle analysis Rsdoctor 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**. 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.dev/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.dev) 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.dev/others/assets/rsdoctor/overall-alerts.jpg) For more details, see [Rsdoctor - Duplicate Dependency Problem](https://rsdoctor.dev/blog/topic/duplicate-pkg-problem). --- url: /guide/optimization/code-splitting.md --- # 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. Here we introduce a concept called Chunk, representing a resource that a browser needs to load. ## Dynamic import Rspack use 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()`, thereby separating 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'); ``` Now we build this project, we get 3 chunks, `src_bar_js.js`, `src_foo_js.js` and `main.js`, if you see them, you will find `shared.js` exist in both `src_bar_js.js` and `src_foo_js.js`, we will remove duplicated modules in later chapters. :::tip 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. ::: :::info Though `shared.js` exist in 2 chunks, but it is executed only once, you don't have to worry about issue of multiple instance. ::: ## Entry point This is the simplest and most intuitive way to split the code. However, this approach requires us to manually configure the Rspack. Let's start by looking at how to split 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, if you examine them, you will find that they all include the repetitive `shared.js`. ## SplitChunksPlugin The code segmentation mentioned above is quite intuitive, but most modern browsers support concurrent network requests. If we divide each page of a SPA application into a single Chunk, and when users switch pages, they request a larger Chunk, this obviously does not make good use of the browser's ability to handle concurrent network requests. Therefore, we can break down the Chunk into smaller ones. When we need to request this Chunk, we change to request these smaller Chunks simultaneously, which will make the browser's requests more efficient. 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. So why does `shared.js` still appear repeatedly in multiple Chunks in our example above? This is because the `shared.js` in our example is very small in size. If a very small module is split into a separate Chunk for the browser to load, it might actually slow down the loading process. We can configure the minimum split size 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, + } + } }; ``` When rebuild, you will find that `shared.js` has been extracted separately, and there is an additional Chunk in the product that contains `shared.js`. ### Force the splitting of certain modules We can specify certain modules to be forcibly grouped into a single Chunk, for example, 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. Here is an example show the effect of the `name` configuration of cacheGroup. ![](https://assets.rspack.dev/rspack/assets/rspack-splitchunks-name-explain.png) ## Prefetching/Preloading modules Using these inline directives while declaring your imports allows Rspack to output “Resource Hint” which tells the browser that for: * **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. --- url: /guide/optimization/production.md --- # Production ## Source mapping It is recommended to enable SourceMap for production environments to facilitate debugging in production environments. If you have a large project, it is recommended that you choose a configuration with better performance (see [devtool](/config/devtool.md) for more options), such as the `source-map` configuration option. ## Minification During the production build, Rspack uses the built-in minimizer to minify JavaScript and CSS code by default. You can use [SwcJsMinimizerRspackPlugin](/plugins/rspack/swc-js-minimizer-rspack-plugin.md) and [LightningCssMinimizerRspackPlugin](/plugins/rspack/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/profile.md --- # Build performance profile This chapter introduces some common performance bottlenecks and performance profile methods for Rspack. ## Analysis with Rsdoctor [Rsdoctor](https://rsdoctor.dev/) 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/optimization/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 in the current folder, and it will contain `trace.json`: * `trace.json`: The time spent on each phase of the Rust side is recorded at a granular level using [tracing](https://github.com/tokio-rs/tracing) and can be viewed using [ui.perfetto.dev](https://ui.perfetto.dev/) ## 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 [Rule.include](/config/module.md#ruleinclude) 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). If your project uses the PostCSS plugin for Tailwind CSS v3, you may need to wait for the release of Tailwind CSS v4, which is based on Rust and Lightning CSS and will provide significant performance improvements. For more details, see [Open-sourcing our progress on Tailwind CSS v4.0](https://tailwindcss.com/blog/tailwindcss-v4-alpha). ### terser-webpack-plugin [terser-webpack-plugin](https://github.com/webpack-contrib/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/rspack/swc-js-minimizer-rspack-plugin.md). ### css-minimizer-webpack-plugin [css-minimizer-webpack-plugin](https://github.com/webpack-contrib/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/rspack/lightning-css-minimizer-rspack-plugin.md). ### less-loader [less-loader](https://github.com/webpack-contrib/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-contrib/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/rspack/html-rspack-plugin.md) implemented in Rust by Rspack can provide better performance. --- url: /guide/optimization/tree-shaking.md --- # 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." Dead code arises when certain exports from a module are not used and they lack side effects, allowing such pieces to be safely deleted to reduce the final output size. Upon setting the `mode` to `production`, Rspack by default enables a series of optimizations related to tree shaking, including: * [usedExports](/config/optimization.md#optimizationusedexports): Checks whether module exports are utilized, allowing the removal of unused exports. * [sideEffects](/config/optimization.md#optimizationsideeffects): Assesses modules for side effects. Modules without side effects can be optimized further via re-exports. * [providedExports](/config/optimization.md#optimizationprovidedExports): Analyzes all exports and their sources of re-exportation. * [innerGraph](/config/optimization.md#optimizationsinnergraph): Tracks the transmission of variables, enhancing the accuracy of determining whether exports are indeed used. Below are examples to illustrate how these configuration options function. :::info Note that Rspack does not directly remove dead code but labels unused exports as potential "dead code." These labels can then be recognized and processed by subsequent compression tools. As such, if compression features are turned off, no actual code removal will be observable. For enhanced readability, pseudocode might be used to demonstrate the effects of code removal. ::: Let's understand this mechanism better through an example, assuming `src/main.js` as the project's 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 defaults to enabling the [usedExports](/config/optimization.md#optimizationusedexports) optimization, detecting which exports are actively used. Unused exports, like `bar`, are safely removed. The final output would resemble: ```js title='dist/main.js' const foo = 1; console.log(foo); ``` ## Side effects analysis In `production` mode, Rspack also typically analyzes modules for the presence of side effects. If all exports from a module are unused and the module is devoid of side effects, then the entire module can be deleted. Let's modify the previous example a bit: ```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 may manually indicate whether a module retains side effects through `package.json` or `module.rules`. For information on how to do so, please consult [sideEffects](/config/optimization.md#optimizationsideeffects). ## Re-export analysis Re-exports are common in development. However, a module might pull in numerous other modules while typically only a fraction of those are needed. Rspack optimizes this situation by ensuring that the referring party can access the actual exported modules directly. Consider this example involving re-exports: ```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 defaults to enable [providedExports](/config/optimization.md#optimizationprovidedexports), which can analyze all exports from a re-exporting module and identify their respective origins. If `src/re-exports.js` contains no side effects, Rspack can convert the import in `src/main.js` from `src/re-exports.js` directly into imports from `src/value.js`, effectively: ```diff title='src/main.js' - import { value } from './re-exports.js'; + import { value } from './value.js'; console.log(value); ``` This approach benefits by entirely ignoring the `src/re-exports.js` module. With an ability to analyze all re-exports in `src/re-exports.js`, it is determined that `foo` from `src/value.js` is not used and will be removed in the final output. ## Variable transmission In some cases, even though exports are accessed, they might not actually be 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 the scenario above, even though the `log` function and the variable `bar` depend on `foo`, since neither is used, `foo` can still be considered dead code and be deleted. After enabling [innerGraph](/config/optimization.md#optimizationinnergraph) optimization (enabled by default for `production` mode), for complex cross-module situations, Rspack maintains the ability to track variable usage, thereby achieving 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; ``` In this context, because `value` is eventually used, the `foo` it depends on is retained. --- url: /guide/optimization/use-rsdoctor.md --- # Use Rsdoctor [Rsdoctor](https://rsdoctor.dev/) 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: 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.dev/). ## Configure Rsdoctor See the [Options](https://rsdoctor.dev/config/options/options) documentation of Rsdoctor to configure the options of the RsdoctorRspackPlugin. ## More features See the [Rsdoctor features](https://rsdoctor.dev/guide/start/features) to learn about all the features of Rsdoctor. --- url: /guide/migration/webpack.md --- # Migrate from webpack Rspack's configuration is designed based on webpack, enabling you to migrate your project from webpack to Rspack with ease. This document is primarily aimed at projects using webpack 5. Since Rspack's API and configuration align with webpack 5. For projects not using webpack 5, there are other migration guides that can be referenced: * For projects using webpack v4 or earlier versions, you can refer to [webpack - To v5 from v4](https://webpack.js.org/migrate/5/) to understand the differences. * For projects using create-react-app or CRACO, you can refer to [Migrating Create React App](/guide/migration/cra.md). * For projects using Vue CLI, you can refer to [Rsbuild - Migrating from Vue CLI](https://rsbuild.dev/guide/migration/vue-cli). ## Installing Rspack In your project directory, install Rspack as a `devDependencies`: Now you can remove the webpack-related dependencies from your project: :::tip In some cases, you will still need to keep `webpack` as a dev dependency, such as when using [vue-loader](https://github.com/vuejs/vue-loader). This is because these packages directly `import` subpaths of webpack and couple with webpack. If you encounter this issue, you can provide feedback to the maintainers of these plugins, asking them if they can make `webpack` an optional dependency. ::: ## Updating package.json Update your build scripts to use Rspack instead of webpack: ```diff title="package.json" { "scripts": { - "serve": "webpack serve", - "build": "webpack build", + "serve": "rspack serve", + "build": "rspack build", } } ``` ## Updating configuration Rename the `webpack.config.js` file to `rspack.config.js`. :::tip Rspack commands can specify the configuration file with `-c` or `--config`, similar to webpack commands. However, unlike webpack, if a configuration file is not explicitly specified, Rspack defaults to using `rspack.config.js`. ::: Rspack does not currently support all webpack configurations, and some configurations might affect the build output. To ensure the correctness of the build output, Rspack enables strict validation of the configurations by default. However, Rspack also provides a loose mode for easy progressive migration. You can enable it by setting the `RSPACK_CONFIG_VALIDATE` environment variable: ```bash # Enable loose validation mode will print out erroneous configurations but will not throw error. RSPACK_CONFIG_VALIDATE=loose rspack build # Enable loose validation mode, without printing errors or throwing error. RSPACK_CONFIG_VALIDATE=loose-silent rspack build ``` Rspack is actively working on implementing webpack's upcoming features, so some configuration defaults differ from webpack 5, as shown below: | Configuration | webpack Default | Rspack Default | | ----------------- | --------------- | -------------- | | node.global | true | 'warn' | | node.\_\_filename | 'mock' | 'warn-mock' | | node.\_\_dirname | 'mock' | 'warn-mock' | You can refer to [Configure Rspack](/config/index.md) to see the configurations supported by Rspack. ## Webpack built-in plugins Rspack has implemented most of webpack's built-in plugins, with the same names and configuration parameters, allowing for easy replacement. For example, replacing the [DefinePlugin](/plugins/webpack/define-plugin.md): ```diff title="rspack.config.js" - const webpack = require('webpack'); + const { rspack } = require('@rspack/core'); module.exports = { //... plugins: [ - new webpack.DefinePlugin({ + new rspack.DefinePlugin({ // ... }), ], } ``` See [Webpack-aligned built-in plugins](/plugins/webpack/index.md) for more information about supported webpack plugins in Rspack. ## Community plugins Rspack supports most of the webpack community plugins and also offers alternative solutions for some currently unsupported plugins. Check [Plugin compat](/guide/compatibility/plugin.md) for more information on Rspack's compatibility with popular webpack community plugins. ### `copy-webpack-plugin` Use [rspack.CopyRspackPlugin](/plugins/rspack/copy-rspack-plugin.md) instead of [copy-webpack-plugin](https://github.com/webpack-contrib/copy-webpack-plugin): ```diff title="rspack.config.js" - const CopyWebpackPlugin = require('copy-webpack-plugin'); + const { rspack } = require('@rspack/core'); module.exports = { plugins: [ - new CopyWebpackPlugin({ + new rspack.CopyRspackPlugin({ // ... }), ] } ``` ### `mini-css-extract-plugin` Use [rspack.CssExtractRspackPlugin](/plugins/rspack/css-extract-rspack-plugin.md) instead of [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin): ```diff title="rspack.config.js" - const CssExtractWebpackPlugin = require('mini-css-extract-plugin'); + const { rspack } = require('@rspack/core'); module.exports = { plugins: [ - new CssExtractWebpackPlugin({ + new rspack.CssExtractRspackPlugin({ // ... }), ] module: { rules: [ { test: /\.css$/i, use: [ - CssExtractWebpackPlugin.loader, + rspack.CssExtractRspackPlugin.loader, "css-loader" ], + type: 'javascript/auto' } ] } } ``` ### `tsconfig-paths-webpack-plugin` Use [resolve.tsConfig](/config/resolve.md#resolvetsconfig) instead of [tsconfig-paths-webpack-plugin](https://github.com/dividab/tsconfig-paths-webpack-plugin): ```diff title="rspack.config.js" - const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); module.exports = { resolve: { - plugins: [new TsconfigPathsPlugin({})] + tsConfig: {} } } ``` ### `fork-ts-checker-webpack-plugin` Use [ts-checker-rspack-plugin](https://github.com/rspack-contrib/ts-checker-rspack-plugin) instead of [fork-ts-checker-webpack-plugin](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin): ```diff title="rspack.config.js" - const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); + const { TsCheckerRspackPlugin } = require('ts-checker-rspack-plugin'); module.exports = { plugins: [ - new ForkTsCheckerWebpackPlugin() + new TsCheckerRspackPlugin() ] } ``` ## Loaders Rspack's loader runner is fully compatible with webpack's loader functionality, supporting the vast majority of webpack loaders. You can use your existing loaders without any changes. However, to achieve the best performance, consider migrating the following loaders: ### [babel-loader](https://github.com/babel/babel-loader) / [swc-loader](https://swc.rs/docs/usage/swc-loader) → builtin:swc-loader Using `builtin:swc-loader` offers better performance compared to the `babel-loader` and the external `swc-loader`, as it avoids frequent communication between JavaScript and Rust. If you need custom transformation logic using Babel plugins, you can retain `babel-loader`, but it is recommended to limit its use to fewer files to prevent significant performance degradation. ```diff title="rspack.config.js" module.exports = { module: { rules: [ - { - test: /\.tsx?$/i, - use: [ - { - loader: 'babel-loader', - options: { - presets: ['@babel/preset-typescript'], - }, - }, - ], - test: /\.jsx?$/i, - use: [ - { - loader: 'babel-loader', - options: { - presets: ['@babel/preset-react'], - }, - }, - ], - }, + { + test: /\.(j|t)s$/, + exclude: [/[\\/]node_modules[\\/]/], + loader: 'builtin:swc-loader', + options: { + jsc: { + parser: { + syntax: 'typescript', + }, + externalHelpers: true, + transform: { + react: { + runtime: 'automatic', + development: !prod, + refresh: !prod, + }, + }, + }, + env: { + targets: 'Chrome >= 48', + }, + }, + }, + { + test: /\.(j|t)sx$/, + loader: 'builtin:swc-loader', + exclude: [/[\\/]node_modules[\\/]/], + options: { + jsc: { + parser: { + syntax: 'typescript', + tsx: true, + }, + transform: { + react: { + runtime: 'automatic', + development: !prod, + refresh: !prod, + }, + }, + externalHelpers: true, + }, + env: { + targets: 'Chrome >= 48', // browser compatibility + }, + }, + }, ], }, }; ``` ### [file-loader](https://github.com/webpack-contrib/raw-loader) / [url-loader](https://github.com/webpack-contrib/url-loader) / [raw-loader](https://github.com/webpack-contrib/raw-loader) → [Asset Modules](/guide/features/asset-module.md) Rspack implements webpack 5's [Asset Modules](https://webpack.js.org/guides/asset-modules), using asset modules to replace `file-loader`, `url-loader`, and `raw-loader` for better performance. #### file-loader → asset/resource ```diff title="rspack.config.js" module.exports = { module: { rules: [ - { - test: /\.(png|jpe?g|gif)$/i, - use: ["file-loader"], - }, + { + test: /\.(png|jpe?g|gif)$/i, + type: "asset/resource", + }, ], }, }; ``` #### url-loader → asset/inline ```diff title="rspack.config.js" module.exports = { module: { rules: [ - { - test: /\.(png|jpe?g|gif)$/i, - use: ["url-loader"], - }, + { + test: /\.(png|jpe?g|gif)$/i, + type: "asset/inline", + }, ], }, }; ``` #### raw-loader → asset/source ```diff title="rspack.config.js" module.exports = { module: { rules: [ - { - test: /^BUILD_ID$/, - use: ["raw-loader",], - }, + { + test: /^BUILD_ID$/, + type: "asset/source", + }, ], }, }; ``` --- url: /guide/migration/cra.md --- # Migrate from Create React App Since Create React App (CRA) comes with rich built-in capabilities, it would be challenging to manually set up an equivalent configuration using Rspack CLI. Therefore, we recommend migrating your CRA application to [Rsbuild](https://rsbuild.dev/) to leverage Rspack's capabilities out of the box. ## What is Rsbuild 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. Rsbuild provides rich build features, including the compilation of TypeScript, JSX, Sass, Less, CSS Modules, Wasm, and others. It also supports Module Federation, image compression, type checking, PostCSS, Lightning CSS, and more. ![build tools](https://assets.rspack.dev/rsbuild/assets/rsbuild-1-0-build-tools.png) ## How to migrate Rsbuild provides a comprehensive migration guide to help you migrate from Create React App. Please refer to the [Migration guide](https://rsbuild.dev/guide/migration/cra) for details. --- url: /guide/migration/storybook.md --- # Migrate from Storybook webpack If you are using React / Vue with [Storybook](https://storybook.js.org/) and building with webpack 5, you can replace the `@storybook/react-webpack5` build with [storybook-rsbuild](https://github.com/rspack-contrib/storybook-rsbuild), which is implemented based on Rsbuild and uses Rspack as the underlying bundler. It supports out-of-the-box use, and the documentation can be found at [storybook-rsbuild](https://github.com/rspack-contrib/storybook-rsbuild). Next, we will take React as an example to introduce how to migrate a Storybook webpack 5 project. The migration steps for Vue projects are similar to React. :::info Storybook Rsbuild requires at least version 8.0 of Storybook. It's highly recommended to upgrade Storybook to the latest version, check Storybook 8's [release note](https://storybook.js.org/blog/storybook-8/) for detail changes and migration guide. ::: ## Update dependencies First, replace `@storybook/react-webpack5` with [`storybook-react-rsbuild`](https://www.npmjs.com/package/storybook-react-rsbuild) (for Vue projects, use [`storybook-vue3-rsbuild`](https://www.npmjs.com/package/storybook-vue3-rsbuild)), add `@rsbuild/core` and `@rsbuild/plugin-react` (for Vue projects, use `@rsbuild/plugin-vue`). ## Configure Rsbuild Storybook Rsbuild will automatically load the Rsbuild configuration file from the working directory. Install [`@rsbuild/plugin-react`](https://rsbuild.dev/guide/framework/react) (for Vue projects, install and use [`@rsbuild/plugin-vue`](https://rsbuild.dev/guide/framework/vue#vue-3)). ```js import { defineConfig } from '@rsbuild/core'; import { pluginReact } from '@rsbuild/plugin-react'; export default defineConfig({ plugins: [pluginReact()], }); ``` ## Update Storybook configuration Refer to the following configuration to modify the `main.js` configuration of Storybook, and specify `'storybook-react-rsbuild'` as the Storybook framework (for Vue projects, use `'storybook-vue3-rsbuild'`). ```diff title=.storybook/main.js export default { - framework: '@storybook/react-webpack5' + framework: 'storybook-react-rsbuild', }, ``` ## Examples The [rspack-contrib/storybook-rsbuild](https://github.com/rspack-contrib/storybook-rsbuild/tree/main/sandboxes) repository provides examples of Storybook for React / Vue projects. ## Limitations Rspack is gradually improving full support for Storybook. Currently, there are some capabilities that are not supported, see [storybook-rsbuild - Roadmap](https://github.com/rspack-contrib/storybook-rsbuild#roadmap) for details. --- url: /guide/migration/rspack_0.x.md --- # Migrating from Rspack 0.x The document lists all breaking changes from Rspack v0.7 to v1.0. You can refer to this document for migration. > See [Breaking changes in Rspack v1.0.0](https://github.com/web-infra-dev/rspack/discussions/6626) for details. ## Configuration default value adjustments In Rspack 1.x, we have aligned the default configuration values with those of Webpack. ### \[Important] experiments.css The default value of [experiments.css](/config/experiments.md#experimentscss) has been changed from `true` to `false`. In Rspack 0.x, `experiments.css` was enabled by default, which means files ending with`*.css`were automatically treated as`type: 'css/auto'` without needing to manually include other loaders to process CSS files. If you rely on the built-in feature to handle CSS files without using any loaders, or if you have used the following configuration to handle CSS files: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.less$/, type: 'css/auto', // 👈 use: ['less-loader'], }, ], }, }; ``` Please note that you now need to manually enable `experiments.css`. ### \[Important] optimization.concatenateModules The default value of [optimization.concatenateModules](/config/optimization.md#optimizationconcatenatemodules) has been changed from `false` to: * `true` when `mode` is `'production'`. * `false` for other values of `mode`. In Rspack 1.x, module concatenation optimization has become more stable. Thus, it's now enabled by default in production mode, allowing multiple modules to be concatenated into a single module to reduce output size and improve compression efficiency. ### devtool The default value of [devtool](/config/devtool.md) has been changed from `false` to: * `eval` when `mode` is `'development'`. * `false` for other values of `mode`. > `@rspack/cli` overrides the default `devtool` value from `@rspack/core`. Therefore, if you are using `@rspack/cli`, this change will not affect you. ### experiments.asyncWebAssembly The default value of [experiments.asyncWebAssembly](/config/experiments.md#experimentsasyncwebassembly) has been changed from `false` to depend on the `experiments.futureDefaults` configuration. It is enabled by default only when `experiments.futureDefaults` is set to `true`. If you are using WebAssembly modules as asynchronous modules, you now need to manually set `experiments.asyncWebAssembly` to `true`. ### splitChunks.cacheGroups.\{cacheGroup}.reuseExistingChunk The default value of [splitChunks.cacheGroups.\{cacheGroup}.reuseExistingChunk](/plugins/webpack/split-chunks-plugin.md#splitchunkscachegroupscachegroupreuseexistingchunk) has been changed from `true` to `false`. ### optimization.moduleIds The default value of [optimization.moduleIds](/config/optimization.md#optimizationmoduleids) has been changed to `'natural'` when `mode` is `none`. ### optimization.chunkIds The default value of [optimization.chunkIds](/config/optimization.md#optimizationchunkids) has been changed to `'natural'` when `mode` is `none`. ## Removed configurations ### \[Important] Removed resolve.tsConfigPath Please use [resolve.tsConfig](/config/resolve.md#resolvetsconfig) instead. ```diff export default { resolve: { - tsConfigPath: path.resolve(__dirname, './tsconfig.json'), + tsConfig: path.resolve(__dirname, './tsconfig.json'), }, }; ``` ### output.amdContainer Please use [output.library.amdContainer](/config/output.md#outputlibraryamdcontainer) instead. ## Adjustments to builtin:swc-loader To streamline the core, Rspack 1.x has removed the built-in SWC plugins. You now need to manually include them. ### \[Important] Removed rspackExperiments.styledComponents Use [@swc/plugin-styled-components](https://www.npmjs.com/package/@swc/plugin-styled-components) instead. ```diff export default { module: { rules: [ { test: /\.jsx$/, loader: "builtin:swc-loader", options: { - rspackExperiments: { - styledComponents: true, - }, jsc: { + experimental: { + plugins: [["@swc/plugin-styled-components", {}]], + }, }, }, }, ], }, }; ``` ### \[Important] Removed rspackExperiments.emotion Use [@swc/plugin-emotion](https://www.npmjs.com/package/@swc/plugin-emotion) instead. ```diff export default { module: { rules: [ { test: /\.jsx$/, loader: "builtin:swc-loader", options: { - rspackExperiments: { - emotion: true, - }, jsc: { + experimental: { + plugins: [["@swc/plugin-emotion", {}]], + }, }, }, }, ], }, }; ``` ### \[Important] Removed rspackExperiments.relay Use [@swc/plugin-relay](https://www.npmjs.com/package/@swc/plugin-relay) instead. ```diff export default { module: { rules: [ { test: /\.jsx$/, loader: "builtin:swc-loader", options: { - rspackExperiments: { - relay: true, - }, jsc: { + experimental: { + plugins: [["@swc/plugin-relay", {}]], + }, }, }, }, ], }, }; ``` ### \[Important] Removed rspackExperiments.preact Use [@swc/plugin-prefresh](https://www.npmjs.com/package/@swc/plugin-prefresh) instead. ```diff export default { module: { rules: [ { test: /\.jsx$/, loader: "builtin:swc-loader", options: { - rspackExperiments: { - preact: true, - }, jsc: { + experimental: { + plugins: [["@swc/plugin-prefresh", {}]], + }, }, }, }, ], }, }; ``` ## Adjustments to built-in plugins ### \[Important] CSS minimizer plugin adjustment In Rspack 0.x, we used the built-in `rspack.SwcCssMinimizerRspackPlugin` to compress CSS size. Now, we have removed it and replaced it with [rspack.LightningCssMinimizerRspackPlugin](/plugins/rspack/lightning-css-minimizer-rspack-plugin.md) to handle the same functionality. If you previously manually registered and configured `rspack.SwcCssMinimizerRspackPlugin`, you should to switch to `rspack.LightningCssMinimizerRspackPlugin`: ```diff import { rspack } from '@rspack/core'; export default { optimization: { minimizer: [ - new rspack.SwcCssMinimizerRspackPlugin({ + new rspack.LightningCssMinimizerRspackPlugin({ // options }), ], }, }; ``` ### rspack.SwcJsMinimizerRspackPlugin Rspack's built-in and default-enabled JavaScript minimizer plugin has had its configuration aligned with [SWC's minification configuration](https://swc.rs/docs/configuration/minification). The breaking changes are as follows: * `minimizerOptions.passes`: moved to `minimizerOptions.compress.passes` * `minimizerOptions.dropConsole`: moved to `minimizerOptions.compress.drop_console` * `minimizerOptions.pureFuncs`: moved to `minimizerOptions.compress.pure_funcs` * `minimizerOptions.keepClassNames`: moved to `minimizerOptions.mangle.keep_classnames` * `minimizerOptions.keepFnNames`: moved to `minimizerOptions.mangle.keep_fnames` * `minimizerOptions.comments`: moved to `minimizerOptions.format.comments` * `minimizerOptions.asciiOnly`: moved to `minimizerOptions.format.ascii_only` Default value changes: * `comments` (`options.format.comments`): changed from `false` to `"some"` ### rspack.HtmlRspackPlugin We have aligned its configuration with [html-webpack-plugin](https://www.npmjs.com/package/html-webpack-plugin), with the following breaking changes: * `excludedChunks` has been renamed to `excludeChunks` * When `mode` is `'production'`, `minify` is now `true` by default ## Other changes ### \[Important] @rspack/cli `@rspack/cli` has upgraded its dependency on `webpack-dev-server` from v4 to v5. If you are using `@rspack/cli`, please be aware of the following breaking changes: * The minimum supported Node.js version for webpack-dev-server v5 is 18.12.0. * Several configuration options have changed. Please refer to the [webpack-dev-server v5 migration guide](https://github.com/webpack/webpack-dev-server/blob/master/migration-v5.md). ### \[Important] `ResolverFactory` and `Resolver` refactoring with Rust `ResolverFactory` and `Resolver` have been refactored with Rust to unify the implementations on the JS and Rust sides. Due to this change, `ResolverFactory` and `Resolver` currently do not support any hooks. Additionally, `Resolver` now only supports the following methods: * `resolveSync` * `resolve` * `withOptions` This change might cause some plugins to become unusable. :::tip Rspack supports the [NormalModuleFactory](/api/plugin-api/normal-module-factory-hooks.md)'s [resolve](/api/plugin-api/normal-module-factory-hooks.md#resolve) hook. In most cases, you can use this hook as a replacement for the `Resolver`'s `resolve` hook to achieve the same functionality. ```js compiler.hooks.normalModuleFactory.tap('PLUGIN', normalModuleFactory => { normalModuleFactory.hooks.resolve.tap('PLUGIN', data => { // Redirect the module if (data.request === './foo.js') { data.request = './bar.js'; } }); }); ``` ::: --- url: /guide/compatibility/plugin.md --- # Plugin compatibility This index lists the compatibility status of some commonly community plugins in Rspack. The support status of Rspack for the built-in plugins in webpack can be refer to [Webpack-aligned built-in plugins](/plugins/webpack/index.md). Note that the table only lists some common community plugins. For plugins that are not mentioned, you can verify their functionality on your own. Feel free to add more plugins to the current document. You can view examples of common plugins at [rstack-examples](https://github.com/rspack-contrib/rstack-examples). Additionally, you can check out the community Rspack plugins at [awesome-rspack](https://github.com/web-infra-dev/awesome-rspack). --- url: /config/index.md --- # Configure Rspack Rspack provides configurations similar to webpack. This chapter will show you how to use the Rspack configuration. ## Configuration file When you run the Rspack CLI, Rspack automatically reads the `rspack.config.*` file in the current working directory. A basic Rspack configuration file looks like this: ```js title="rspack.config.mjs" import { defineConfig } from '@rspack/cli'; export default defineConfig({ entry: { main: './src/index.js', }, }); ``` ```js title="rspack.config.cjs" const { defineConfig } = require('@rspack/cli'); module.exports = defineConfig({ entry: { main: './src/index.js', }, }); ``` ```ts title="rspack.config.ts" import { defineConfig } from '@rspack/cli'; export default defineConfig({ entry: { main: './src/index.js', }, }); ``` ## Configuration file formats Rspack supports these configuration file formats: * `rspack.config.js`: defaults to `CommonJS` format, or `ES modules` format if the type of the package.json is "module". * `rspack.config.ts`: `TypeScript` format, see [TypeScript configuration file](#typescript-configuration-file) for more details. * `rspack.config.cjs`: Forced to `CommonJS` format. * `rspack.config.mjs`: Forced to `ES modules` format. Note that Rspack will first search JS configuration file and then TS configuration file. > See [ES modules](https://nodejs.org/api/esm.html#modules-ecmascript-modules) and [CommonJS](https://nodejs.org/api/modules.html) for the difference between `CommonJS` and `ES modules`. ## Extending configurations See [Extending Configurations](/en/config/extends.md) for details on how to extend configurations from other files or packages. ## TypeScript configuration file When using `rspack.config.ts`, you need to use a runtime that supports TypeScript, or install additional dependencies to resolve TypeScript files. You can choose one of the following: ### Native support If your JavaScript runtime already natively supports TypeScript, you can use the built-in TS transformation to load the configuration file without needing to install additional dependencies. For example, Node.js already natively supports TypeScript, you can use the following command to use the Node.js native loader to load the configuration file: * For Node.js v22.7.0 to v23.5.0, you need to enable the `--experimental-transform-types` flag: ```json title="package.json" { "scripts": { "build": "NODE_OPTIONS='--experimental-transform-types' rspack build" } } ``` * For Node.js v23.6.0+, the `--experimental-transform-types` flag is no longer required: ```json title="package.json" { "scripts": { "build": "rspack build" } } ``` See [Node.js - Running TypeScript Natively](https://nodejs.org/en/learn/typescript/run-natively#running-typescript-natively) for more details. ### Using esbuild For lower Node.js versions, you can use `esbuild-register` to load the configuration file. Install [esbuild](https://npmjs.com/package/esbuild) and [esbuild-register](https://npmjs.com/package/esbuild-register), no additional configuration is needed. ### Using ts-node You can also use [ts-node](https://npmjs.com/package/ts-node) to load the configuration file. 1. Install `ts-node`: 2) Then configure `ts-node` to use `CommonJS` modules in `tsconfig.json`: ```json title="tsconfig.json" { "ts-node": { "compilerOptions": { "module": "CommonJS" } } } ``` ## Type checking Use the `defineConfig` helper to enable auto-completion. For JavaScript configuration files, you can use the `// @ts-check` comment to enable type checking. ```ts title="rspack.config.ts" import { defineConfig } from '@rspack/cli'; export default defineConfig({ entry: { main: './src/index.js', }, }); ``` ```js title="rspack.config.mjs" // @ts-check import { defineConfig } from '@rspack/cli'; export default defineConfig({ entry: { main: './src/index.js', }, }); ``` Alternatively, you can use [JSDoc](https://jsdoc.app/) for type checking. ```js title="rspack.config.mjs" // @ts-check /** @type {import('@rspack/cli').Configuration} */ const config = { entry: { main: './src/index.js', }, }; export default config; ``` ## Specify the configuration file Specify the name of the configuration file using the `--config` option. For example, if you need to use the `rspack.prod.config.js` file when running build, you can add the following scripts to `package.json`: ```json title="package.json" { "scripts": { "dev": "rspack serve", "build": "rspack build --config rspack.prod.config.js" } } ``` Abbreviate the `--config` option to `-c`: ```bash $ rspack build -c rspack.prod.config.js ``` ## Exporting a configuration function Rspack supports exporting a function in Rspack configuration file, you can dynamically compute the configuration in the function and return it to Rspack. ```js title="rspack.config.mjs" export default function (env, argv) { return { devtool: env.production ? 'source-map' : 'eval', }; } ``` As you can see from the example above, the function takes two input parameters: * The first argument is `env`, which corresponds to the value of the `--env` option when running the CLI command. * The second argument is `argv`, which contains all the options passed to the CLI. ### Determine the current environment In addition to passing the `env` parameter, it is more common to use `process.env.NODE_ENV` to determine the current environment: ```js title="rspack.config.mjs" export default function (env, argv) { const isProduction = process.env.NODE_ENV === 'production'; return { devtool: isProduction ? 'source-map' : 'eval', }; } ``` ## Merge configurations Use Rspack's [extends](/config/extends.md) option or [webpack-merge](https://npmjs.com/package/webpack-merge) package to merge multiple Rspack configurations. ### extends option When using [@rspack/cli](/api/cli.md), Rspack provides the `extends` option, allowing you to extend configurations from other files or packages. ```js title="rspack.config.mjs" export default { extends: './base.rspack.config.mjs', output: { filename: '[name].bundle.js', }, }; ``` > This option is only supported in `@rspack/cli`, see [extends](/config/extends.md) for more usage. ### webpack-merge `webpack-merge` is a community library for merging multiple webpack configurations, and it can also be used to merge Rspack configurations. First install `webpack-merge`: Then you can use its `merge` function to merge configurations: ```js title="rspack.config.mjs" import { merge } from 'webpack-merge'; const isDev = process.env.NODE_ENV === 'development'; const base = {}; const dev = { plugins: [new SomeDevPlugin()], }; export default isDev ? merge(base, dev) : base; ``` > See [webpack-merge documentation](https://npmjs.com/package/webpack-merge) for more details. --- url: /config/extends.md --- # Extends Used to extend configurations from other files or packages. This allows you to create a base configuration and extend it for different environments or use cases. * **Type:** `string | string[]` * **Default:** `undefined` :::info This option is only supported in [`@rspack/cli`](/api/cli.md). If you are using the JavaScript API or other Rspack-based tools, `extends` will not take effect, use [webpack-merge](/config/index.md#webpack-merge) instead. ::: ## Basic usage You can extend a configuration from another file by specifying the path to the file in the `extends` property. The path can be absolute or relative to the configuration file: ```js title="rspack.config.mjs" export default { extends: './base.rspack.config.mjs', // Override or add to the base configuration output: { filename: '[name].bundle.js', }, }; ``` ```js title="rspack.config.cjs" module.exports = { extends: './base.rspack.config.cjs', // Override or add to the base configuration output: { filename: '[name].bundle.js', }, }; ``` :::tip When using relative paths, they are resolved relative to the configuration file that contains the `extends` property. ::: ## Multiple configurations * **Type:** `string[]` * **Default:** `undefined` You can extend multiple configurations by providing an array of paths. Configurations are merged from right to left, meaning that the rightmost configuration will be merged into the leftmost one, and so on: ```js title="rspack.config.mjs" export default { extends: ['./base.rspack.config.mjs', './dev.rspack.config.mjs'], // Additional configuration options plugins: [ // Add more plugins ], }; ``` :::info Merge Behavior When merging configurations: * Simple values are overwritten * Arrays are concatenated * Objects are deeply merged ::: ## Node modules * **Type:** `string` * **Default:** `undefined` You can also extend configurations from packages installed in your node\_modules. The package should export a valid Rspack configuration: ```js title="rspack.config.mjs" export default { extends: 'some-rspack-config-package', // Override or add to the package's configuration }; ``` ## Nested extends Configurations can have their own `extends` property, allowing for nested configuration inheritance. The resolution is performed recursively: ```js title="base.rspack.config.mjs" export default { extends: './core.rspack.config.mjs', // Base configuration options }; ``` ```js title="rspack.config.mjs" export default { extends: './base.rspack.config.mjs', // Environment-specific configuration options }; ``` --- url: /config/entry.md --- # Entry The `entry` configuration is used to set the entry module for Rspack builds. ## Single entry If you are building a single page application or a library, you will usually only need to set up a single entry point. To set up a single entry, simply pass the path to the entry module as a string to the `entry` configuration. ```js title="rspack.config.mjs" export default { entry: './src/index.js', }; ``` The above writing method will automatically set the name of the entry module to `main`, which is equivalent to the following writing method: ```js title="rspack.config.mjs" export default { entry: { main: './src/index.js', }, }; ``` ### Path type The path of the entry module can be a relative path or an absolute path. If `entry` is set as a relative path, Rspack will use the value set by [context configuration](/config/context.md) as the base path, which by default is the current working directory of the Node.js process, namely `process.cwd ()`. You can also use the [path module](https://nodejs.org/api/path.html) in Node.js to generate an absolute path and pass it to the `entry` configuration: ```js title="rspack.config.mjs" import path from 'node:path'; export default { entry: path.join(__dirname, './src/index.js'), }; ``` ### Entry array When setting the value of an entry, in addition to setting it to `string`, you can also pass in a `string[]`, meaning that the entry contains multiple entry modules. For example, the following example will build `pre.js` and `post.js` into the output of `page`. ```js title="rspack.config.mjs" export default { entry: { page: ['./src/pre.js', './src/post.js'], }, }; ``` Multiple modules will be executed sequentially according to the order defined by the array, so the code in `pre.js` will be executed before the code in `post.js`. ## Multiple entries If you need to build multiple entries at once, you should set `entry` to an object, and each key of the object corresponds to an entry name. For example, the following example will build `page1` and `page2` as two entries: ```js title="rspack.config.mjs" export default { entry: { page1: './src/page1/index.js', page2: './src/page2/index.js', }, }; ``` ### Entry description object When you set `entry` to an object, you can set the value of the entry to a description object. A description object can contain the following properties: #### EntryDescription.import The path or paths to the entry modules. ```js title="rspack.config.mjs" export default { entry: { foo: { import: './src/foo.js', }, }, }; ``` Multiple paths can be set in the `import` property: ```js title="rspack.config.mjs" export default { entry: { foo: { import: ['./src/foo.js', './src/bar.js'], }, }, }; ``` #### EntryDescription.runtime The name of the runtime chunk. When `runtime` is set, a new runtime chunk will be created. You can also set it to `false` to avoid a new runtime chunk. The `runtime` property is used to set the name of the runtime chunk, for example to set the name of the `main` entry chunk to `'foo'`: ```js title="rspack.config.mjs" export default { entry: { main: { import: './src/index.js', runtime: 'foo', }, }, }; ``` #### EntryDescription.chunkLoading How this entry load other chunks. Methods included by default are `'jsonp'` (web), `'import'` (ESM), `'import-scripts'` (WebWorker), `'require'` (sync node.js), `'async-node'` (async node.js), but others might be added by plugins. #### EntryDescription.asyncChunks Whether to create a load-on-demand asynchronous chunk for this entry. #### EntryDescription.publicPath The publicPath of the resource referenced by this entry. #### EntryDescription.baseUri The baseURI of the resource referenced by this entry. #### EntryDescription.filename The filename of the entry chunk. #### EntryDescription.library The format of the chunk generated by this entry as a library, for detailed configuration, see [output.library](/config/output.md#outputlibrary). #### EntryDescription.dependOn The entry that the current entry depends on. With `dependOn` option you can share the modules from one entry chunk to another. #### EntryDescription.wasmLoading Option to set the method of loading WebAssembly Modules. Methods included by default are `'fetch'` (web/WebWorker), `'async-node'` (Node.js), but others might be added by plugins. The default value can be affected by different [target](/config/target.md): * Defaults to `'fetch'` if target is set to `'web'`, `'webworker'`, `'electron-renderer'` or `'node-webkit'`. * Defaults to `'async-node'` if target is set to `'node'`, `'async-node'`, `'electron-main'` or `'electron-preload'`. #### EntryDescription.layer Specifies the layer in which modules of this entrypoint are placed. Make the corresponding configuration take effect through layer matching in split chunks, [rules](/config/module.md#ruleissuerlayer), stats, and externals. :::warning This configuration will only take effect when [experiments.layers](/config/experiments.md#experimentslayers) is `true`. ::: ```js title="rspack.config.mjs" export default { entry: { index: { import: './src/index.js', layer: 'layer-name', }, }, experiments: { layers: true, }, }; ``` ## Dynamic entry If a function is passed then it will be invoked on every [make](/api/plugin-api/compiler-hooks.md#make) event. > Note that the `make` event triggers when webpack starts and for every invalidation when [watching for file changes](/config/watch.md). ```js title="rspack.config.mjs" export default { //... entry: () => './demo', }; ``` Or: ```js title="rspack.config.mjs" export default { //... entry: () => new Promise(resolve => resolve(['./demo', './demo2'])), }; ``` For example: you can use dynamic entries to get the actual entries from an external source (remote server, file system content or database): ```js title="rspack.config.mjs" export default { entry() { return fetchPathsFromSomeExternalSource(); // returns a promise that will be resolved with something like ['src/main-layout.js', 'src/admin-layout.js'] }, }; ``` When combining with the [output.library](/config/output.md#outputlibrary) option: If an array is passed only the last item is exported. --- url: /config/context.md --- # Context The `context` configuration is used to set the base directory for Rspack builds. `context` is an absolute path that is used as the base path for relative paths in Rspack configurations such as [entry](/config/entry.md) and [output](/config/output.md). By default, Rspack uses the current working directory of the Node.js process as the base directory. In most cases, it is recommended to set a base directory manually, rather than relying on the current working directory of Node.js. ## Example For example, you can use [`__dirname`](https://nodejs.org/docs/latest/api/modules.html#__dirname) as the base directory: ```js title="rspack.config.mjs" import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); export default { context: __dirname, entry: { main: './src/index.js', }, }; ``` ```js title="rspack.config.cjs" module.exports = { context: __dirname, entry: { main: './src/index.js', }, }; ``` In the above example, the `main` entry will be resolved based on the `path.join(__dirname, './src/index.js')` path. --- url: /config/mode.md --- # Mode The `mode` configuration is used to set the build mode of Rspack to enable the default optimization strategy. ## Usage You can set the mode directly in Rspack config: ```js title="rspack.config.mjs" export default { mode: 'production', }; ``` In actual scenarios, you can dynamically set the mode according to `process.env.NODE_ENV`: ```js title="rspack.config.mjs" const isProduction = process.env.NODE_ENV === 'production'; export default { mode: isProduction ? 'production' : 'development', }; ``` Alternatively, you can set the mode using the `--mode` option on the Rspack CLI: ```bash rspack --mode=production ``` :::info `--mode` option on the CLI has a higher priority than `mode` in Rspack config. ::: ## Optional values `mode` has the following optional values: ### production In production mode, Rspack automatically enables the following optimization strategies: * Replace `process.env.NODE_ENV` in code with `'production'`. * Set the default value of `optimization.minimize` to `true` to enable SWC minification. ### development In development mode, Rspack automatically enables the following optimization strategies: * Replace `process.env.NODE_ENV` in code with `'development'`. * Set proper naming format for modules and chunks. ### none When `mode` is set to `'none'`, Rspack will not enable any default optimization strategies. --- url: /config/output.md --- # Output The top-level output key contains a set of options instructing Rspack on how and where it should output your bundles, assets, and anything else you bundle or load with Rspack. * **Type:** `Object` ## output.assetModuleFilename * **Type:** `string | ((pathData: PathData, assetInfo?: AssetInfo) => string)` * **Default:** `'[hash][ext][query]'` The same as [`output.filename`](#outputfilename) but for [Asset Modules](/guide/features/asset-module.md). `[name]`, `[file]`, `[query]`, `[fragment]`, `[base]`, and `[path]` are set to an empty string for the assets built from data URI replacements. The name of the file to be output by the Asset module. This value can be overridden by [Rule.generator.filename](#outputfilename). :::info Asset module output as a separate file * Module type is `'asset'` and asset is set to satisfy [Rule.parser.dataUrlCondition](/config/module.md#ruleparserdataurlcondition) * Module type is `'asset/resource'` ::: ## output.asyncChunks * **Type:** `boolean` * **Default:** `true` Create async chunks that are loaded on demand. ## output.charset * **Type:** `boolean` * **Default:** `true` Add `charset="utf-8"` to the 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. 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:** Determined by [`output.filename`](/config/output.md#outputfilename) 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. 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:** `string` | `function (info)` * **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:** `string = 'webpack://[namespace]/[resource-path]?[loaders]'` | `function (info) => string` * **Default:** `undefined` 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 | | \[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-streaming' | 'fetch' | 'async-node' | string | false)[]` * **Default:** Determined by [`output.wasmLoading`](#outputwasmloading) and [`output.workerWasmLoading`](#workerWasmLoading) List of Wasm loading types enabled for use by entry points. ```js title="rspack.config.mjs" export default { //... output: { enabledWasmLoadingTypes: ['fetch'], }, }; ``` ## output.environment Tell Rspack what kind of ES-features may be used in the generated runtime-code. ```js title="rspack.config.mjs" export default { output: { environment: { // The environment supports arrow functions ('() => { ... }'). arrowFunction: true, // The environment supports async function and await ('async function () { await ... }'). asyncFunction: true, // The environment supports BigInt as literal (123n). bigIntLiteral: false, // The environment supports const and let for variable declarations. const: true, // The environment supports destructuring ('{ a, b } = obj'). destructuring: true, // The environment supports 'document' variable. document: true, // The environment supports an async import() function to import ECMAScript modules. dynamicImport: false, // The environment supports an async import() when creating a worker, only for web targets at the moment. dynamicImportInWorker: false, // The environment supports 'for of' iteration ('for (const x of array) { ... }'). forOf: true, // The environment supports 'globalThis'. globalThis: true, // The environment supports ECMAScript Module syntax to import ECMAScript modules (import ... from '...'). module: false, // Determines if the node: prefix is generated for core module imports in environments that support it. // This is only applicable to webpack runtime code. nodePrefixForCoreModules: false, // The environment supports optional chaining ('obj?.a' or 'obj?.()'). optionalChaining: true, // The environment supports template literals. templateLiteral: true, }, }, }; ``` ## 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. { // TODO: add the Glossary link } ::: 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', }, }; ``` 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. ## Template string The template string below can be used to replace the corresponding file name. Different contexts correspond to different replaceable content, e.g. [output.assetModuleFilename](/config/output.md#outputassetmodulefilename) supports the use of [File Context](/config/output.md#file-context) and [Module Context](/config/output.md#module-context). ### Compilation context Content that can be replaced at the compilation level. | Template | Description | | ------------ | ------------------------ | | `[fullhash]` | full hash of compilation | ### Chunk context Content that can be replaced at the chunk level. | template | description | | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `[id]` | The current chunk id | | `[name]` | Use name when chunk name exists, otherwise use chunk id | | `[chunkhash]` | The hash value of the chunk, computed from all elements of type in the current chunk | | `[contenthash]` | The hash value of the chunk, computed from the elements that contain only the content of that type. For example, if a module of type JavaScript is generated, only the hash of all JavaScript-typed modules in the current chunk is used. | ### Module context Content that can be replaced at the module level. | Template | Description | | --------------- | ---------------------- | | `[id]` | The id of the module | | `[hash]` | The hash of the module | | `[contenthash]` | hash of module content | ### File context Content that can be replaced at the file level. | Template | Description | | ------------ | --------------------------------------------------------------------------------- | | `[file]` | Filename and path, without query or fragment | | `[query]` | Query with leading `?` | | `[fragment]` | Fragment with leading `#` | | `[base]` | Only filename (including extensions), without path | | `[filebase]` | Same, but deprecated | | `[path]` | Only path, without filename | | `[name]` | Only filename without extension or path | | `[ext]` | Extension with leading `.` (not available for [output.filename](#outputfilename)) | Substitutions available on URL-level: | Template | Description | | -------- | ----------- | | `[url]` | URL | :::tip `[file]` equals `[path][base]`. `[base]` equals `[name][ext]`. The full path is `[path][name][ext][query][fragment]` or `[path][base][query][fragment]` or `[file][query][fragment]`. ::: The length of hashes (`[hash]`, `[contenthash]` or `[chunkhash]`) can be specified using `[hash:12]` (defaults to 16). Alternatively, specify [`output.hashDigestLength`](#outputhashdigestlength) to configure the length globally. It is possible to filter out placeholder replacement when you want to use one of the placeholders in the actual file name. For example, to output a file `[name].js`, you have to escape the `[name]` placeholder by adding backslashes between the brackets. So that `[\name\]` generates `[name]` instead of getting replaced with the `name` of the asset. Example: `[\id\]` generates `[id]` instead of getting replaced with the `id`. If using a function for this option, the function will be passed an object containing data for the substitutions in the table above. Substitutions will be applied to the returned string too. The passed object will have this type: (properties available depending on context) ```ts type PathData = { hash: string; hashWithLength: (number) => string; chunk: Chunk | ChunkPathData; module: Module | ModulePathData; contentHashType: string; contentHash: string; contentHashWithLength: (number) => string; filename: string; url: string; runtime: string | SortableSet; chunkGraph: ChunkGraph; }; type ChunkPathData = { id: string | number; name: string; hash: string; hashWithLength: (number) => string; contentHash: Record; contentHashWithLength: Record string>; }; type ModulePathData = { id: string | number; hash: string; hashWithLength: (number) => string; }; ``` :::warning When developing locally, it's recommended to avoid using hash values in filenames. This is because entry files and chunks split by [`optimization.splitChunks`](/plugins/webpack/split-chunks-plugin.md) are loaded via ` ``` 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'`, `'system'`, `'assign'`, `'assign-properties'`, `'this'`, `'window'`, `'self'`, `'global'`, `'commonjs'`, `'commonjs2'`, `'commonjs-module'`, `'commonjs-static'`, `'amd'`, `'amd-require'`, `'umd'`, `'umd2'`, 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 { // … experiments: { outputModule: true, }, output: { library: { // do not specify a `name` here type: 'module', }, }, }; ``` Output ES modules. However this feature is still experimental and not fully supported yet, so make sure to enable [`experiments.outputModule`](/config/experiments.md#experimentsoutputmodule) beforehand. In addition, you can track the development progress in [this thread](https://github.com/webpack/webpack/issues/2933#issuecomment-774253975). ##### type: 'modern-module' ```js title="rspack.config.mjs" export default { // … experiments: { outputModule: true, }, output: { library: { // do not specify a `name` here type: 'modern-module', }, }, }; ``` This configuration generates tree-shakable output for ES Modules. However this feature is still experimental and not fully supported yet, so make sure to enable [`experiments.outputModule`](/config/experiments.md#experimentsoutputmodule) beforehand. ##### 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)). ::: ##### 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 ` ``` ```js title="rspack.config.mjs" export default { //... externals: { jquery: 'jquery', }, }; ``` This leaves any dependent modules unchanged, i.e. the code shown below will still work: ```js import $ from 'jquery'; $('.my-element').animate(/* ... */); ``` The property name `jquery` specified under `externals` in the above Rspack configuration indicates that the module `jquery` in `import $ from 'jquery'` should be excluded from bundling. In order to replace this module, the value `jQuery` will be used to retrieve a global `jQuery` variable, as the default external library type is `var`, see [externalsType](#externalstype). While we showed an example consuming external global variable above, the external can actually be available in any of these forms: global variable, CommonJS, AMD, ES2015 Module, see more in [externalsType](#externalstype). ### string Depending on the [externalsType](#externalstype), this could be the name of the global variable (see [`'global'`](#externalstypeglobal), [`'this'`](#externalstypethis), [`'var'`](#externalstypevar), [`'window'`](#externalstypewindow)) or the name of the module (see `amd`, [`commonjs`](#externalstypecommonjs), [`module`](#externalstypemodule), `umd`). You can also use the shortcut syntax if you're defining only 1 external: ```js title="rspack.config.mjs" export default { //... externals: 'jquery', }; ``` equals to ```js title="rspack.config.mjs" export default { //... externals: { jquery: 'jquery', }, }; ``` You can specify the [external library type](#externalstype) to the external with the `${externalsType} ${libraryName}` syntax. It will override the default external library type specified in the [externalsType](#externalstype) option. For example, if the external library is a [CommonJS module](#externalstypecommonjs), you can specify ```js title="rspack.config.mjs" export default { //... externals: { jquery: 'commonjs jquery', }, }; ``` ### 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 [`libraryTarget: 'umd'`](/config/output.md#outputlibrarytarget) and [`externalsType: 'umd'`](#externalstype). It's not allowed for other library targets. ::: ```js title="rspack.config.mjs" export default { externals: { // When `libraryTarget: '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`): Describes the external module with the other external formats ([`string`](#string), [`string[]`](#string-array), or [`object`](#object)) * `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 Every dependency that matches the given regular expression will be excluded from the output bundles. ```js title="rspack.config.mjs" export default { //... externals: /^(jquery|\$)$/i, }; ``` In this case, any dependency named `jQuery`, capitalized or not, or `$` would be externalized. ### 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` * **Default:** `'var'` Specify the default type of externals. `amd`, `umd`, `system` and `jsonp` externals **depend on the [`output.libraryTarget`](/config/output.md#outputlibrarytarget)** being set to the same value e.g. you can only consume `amd` externals within an `amd` library. Supported types: * `'amd'` * `'amd-require'` * `'assign'` - same as `'var'` * [`'commonjs'`](#externalstypecommonjs) * `'commonjs-module'` * [`'global'`](#externalstypeglobal) * [`'module'`](#externalstypemodule) * [`'import'`](#externalstypeimport) - uses `import()` to load a native ECMAScript module (async module) * [`'module-import'`](#externalstypemodule-import) * [`'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 [`experiments.outputModule`](/config/experiments.md#experimentsoutputmodule) first, otherwise Rspack will throw errors. **Example** ```js import jq from 'jquery'; jq('.my-element').animate(/* ... */); ``` ```js title="rspack.config.mjs" export default { experiments: { outputModule: true, }, externalsType: 'module', externals: { jquery: 'jquery', }, }; ``` Will generate into something like ```js import * as __WEBPACK_EXTERNAL_MODULE_jquery__ from 'jquery'; const jq = __WEBPACK_EXTERNAL_MODULE_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'); }, }; // webpack 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. Make sure to enable [`experiments.outputModule`](/config/index.md#experimentsoutputmodule) first if static imports exist, otherwise Rspack will throw errors. **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 __WEBPACK_EXTERNAL_MODULE_lodash__ from 'lodash'; const lodash = __WEBPACK_EXTERNAL_MODULE_jquery__; var __webpack_modules__ = { jquery: module => { module.exports = import('jquery'); }, }; // webpack 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\['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'); }, }; // webpack runtime... async function foo() { const jq = await Promise.resolve(/* import() */).then( __webpack_require__.bind(__webpack_require__, 'jquery'), ); (0, lodash__WEBPACK_IMPORTED_MODULE_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 { experiments: { outputModule: true, }, externalsType: 'node-commonjs', externals: { jquery: 'jquery', }, }; ``` Will generate into something like ```js import { createRequire } from '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 `

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

Hello, <strong>Rspack</strong>.

Hello, Rspack.

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

Hello,

.

``` #### Control statements Use the `for in` statement to implement list traversal and the `if` statement to implement conditional judgment: ```txt title="ejs" <% for tag in htmlRspackPlugin.tags.headTags { %> <% if tag.tagName=="script" { %> <%= toHtml(tag) %> <% } %> <% } %> ``` ## Usage The plugin will generate an HTML file for you that includes all your JS outputs in the head using ` ``` If you have multiple entry points in your Rspack config, they will all be included with `` tag in the final html content. ```js title="rspack.config.mjs" const AddScriptPlugin = { apply(compiler) { compiler.hooks.compilation.tap('AddScriptPlugin', compilation => { HtmlRspackPlugin.getCompilationHooks( compilation, ).beforeAssetTagGeneration.tapPromise('AddScriptPlugin', async data => { data.assets.js.push('extra-script.js'); }); }); }, }; export default { //... plugins: [new HtmlRspackPlugin(), AddScriptPlugin], }; ``` ### alterAssetTags This hook will be called after generating the asset tags based on the asset files, but before determining the insertion position of the tags. The tags can be adjusted here. * **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; }; outputName: string; plugin: { options: HtmlRspackPluginOptions; }; }; ``` :::warning Only `assetTags` can be modified. Modifications to other items will not take effect. ::: * When set the attribute value to `true`, a valueless attribute will be added, and `` will be generated. * When set the attribute value to a `string`, a valued attribute will be added, and `` will be generated. * When set the attribute value to `false`, the attribute will be removed. The following code adds the `specialAttribute` property to all `script` type tags: ```js title="rspack.config.mjs" const AddAttributePlugin = { apply(compiler) { compiler.hooks.compilation.tap('AddAttributePlugin', compilation => { HtmlRspackPlugin.getCompilationHooks( compilation, ).alterAssetTags.tapPromise('AddAttributePlugin', async data => { data.assetTags.scripts = data.assetTags.scripts.map(tag => { if (tag.tagName === 'script') { tag.attributes.specialAttribute = true; } return tag; }); }); }); }, }; export default { //... plugins: [new HtmlRspackPlugin(), AddAttributePlugin], }; ``` ### alterAssetTagGroups This hook will be called after generating the tag groups of `head` and `body`, but before the template is rendered by function or template engine. The insertion position of the tags can be adjusted here. * **Type**: `AsyncSeriesWaterfallHook<[AlterAssetTagGroupsData]>` * **Parameters**: ```ts type AlterAssetTagGroupsData = { headTags: Array; bodyTags: Array; outputName: string; plugin: { options: HtmlRspackPluginOptions; }; }; ``` :::warning Warning Only `headTags` and `bodyTags` can be modified. Modifications to other items will not take effect. ::: The following code moves the `async` `script` tags from `body` to `head`: ```js title="rspack.config.mjs" const MoveTagsPlugin = { apply(compiler) { compiler.hooks.compilation.tap('MoveTagsPlugin', compilation => { HtmlWebpackPlugin.getCompilationHooks( compilation, ).alterAssetTagGroups.tapPromise('MoveTagsPlugin', async data => { data.headTags.push(data.headTags.bodyTags.filter(i => i.async)); data.bodyTags = data.bodyTags.filter(i => !i.async); }); }); }, }; export default { //... plugins: [ new HtmlRspackPlugin({ inject: 'body', }), AllHeadTagsPlugin, ], }; ``` ### afterTemplateExecution This hook will be called after the template rendering is completed, but before the tags are injected. The HTML content and the tags to be injected can be modified here. * When using the function `templateContent` or the `template` ending with `.js/.cjs`, and using this function to render the template, here `html` is the result returned by the function. * In other scenarios, the HTML template will be compiled through a template engine inside, and here `html` is the compiled result. * **Type**: `AsyncSeriesWaterfallHook<[AfterTemplateExecutionData]>` * **Parameters**: ```ts type AfterTemplateExecutionData = { html: string; headTags: Array; bodyTags: Array; outputName: string; plugin: { options: HtmlRspackPluginOptions; }; }; ``` :::warning Warning Only `html`, `headTags`, and `bodyTags` can be modified. Modifications to other items will not take effect. ::: The following code adds `Injected by plugin` at the end of the body. Then the tags will be injected after this text. Therefore, it will be `` in the final HTML content: ```js title="rspack.config.mjs" const InjectContentPlugin = { apply(compiler) { compiler.hooks.compilation.tap('InjectContentPlugin', compilation => { HtmlWebpackPlugin.getCompilationHooks( compilation, ).afterTemplateExecution.tapPromise('InjectContentPlugin', async data => { data.html = data.html.replace('', 'Injected by plugin'); }); }); }, }; export default { //... plugins: [ new HtmlRspackPlugin({ inject: 'body', }), InjectContentPlugin, ], }; ``` ### beforeEmit This hook will be called before generating the HTML asset file, and it is the final chance to modify the HTML content. * **Type**: `SyncHook<[BeforeEmitData]>` * **Parameters**: ```ts type BeforeEmitData = { html: string; outputName: string; plugin: { options: HtmlRspackPluginOptions; }; }; ``` :::warning Warning Only `html` can be modified. Modifications to other items will not take effect. ::: The following code adds `Injected by plugin` at the end of the body. It will be `Injected by plugin` in the final HTML content: ```js title="rspack.config.mjs" const InjectContentPlugin = { apply(compiler) { compiler.hooks.compilation.tap('InjectContentPlugin', compilation => { HtmlWebpackPlugin.getCompilationHooks(compilation).beforeEmit.tapPromise( 'InjectContentPlugin', async data => { data.html = data.html.replace('', 'Injected by plugin'); }, ); }); }, }; export default { //... plugins: [ new HtmlRspackPlugin({ inject: 'body', }), InjectContentPlugin, ], }; ``` ### afterEmit This hook will be called after generating the HTML asset file and is only used for notification. * **Type**: `SyncHook<[AfterEmitData]>` * **Parameters**: ```ts type AfterEmitData = { outputName: string; plugin: { options: HtmlRspackPluginOptions; }; }; ``` --- url: /plugins/rspack/lightning-css-minimizer-rspack-plugin.md --- # LightningCssMinimizerRspackPlugin This plugin uses [lightningcss](https://lightningcss.dev/) to minify CSS assets. See [optimization.minimizer](/config/optimization.md#optimizationminimizer). ```js title="rspack.config.mjs" import { rspack } from '@rspack/core'; export default { // ... optimization: { minimizer: [new rspack.LightningCssMinimizerRspackPlugin(options)], }, }; ``` ## 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: {/* prettier-ignore */} ```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 default `targets` is set to `"fully supports es6"` to ensure 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 LightningCssMinimizerOptions = { errorRecovery?: boolean; targets?: string[] | string; include?: LightningcssFeatureOptions; exclude?: LightningcssFeatureOptions; /** * @deprecated Use `drafts` instead. * This will be removed in the next major version. */ draft?: Drafts; 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/rspack/subresource-integrity-plugin.md --- # SubresourceIntegrityPlugin The `rspack.experiments.SubresourceIntegrityPlugin` is a plugin for enabling Subresource Integrity in Rspack. ## 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.plugin('done', 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/rspack/swc-js-minimizer-rspack-plugin.md --- # SwcJsMinimizerRspackPlugin This plugin is used to minify JavaScript files using [SWC](https://swc.rs/). ## Example 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/rspack/lightning-css-minimizer-rspack-plugin.md) to minify CSS files. ::: ## Options ### test * **Type:** `string | RegExp | Array` * **Default:** `undefined` 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 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, }); ``` #### RegExp 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 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 `/*! For license information please see {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; mangle?: TerserMangleOptions | boolean; compress?: TerserCompressOptions | boolean; format?: JsFormatOptions & ToSnakeCaseProperties; }; ``` * **Default:** ```js const defaultOptions = { minify: true, mangle: true, compress: { passes: 2, } format: { comments: false, }, }; ``` 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: /api/index.md --- # Introduction Rspack provides a variety of APIs and command line interface (CLI) to customize the build process. There are some features overlap between APIs and CLI, e.g. some configuration options may be available via CLI flags, while some others are only available through specific APIs. The following concepts will help you get started. ## CLI The Command Line Interface (CLI) to configure and interact with your build process. For the most part, the CLI is used to kick off the process using a [configuration file](/config/index.md) and a few flags (e.g. `--env`). [Learn more about the CLI →](/api/cli.md) ## Runtime API When processing modules with rspack, it is important to understand the different module syntaxes – specifically the methods and variables - that are supported. And also the runtime HMR improves the development experience by updating modules in the browser at runtime without needing a whole page refresh. [Learn more about the Runtime API →](/api/runtime-api/module-methods.md) ## JavaScript API While most users can get away with using the CLI along with a configuration file, more fine-grained control of the compilation can be achieved via the Node interface. This includes passing multiple configurations, programmatically running or watching, and collecting stats. [Learn more about the JavaScript API →](/api/javascript-api/index.md) ## Loader API Loaders are transformations that are applied to the source code of a module. They are written as functions that accept source code as a parameter and return a new version of that code with transformations applied. [Learn more about the loaders →](/api/loader-api/index.md) ## Plugin API The plugin interface allows users to tap directly into the compilation process. Plugins can register handlers on lifecycle hooks that run at different points throughout a compilation. When each hook is executed, the plugin will have full access to the current state of the compilation. [Learn more about the plugins →](/api/plugin-api/index.md) --- url: /api/javascript-api/index.md --- # JavaScript API Rspack provides a set of JavaScript APIs to be used in JavaScript runtimes like Node.js, Deno, or Bun. The JavaScript API is useful in scenarios in which you need to customize the build or development process since all the reporting and error handling must be done manually and webpack only does the compiling part. For this reason the [`stats`](/config/stats.md) configuration options will not have any effect in the `rspack()` call. :::tip `@rspack/core` is designed to align with webpack's JavaScript API to ensure functional consistency and a similar user experience. ::: ## Installation To start using the Rspack JavaScript API, first install `@rspack/core` if you haven't yet: Then introduce the `@rspack/core` module in your JavaScript file: ```js title="build.mjs" import { rspack } from '@rspack/core'; ``` ```js title="build.cjs" const { rspack } = require('@rspack/core'); ``` ## rspack() The imported rspack function is fed a Rspack Configuration Object and runs the Rspack compiler if a callback function is provided: ```js import { rspack } from '@rspack/core'; rspack({}, (err, stats) => { if (err || stats.hasErrors()) { // ... } // Done processing }); ``` ```ts function rspack( options: MultiRspackOptions | RspackOptions, callback?: Callback, ): null | MultiCompiler | Compiler; ``` :::tip The `err` object will not include compilation errors. Those must be handled separately using `stats.hasErrors()`, which will be covered in detail in the [Error Handling](/api/javascript-api/index.md#error-handling) section of this guide. The `err` object will only contain rspack-related issues, such as misconfiguration, etc. ::: :::tip You can provide the `rspack` function with an array of configurations. See the [MultiCompiler](/api/javascript-api/index.md#multicompiler) section below for more information. ::: ## Compiler instance If you don't pass the `rspack` runner function a callback, it will return a Rspack `Compiler` instance. This instance can be used to manually trigger the Rspack runner or have it build and watch for changes, much like the [CLI](/api/cli.md). The `Compiler` instance provides the following methods: * `.run(callback)` * `.watch(watchOptions, handler)` Typically, only one master `Compiler` instance is created, although child compilers can be created in order to delegate specific tasks. The `Compiler` is ultimately a function which performs bare minimum functionality to keep a lifecycle running. It delegates all the loading, bundling, and writing work to registered plugins. The `hooks` property on a `Compiler` instance is used to register a plugin to any hook event in the `Compiler`'s lifecycle. The [`RspackOptionsApply`](https://github.com/web-infra-dev/rspack/blob/main/packages/rspack/src/rspackOptionsApply.ts) utilities are used by Rspack to configure its `Compiler` instance with all the built-in plugins. > See [Compiler API](/api/javascript-api/compiler.md) for more details. ```ts type Compiler = { hooks: CompilerHooks; inputFileSystem: InputFileSystem | null; outputFileSystem: OutputFileSystem | null; watchFileSystem: WatchFileSystem | null; options: RspackOptionsNormalized; watching: Watching; getInfrastructureLogger(name: string | (() => string)): Logger; getCache(name: string): CacheFacade; watch( watchOptions: Watchpack.WatchOptions, handler: liteTapable.Callback, ): Watching; run(callback: liteTapable.Callback): void; runAsChild( callback: ( err?: null | Error, entries?: Chunk[], compilation?: Compilation, ) => any, ): void; createChildCompiler( compilation: Compilation, compilerName: string, compilerIndex: number, outputOptions: OutputNormalized, plugins: RspackPluginInstance[], ): Compiler; compile(callback: liteTapable.Callback): void; close(callback: (error?: Error | null) => void): void; }; ``` ## compiler.run The `run` method is then used to kickstart all compilation work. Upon completion, the given `callback` function is executed. The final logging of stats and errors should be done in this `callback` function. :::warning The API only supports a single concurrent compilation at a time. When using `run` or `watch`, call `close` and wait for it to finish before calling `run` or `watch` again. Concurrent compilations will corrupt the output files. ::: ```js import { rspack } from '@rspack/core'; const compiler = rspack({ // ... }); compiler.run((err, stats) => { // ... compiler.close(closeErr => { // ... }); }); ``` ## compiler.watch Calling the `watch` method triggers the rspack runner, but then watches for changes (much like CLI: `rspack --watch`), as soon as Rspack detects a change, runs again. Returns an instance of `Watching`. ```js import { rspack } from '@rspack/core'; const compiler = rspack({ // ... }); const watching = compiler.watch( { // Example aggregateTimeout: 300, poll: undefined, }, (err, stats) => { // Print watch/build result here... console.log(stats); }, ); ``` `Watching` options are covered in detail [here](/config/watch.md#watchoptions). :::warning Filesystem inaccuracies may trigger multiple builds for a single change. In the example above, the `console.log` statement may fire multiple times for a single modification. Users should expect this behavior and may check `stats.hash` to see if the file hash has actually changed. ::: > See [`Compiler.watch`](/api/javascript-api/compiler.md#watch) for more details. ```ts type Watching = { watch( files: Iterable, dirs: Iterable, missing: Iterable, ): void; suspend(): void; resume(): void; invalidate(callback?: Callback): void; close(callback?: () => void): void; }; ``` ## Stats object The `stats` object that is passed as a second argument of the [`rspack()`](/api/javascript-api/index.md#rspack) callback, is a good source of information about the code compilation process. It includes: * Errors and Warnings (if any) * Timings * Module and Chunk information The [Rspack CLI](/api/cli.md) uses this information to display nicely formatted output in your console. :::tip When using the `MultiCompiler`, a `MultiStats` instance is returned that fulfills the same interface as `stats`, i.e. the methods described below. ::: > See [Stats API](/api/javascript-api/stats.md) for more details. ```ts type Stats = { compilation: Compilation; hash: Readonly; startTime?: number; endTime?: number; hasErrors(): bool; hasWarnings(): bool; toJson(opts?: StatsValue): StatsCompilation; toString(opts?: StatsValue): string; }; ``` ## MultiCompiler The `MultiCompiler` module allows Rspack to run multiple configurations in separate compilers. If the `options` parameter in the Rspack's JavaScript API is an array of options, Rspack applies separate compilers and calls the callback after all compilers have been executed. ```js import { rspack } from '@rspack/core'; rspack( [ { entry: './index1.js', output: { filename: 'bundle1.js' } }, { entry: './index2.js', output: { filename: 'bundle2.js' } }, ], (err, stats) => { process.stdout.write(stats.toString() + '\n'); }, ); ``` > See [MultiCompiler API](/api/javascript-api/compiler.md#multicompiler) for more details. ## Error handling For good error handling, you need to account for these three types of errors: * Fatal rspack errors (wrong configuration, etc) * Compilation errors (missing modules, syntax errors, etc) * Compilation warnings Here's an example that handles all conditions: ```js import { rspack } from '@rspack/core'; rspack( { // ... }, (err, stats) => { if (err) { console.error(err.stack || err); if (err.details) { console.error(err.details); } return; } const info = stats.toJson(); if (stats.hasErrors()) { console.error(info.errors); } if (stats.hasWarnings()) { console.warn(info.warnings); } // Log result... }, ); ``` ## Custom file systems :::danger Differences with webpack 1. The current support for `inputFileSystem` in Rspack is limited, and the ability to customize the filesystem read capability consistent with webpack has not yet been implemented. Please refer to: [Issue #5091](https://github.com/web-infra-dev/rspack/issues/5091). 2. With Rspack, when using a specified output file system, there's no longer a requirement to supply `mkdirp` and `join` utility methods. ::: By default, Rspack reads files and writes files to disk using a normal file system. However, it is possible to change the input or output behavior using a different kind of file system (memory, webDAV, etc). To accomplish this, one can change the `inputFileSystem` or `outputFileSystem`. For example, you can replace the default `outputFileSystem` with [`memfs`](https://github.com/streamich/memfs) to write files to memory instead of to disk: ```js import { createFsFromVolume, Volume } from 'memfs'; import { rspack } from '@rspack/core'; const fs = createFsFromVolume(new Volume()); const compiler = rspack({ /* options */ }); compiler.outputFileSystem = fs; compiler.run((err, stats) => { // Read the output later: const content = fs.readFileSync('...'); compiler.close(closeErr => { // ... }); }); ``` ## `sources` object `@rspack/core` exports the [webpack-sources](https://github.com/webpack/webpack-sources) module through `sources`. It provides a set of classes for creating and manipulating source code fragments and source maps. When developing Rspack plugins, you can use these classes to handle and manipulate source code. ```js import { sources } from '@rspack/core'; const { RawSource } = sources; const source = new RawSource('console.log("Hello, world!");'); ``` For detailed usage, please refer to the [webpack-sources](https://github.com/webpack/webpack-sources) documentation. --- url: /api/loader-api/index.md --- # Overview ## Compatibility Rspack is committed to being compatible with the loaders within the webpack ecosystem. We ensure that Rspack is as compatible as possible with the webpack loader API, allowing more existing webpack loaders to be directly used in Rspack. Currently, Rspack is compatible with most of webpack's loader APIs. If you find that a webpack loader cannot be used in Rspack, feel free to file an issue in the [Rspack repository](https://github.com/web-infra-dev/rspack). ## Examples We provide some basic examples of different types of loaders. If you want to write a loader, you can refer to [these examples](/en/api/loader-api/examples.md) to get started. If you need to use an existing loader, you can refer to [Features - Loader](/guide/features/loader.md) to learn how to use it. ## Loader API Loader API includes: * [Loader Context](/api/loader-api/context.md): Represents the properties that are available inside of a loader assigned to the `this` property. * [Inline loader](/api/loader-api/inline.md): Specify a loader in an `import` statement. * [Inline matchResource](/api/loader-api/inline-match-resource.md): Allows you to dynamically change the matching rules when loading resources. --- url: /api/plugin-api/index.md --- # Overview ## Compatibility status Rspack is committed to being compatible with the plugins within the webpack ecosystem. We ensure that Rspack is as compatible as possible with the webpack plugin API, allowing more existing webpack plugins to be directly used in Rspack. We have already made most of the webpack plugin APIs compatible. You can visit [this page](https://github.com/orgs/web-infra-dev/projects/9) to learn about the current compatibility status of webpack plugin APIs. ## Writing plugins compatible with Rspack and webpack In most cases, you don't need to do any extra work to make a webpack plugin run correctly in Rspack. However, you should avoid directly importing classes or methods from the webpack package. Instead, retrieve these classes or methods from the `compiler` object within your plugin. ```js export class Plugin { apply(compiler) { const { DefinePlugin, // Retrieve plugin NormalModule, sources: { RawSource }, // Retrieve class } = compiler.webpack; } } ``` Although Rspack strives to be compatible with webpack's plugin API, you may still encounter some subtle differences between Rspack and webpack's plugin APIs. To determine whether your plugin is running in webpack or Rspack, you can check the `compiler.rspack` property: ```js export class Plugin { apply(compiler) { if (compiler.rspack) { // Logic for running in Rspack } else { // Logic for running in webpack } } } ``` --- url: /api/cli.md --- # Command line interface [@rspack/cli](https://npmjs.com/package/@rspack/cli) is the command line tool for Rspack, providing a variety of commands to make working with Rspack easier. * If you do not have `@rspack/cli` installed, please read the [Quick start](/guide/start/quick-start.md) section first. * If you are using Rsbuild, please refer to the [Rsbuild CLI](https://rsbuild.dev/guide/basic/cli) section. :::warning Compatible with webpack-cli `@rspack/cli` is not compatible with `webpack-cli`, so there will be some differences between the two. ::: ## All commands To view all available CLI commands, run the following command in the project directory: ```bash npx rspack -h ``` ## Common flags Rspack CLI provides several common flags that can be used with all commands: | Flag | Description | | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | -c, --config \[value] | Specify the path to the configuration file, see [Specify the configuration file](/config/index.md#specify-the-configuration-file) | | --configLoader | Specify the loader to load the config file, can be `native` or `register`, defaults to `register` | | --configName | Specify the name of the configuration to use. | | --nodeEnv | Set the value of `process.env.NODE_ENV`, defaults to `development` for `rspack dev`, and `production` for `rspack build` and `rspack preview` | | -h, --help | Show help information | | -v, --version | Show version number | :::tip All flags in Rspack CLI support the `camelCase` and `kebab-case`, for example, both `--configLoader` and `--config-loader` are valid. ::: ## rspack build `rspack build` is used to run Rspack build, which will generate the output files in the [output.path](/config/output.md#outputpath) directory. ```bash npx rspack build # Read the `rspack.config.*` configuration file by default ``` `rspack build` can be abbreviated as `rspack b`: ```bash npx rspack b ``` Use the `-c` or `--config` flag to specify the configuration file path: ```bash npx rspack build -c ./your.config.js ``` The complete flags are as follows: ``` rspack build Options: --entry entry file [array] -o, --outputPath output path dir [string] -m, --mode mode [string] -w, --watch watch [boolean] [default: false] --env env passed to config function [array] -d, --devtool devtool [boolean] [default: false] --analyze analyze [boolean] [default: false] --json emit stats json --profile capture timing information for each module [boolean] [default: false] ``` ## rspack dev `rspack dev` is used to run Rspack dev server, which will start a local dev server that will listen for file changes and automatically refresh the browser. ```bash npx rspack dev ``` Use the `-c` or `--config` flag to specify the configuration file path: ```bash npx rspack dev -c ./your.config.js ``` `rspack dev` can be abbreviated as `rspack serve` or `rspack s`: ```bash npx rspack s npx rspack serve ``` The complete flags are as follows: ``` rspack dev Options: --entry entry file [array] -o, --outputPath output path dir [string] -m, --mode mode [string] -w, --watch watch [boolean] [default: false] --env env passed to config function [array] -d, --devtool devtool [boolean] [default: false] --hot enables hot module replacement --port allows to specify a port to use [number] --host allows to specify a hostname to use [string] ``` ## rspack preview `rspack preview` is used to preview the production build output locally, note that you need to build the output first by running the `rspack build` command. ```bash npx rspack preview ``` The complete flags are as follows: ``` rspack preview [dir] run the rspack server for build output Positionals: dir directory want to preview [string] Options: --publicPath static resource server path [string] --port preview server port [number] --host preview server host [string] --open open browser [boolean] --server Configuration items for the server. [string] ``` --- url: /api/runtime-api/module-methods.md --- # Module methods This section covers all methods available in code compiled with Rspack. When using Rspack to bundle your application, you can pick from a variety of module syntax styles including [ES modules](https://nodejs.org/api/esm.html#modules-ecmascript-modules) and [CommonJS](https://nodejs.org/api/modules.html). While Rspack supports multiple module syntaxes, we recommend following a single syntax for consistency and to avoid odd behaviors or bugs. Actually Rspack would enforce the recommendation for `.mjs` files, `.cjs` files or `.js` files when their nearest parent `package.json` file contains a ["type"](https://nodejs.org/api/packages.html#type) field with a value of either `"module"` or `"commonjs"`. Please pay attention to these enforcements before you read on: * `.mjs` or `.js` with `"type": "module"` in package.json * No CommonJS allowed, for example, you can't use `require`, `module.exports` or `exports` * File extensions are required when importing, e.g, you should use import './src/App.mjs' instead of import './src/App' (you can disable this enforcement with Rule.resolve.fullySpecified) * `.cjs` or `.js` with "type": "commonjs" in package.json * Neither import nor export is available ## ES modules (recommended) Rspack support ES modules syntax natively, you can use static `import`, `export` and `import()` syntax. :::warning Keep in mind that you will still probably need SWC or Babel for other ES6+ features. ::: ### import Statically `import` the `export` of another module. ```js import MyModule from './my-module.js'; import { NamedExport } from './other-module.js'; ``` You can also `import` Data URI, this allow you to embed Base64 encoded JavaScript code directly in the import statement: ```js // Equivalent to import a module that contains `console.log('hello')` import 'data:text/javascript;charset=utf-8;base64,Y29uc29sZS5sb2coJ2hlbGxvJyk='; // Equivalent to import a module that contains `export const number = 42;` import { number } from 'data:text/javascript;charset=utf-8;base64,ZXhwb3J0IGNvbnN0IG51bWJlciA9IDQyOw=='; ``` ### export Export anything as a `default` or named export. ```js // Named exports export var Count = 5; export function Multiply(a, b) { return a * b; } // Default export export default { // Some data... }; ``` ### Dynamic import() ```ts function import(path: string): Promise; ``` Dynamically load modules, see [Dynamic import](/guide/optimization/code-splitting.md#dynamic-import) for more details. Calls to `import()` are treated as split points, meaning the requested module and its children are split out into a separate chunk. ```js if (module.hot) { import('lodash').then(_ => { // Do something with lodash (a.k.a '_')... }); } ``` :::warning This feature relies on `Promise` internally. If you use `import()` with legacy browsers, remember to shim `Promise` using a polyfill such as [core-js](https://github.com/zloirock/core-js), [es6-promise](https://github.com/stefanpenner/es6-promise) or [promise-polyfill](https://github.com/taylorhakes/promise-polyfill). ::: #### Dynamic expressions in import() It is not possible to use a fully dynamic import statement, such as `import(foo)`. Because `foo` could potentially be any path to any file in your system or project. The `import()` must contain at least some information about where the module is located. Bundling can be limited to a specific directory or set of files so that when you are using a dynamic expression, every module that could potentially be requested on an `import()` call is included. For example, `import(`./locale/$\{language}.json`)` will cause every `.json` file in the `./locale` directory to be bundled into the new chunk. At run time, when the variable `language` has been computed, any file like `english.json` or `german.json` will be available for consumption. ```js // imagine we had a method to get language from cookies or other storage const language = detectVisitorLanguage(); import(`./locale/${language}.json`).then(module => { // do something with the translations }); ``` #### Magic comments Inline comments to make features work. By adding comments to the import, we can do things such as specify chunk name or select different loading modes. For a full list of these magic comments see the code below followed by an explanation of what these comments do. ```js // Single target import( /* webpackChunkName: "my-chunk-name" */ /* webpackMode: "lazy" */ /* webpackExports: ["default", "named"] */ /* webpackFetchPriority: "high" */ 'module' ); // Multiple possible targets import( /* webpackInclude: /\.json$/ */ /* webpackExclude: /\.noimport\.json$/ */ /* webpackChunkName: "my-chunk-name" */ /* webpackMode: "lazy" */ /* webpackPrefetch: true */ /* webpackPreload: true */ `./locale/${language}` ); ``` ##### webpackIgnore * **Type:** `boolean` Disables dynamic import parsing when set to true. :::warning Note that setting webpackIgnore to true opts out of code splitting. ::: ##### webpackMode * **Type:** `"eager" | "lazy" | "weak" | "lazy-once"` * **Default:** `'lazy'` Different modes for resolving dynamic imports can be specified. The following options are supported: * `'lazy'` (default): Generates a lazy-loadable chunk for each `import()`ed module. * `'lazy-once'`: Generates a single lazy-loadable chunk that can satisfy all calls to `import()`. The chunk will be fetched on the first call to `import()`, and subsequent calls to `import()` will use the same network response. Note that this only makes sense in the case of a partially dynamic statement, e.g. `import("./locales/${language}.json")`, where multiple module paths that can potentially be requested. * `'eager'`: Generates no extra chunk. All modules are included in the current chunk and no additional network requests are made. A Promise is still returned but is already resolved. In contrast to a static import, the module isn't executed until the call to `import()` is made. * `'weak'`: Tries to load the module if the module function has already been loaded in some other way (e.g. another chunk imported it or a script containing the module was loaded). A Promise is still returned, but only successfully resolves if the chunks are already on the client. If the module is not available, the Promise is rejected. A network request will never be performed. This is useful for universal rendering when required chunks are always manually served in initial requests (embedded within the page), but not in cases where app navigation will trigger an import not initially served. ##### webpackPrefetch * **Type:** * `number`: chunk prefetch priority * `boolean`: `false` means not to prefetch, `true` means priority is `0` Tells the browser that the resource is probably needed for some navigation in the future, see [Prefetching/Preloading modules](/guide/optimization/code-splitting.md#prefetchingpreloading-modules) for more details. ##### webpackPreload * **Type:** * `number`: chunk preload priority * `boolean`: `false` means not to preload, `true` means priority is `0` Tells the browser that the resource might be needed during the current navigation, , see [Prefetching/Preloading modules](/guide/optimization/code-splitting.md#prefetchingpreloading-modules) for more details. ##### webpackChunkName * **Type:**: `string` A name for the new chunk. ##### webpackFetchPriority * **Type:**: `"low" | "high" | "auto"` Set [`fetchPriority`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/fetchPriority) for specific dynamic imports. It's also possible to set a global default value for all dynamic imports by using the `module.parser.javascript.dynamicImportFetchPriority` option. ##### webpackInclude * **Type:**: `Regexp` A regular expression that will be matched against during import resolution. Only modules that match **will be bundled**. ##### webpackExclude * **Type:**: `Regexp` A regular expression that will be matched against during import resolution. Any module that matches **will not be bundled**. :::info Note that `webpackInclude` and `webpackExclude` options do not interfere with the prefix. eg: `./locale`. ::: ##### webpackExports * **Type:**: `string | string[]` Tells webpack to only bundle the specified exports of a dynamically `import()`ed module. It can decrease the output size of a chunk. ## CommonJS Rspack is also support `CommonJS` syntax natively, you can use `require` and `module.exports` methods. ### require Synchronously retrieve the exports from another module. ```js require(dependency: string); ``` ### require.resolve Synchronously retrieves the module ID without executing the module code. This method will include the module in the final bundle. The returned module ID is primarily intended for use with `require.cache[id]` or the Rspack internal `__webpack_require__(id)` function. Direct use of this method should be avoided in most application scenarios. ```js require.resolve(dependency: string); ``` :::warning Module ID's type can be a number or a string depending on the `optimization.moduleIds` configuration. ::: ### require.cache Multiple requires of the same module result in only one module execution and only one export. Therefore a cache in the runtime exists. Removing values from this cache causes new module execution and a new export. ```js var d1 = require('dependency'); require('dependency') === d1; delete require.cache[require.resolve('dependency')]; require('dependency') !== d1; ``` ### require.context `require.context` is a function specific to webpack that allows you to dynamically require a set of modules. You can use `require.context` in your code, and Rspack will parse and reference the matching modules during the build process. :::tip The return value of `require.context` is the same as [import.meta.webpackContext](/api/runtime-api/module-variables.md#importmetawebpackcontext). We recommend using `import.meta.webpackContext`, which is more powerful. ::: * **Type:** ```ts function requireContext( /** * A directory to search. */ directory: string, /** * Whether subdirectories should be searched. * @default true */ includeSubdirs?: boolean, /** * A regular expression to match files. * @default /^\.\/.*$/ (any file) */ filter?: RegExp, /** * Module loading mode. * @default 'sync' */ mode?: 'sync' | 'eager' | 'weak' | 'lazy' | 'lazy-once', ): Context; ``` * **Example:** ```js // Create a context, with files from the test directory that // can be required with a module specifier ending with `.test.js`. const context = require.context('./test', false, /\.test\.js$/); ``` ```js // Create a context with all files in the parent folder and // descending folders ending with `.stories.js`. const context = require.context('../', true, /\.stories\.js$/); ``` ```js // If mode is set to 'lazy', the underlying modules will be loaded asynchronously const context = require.context('./locales', true, /\.json$/, 'lazy'); ``` :::tip Rspack uses static analysis to parse the parameters of `require.context` during compilation. Therefore, the parameters must be [literals](https://developer.mozilla.org/en-US/docs/Glossary/Literal). For example, the value of `filter` cannot be a variable, nor can it be the value generated by `new RegExp()`. It can only be a regular expression literal. ::: ### require.ensure :::tip `require.ensure()` is specific to rspack/webpack and superseded by `import()`. ::: Split out the given `dependencies` to a separate bundle that will be loaded asynchronously. When using CommonJS module syntax, this is the only way to dynamically load `dependencies`. Meaning, this code can be run within execution, only loading the dependencies if certain conditions are met. :::warning This feature relies on [Promise](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise) internally. If you use `require.ensure` with older browsers, remember to shim Promise using a polyfill such as [es6-promise](https://github.com/stefanpenner/es6-promise) or [promise-polyfill](https://github.com/taylorhakes/promise-polyfill). ::: * **Type:** ```ts function requireEnsure( /** * An array of strings declaring all modules required for the code in the callback to execute. */ dependencies: String[], /** * A function that webpack will execute once the dependencies are loaded. * An implementation of the require function is sent as a parameter to this function. * The function body can use this to further require() modules it needs for execution */ callback: function(require), /** * A function that is executed when webpack fails to load the dependencies. */ errorCallback?: function(error), /** * A name given to the chunk created by this particular require.ensure(). * By passing the same chunkName to various require.ensure() calls, * we can combine their code into a single chunk, resulting in only one bundle that the browser must load. */ chunkName?: string ): Context; ``` * **Example:** ```ts var a = require('normal-dep'); if (module.hot) { require.ensure(['b'], function (require) { var c = require('c'); // Do something special... }); } ``` ### require.resolveWeak Similar to `require.resolve`, but this method won't pull the module into the final bundle. It's what is considered a "weak" dependency. ```js require.resolveWeak(dependency: string); ``` For example: ```js if (__webpack_modules__[require.resolveWeak('module')]) { // Do something when module is available... } if (require.cache[require.resolveWeak('module')]) { // Do something when module was loaded before... } // You can perform dynamic resolves ("context") // similarly to other require/import methods. const page = 'Foo'; __webpack_modules__[require.resolveWeak(`./page/${page}`)]; ``` ## Data URI module Rspack supports importing Data URI modules using the `import` and `require` syntax. **import** ```js import DataURI from 'data:text/javascript,export default 42'; ``` **require** ```js require('data:text/javascript,module.exports = 42'); ``` In addition, Base64 encoded requests are also supported: ```js const { number, fn, } = require('data:text/javascript;charset=utf-8;base64,ZXhwb3J0IGNvbnN0IG51bWJlciA9IDQyOwpleHBvcnQgZnVuY3Rpb24gZm4oKSB7CiAgcmV0dXJuICJIZWxsbyB3b3JsZCI7Cn0='); ``` ::: tip The Data URI module can be used as a method to implement virtual modules, such as combining with a Loader to dynamically load custom modules at runtime. ::: --- url: /api/runtime-api/module-variables.md --- # Module variables This section covers all variables available in code compiled with Rspack. Modules will be able to access specific data from the compilation process through `module` and other variables. ## CommonJS ### module.loaded `false` means that the module is being executed, `true` the synchronous execution has been completed. ### module.id Current module ID. ```js title=src/main.js module.id === require.resolve('./src/main.js'); // true ``` ### module.hot Indicates whether or not hot module replacement is enabled and provides an interface to the process. See the [HMR API page](/api/runtime-api/hmr.md) for details. ### global See [node.js global](https://nodejs.org/api/globals.html#globals_global) for details. Rspack will replace the global with a proxy object and handle compatibility issues in it. ```js title=Source global['property'] ``` ```js title=Compiled __webpack_require__.g['property']; // webpack/runtime/global __webpack_require__.g = (function () { // compatibility code })(); ``` ### \_\_filename Depends on the configuration [`node.__filename`](/config/node.md#node__filename). * `false`: undefined * `mock`: equal to `'/index.js'` * `true`: [NodeJs \_\_filename](https://nodejs.org/api/modules.html#__filename) If used inside an expression that is parsed by the Parser, the configuration option is treated as `true`. ```js title=Source __filename ``` ```js title=Compiled 'src/main.js'; ``` ### \_\_dirname Depends on the configuration [`node.__dirname`](/config/node.md#node__dirname). * `false`: undefined * `mock`: equal to `'/index.js'` * `true`: [NodeJs \_\_dirname](https://nodejs.org/api/modules.html#__dirname) If used inside an expression that is parsed by the Parser, the configuration option is treated as `true`. ```js title=Source __dirname ``` ```js title=Compiled 'src'; ``` ## import.meta (ESM) The `import.meta` exposes context-specific metadata to a JavaScript module, such as the URL of the module. It is only available in ESM. > Please note that Rspack does not support direct access to `import.meta`. Instead, you should access its properties or use destructuring assignment. E.g., ```js title="Source" import.meta typeof import.meta ``` ```js title="Compiled" { } // Warning: Direct access to import.meta is not supported (only property access or destructuring is supported) ('object'); ``` ### import.meta.url Returns the absolute `file:` URL of the module. ```js title=Source import.meta.url typeof import.meta.url ``` ```js title=Compiled 'file://project_root/src/main.js'; 'string'; ``` ### import.meta.webpackContext `import.meta.webpackContext` is a function specific to webpack that allows you to dynamically import a set of modules. You can use `import.meta.webpackContext` in your code, and Rspack will parse and reference the matching modules during the build process. * **Type:** ```ts function webpackContext( /** * A directory to search. */ request: string, options?: { /** * Whether subdirectories should be searched. * @default true */ recursive?: boolean; /** * A regular expression to match files. * @default /^\.\/.*$/ (any file) */ regExp?: RegExp; /** * Module loading mode. * @default 'sync' */ mode?: 'sync' | 'eager' | 'weak' | 'lazy' | 'lazy-once'; include?: RegExp; exclude?: RegExp; preload?: boolean | number; prefetch?: boolean | number; chunkName?: string; exports?: string | string[][]; }, ): Context; ``` * **Example:** ```js // Create a context, with files from the test directory that // can be required with a module specifier ending with `.test.js`. const context = import.meta.webpackContext('./test', { recursive: false, regExp: /\.test\.js$/, }); ``` ```js // Create a context with all files in the parent folder and // descending folders ending with `.stories.js`. const context = import.meta.webpackContext('../', { recursive: true, regExp: /\.stories\.js$/, }); ``` ```js // If mode is set to 'lazy', the underlying modules will be loaded asynchronously const context = import.meta.webpackContext('./locales', { recursive: true, regExp: /\.json$/, mode: 'lazy', }); ``` :::tip Rspack uses static analysis to parse the parameters of `import.meta.webpackContext()` during compilation. Therefore, the parameters must be [literals](https://developer.mozilla.org/en-US/docs/Glossary/Literal). For example, the value of `regExp` cannot be a variable, nor can it be the value generated by `new RegExp()`. It can only be a regular expression literal. ::: ### context API The context returned by `import.meta.webpackContext()` is a function that takes a `request` argument (module path). This function has three properties: `resolve`, `keys`, and `id`. * `resolve` is a function and returns the module id of the parsed module specifier. * `keys` is a function that returns an array of all possible requests that the context module can handle. * `id` is the module id of the context module. This may be useful for `module.hot.accept`. This can be useful if you want to require all files in a directory or matching a pattern. Consider a scenario where you have a folder structure like this: ``` src ├── components │ ├── Button.js │ ├── Header.js │ └── Footer.js ``` You can use `import.meta.webpackContext()` to dynamically import all component files in the folder: ```js const componentsContext = import.meta.webpackContext('./components', { recursive: false, regExp: /\.js$/, }); componentsContext.keys().forEach(fileName => { const componentModule = componentsContext(fileName); // Here you can use your module, for example console.log console.log(componentModule); }); ``` `import.meta.webpackContext()` streamlines the process of module importation especially when you have a lot of files to manage. When using it, please avoid matching unnecessary files, as this might lead to significantly increased build time and output size. ### import.meta.webpackHot An alias for [`module.hot`](#modulehot), however `import.meta.webpackHot` can be used in strict ESM while `module.hot` can't. ## Runtime ### \_\_webpack\_hash\_\_ It provides access to the hash of the compilation. ```js title=Source __webpack_hash__ ``` ```js title=Compiled __webpack_require__.h(); // webpack/runtime/get_full_hash __webpack_require__.h = function () { return '9210c6f859a51c6f9a62'; }; ``` ### \_\_webpack\_runtime\_id\_\_ Access the runtime id of current entry. ```js title=Source __webpack_runtime_id__ ``` ```js title=Compiled __webpack_require__.j; // webpack/runtime/runtime_id __webpack_require__.j = '909'; ``` ### \_\_webpack\_public\_path\_\_ Equals the configuration option's [`output.publicPath`](/config/output.md#outputpublicpath). ```js title=Source __webpack_public_path__ ``` ```js title=Compiled __webpack_require__.p; // output.publicPath !== "auto" __webpack_require__.p = 'output.publicPath'; // output.publicPath === "auto" __webpack_require__.p = 'calculated from document/location'; ``` > See [Dynamically set publicPath](/config/output.md#dynamically-set-publicpath) for more information about the usage of `__webpack_public_path__`. ### \_\_webpack\_base\_uri\_\_ Get or change base URI at runtime. ```js title=Source __webpack_base_uri__ ``` ```js title=Compiled __webpack_require__.b; // chunk loading __webpack_require__.b = document.baseURI || self.location.href; ``` ### \_\_webpack\_nonce\_\_ Rspack is capable of adding a nonce to all scripts that it loads. To activate this feature, set a `__webpack_nonce__` variable and include it in your entry script. ```js title=Source __webpack_nonce__ = 'your_nonce_code'; ``` ```js title=Compiled __webpack_require__.nc = '2312312'; // webpack/runtime/load_script if (__webpack_require__.nc) { script.setAttribute('nonce', __webpack_require__.nc); } ``` ## Modules ### \_\_webpack\_modules\_\_ Access to the internal object of all modules. ```js title=Source __webpack_modules__ ``` ```js title=Compiled var __webpack_modules__ = { 'main.js': function () { __webpack_require__.m; }, }; __webpack_require__.m = __webpack_modules__; ``` ### \_\_webpack\_module\_\_ It provides access to the the current `module`. `module` is not available in strict ESM. ```js title=Source __webpack_module__ ``` ```js title=Compiled "main.js": function(renamed_module) { renamed_module } ``` ### \_\_webpack\_module\_\_.id It provides access to the ID of current module (`module.id`). `module` is not available in strict ESM. ```js title=Source __webpack_module__.id ``` ```js title=Compiled "main.js": function(renamed_module) { renamed_module.id } ``` ### \_\_webpack\_require\_\_ The raw require function. This expression isn't parsed by the Parser for dependencies. ```js title=Source __webpack_require__('./dep.js') ``` ```js title=Compiled "main.js": function(_, __, renamed_require) { renamed_require('./dep.js') } ``` ### \_\_non\_webpack\_require\_\_ Generates a `require` function that is not parsed by webpack. Can be used to do cool stuff with a global require function if available. ```js title=Source __non_webpack_require__('outer.js') ``` ```js title=Compiled "main.js": function(_, __, __webpack_require__) { require('outer.js') } ``` ### \_\_webpack\_is\_included\_\_ Test whether or not the given module is bundled by webpack. ```js title=Source if (__webpack_is_included__('./dep.js')) { // do something } ``` ```js title=Compiled if (true) { // do something } ``` ### \_\_resourceQuery The resource query of the current module. If the following `require` call was made, then the query string would be available in `file.js`. ```js require('file.js?test'); ``` ```js title=Source __resourceQuery ``` ```js title=Compiled '?test'; ``` ### \_\_webpack\_exports\_info\_\_ In modules, `__webpack_exports_info__` is available to allow exports introspection: * `__webpack_exports_info__` is always `true` * `__webpack_exports_info__..used` is `false` when the export is known to be unused, `true` otherwise * `__webpack_exports_info__..useInfo` is * `false` when the export is known to be unused * `true` when the export is known to be used * `null` when the export usage could depend on runtime conditions * `undefined` when no info is available * `__webpack_exports_info__..provideInfo` is * `false` when the export is known to be not provided * `true` when the export is known to be provided * `null` when the export provision could depend on runtime conditions * `undefined` when no info is available * Accessing the info from nested exports is possible: i. e. `__webpack_exports_info__....used` * Check whether exports can be mangled with `__webpack_exports_info__..canMangle` ```js title=Source if (__webpack_exports_info__.someUsedExport.used) { } if (__webpack_exports_info__.someUnusedExport.used) { } ``` ```js title=Compiled if (true) { } if (false) { } ``` ## Chunks ### \_\_webpack\_chunkname\_\_ Get current chunk name. ```js title=Source __webpack_chunkname__ ``` ```js title=Compiled __webpack_require__.cn; // webpack/runtime/chunk_name __webpack_require__.cn = 'main'; ``` ### \_\_webpack\_chunk\_load\_\_ The internal chunk loading function. Takes one argument: * `chunkId`: the id for the chunk to load. ```js title=Source __webpack_chunk_load__ ``` ```js title=Compiled __webpack_require__.e; // webpack/runtime/ensure_chunk __webpack_require__.e = function (chunkId) { // return chunk loading promise }; ``` Example to load chunks from alternate public path when one failed: ```js const originalLoad = __webpack_chunk_load__; const publicPaths = ['a', 'b', 'c']; __webpack_chunk_load__ = async id => { let error; for (const path of publicPaths) { __webpack_public_path__ = path; try { return await originalLoad(id); } catch (e) { error = e; } } throw error; }; import('./module-a').then(moduleA => { // now webpack will use the custom __webpack_chunk_load__ to load chunk }); ``` ### \_\_webpack\_get\_script\_filename\_\_ It provides filename of the chunk by its id. ```js title=Source __webpack_get_script_filename__ ``` ```js title=Compiled __webpack_require__.u; // webpack/runtime/get_chunk_filename __webpack_require__.u = function (chunkId) { // ... }; ``` It is assignable, which allows changing the filename used by the runtime. For example, it can be used to determine the final path when loading chunks. ```js const oldFn = __webpack_get_script_filename__; __webpack_get_script_filename__ = chunkId => { const filename = oldFn(chunkId); return filename + '.changed'; }; ``` ## Module Federation ### \_\_webpack\_share\_scopes\_\_ This object is used as a shared scope in the remote container and is filled with the provided modules from a host ### \_\_webpack\_init\_sharing\_\_ This method is used to initialize modules of a shared scope in the host container. ## System.js ### \_\_system\_context\_\_ Context from System.js when `output.libraryTarget="system"` ## Rspack ### \_\_rspack\_version\_\_ Current Rspack version, default to version in `@rspack/core/package.json`, can be modified through experiments.rspackFuture.bundlerInfo.version. ```js title=Source __rspack_version__ ``` ```js title=Compiled __webpack_require__.rv; // webpack/runtime/rspack_version __webpack_require__.rv = '0.7.4'; ``` ### \_\_rspack\_unique\_id\_\_ The ID of the current bundler, the value is `bundler={bundler}@{version}`: * `bundler`: Default to `"rspack"` and can be modified through [experiments.rspackFuture.bundlerInfo.bundler](/config/experiments.md#rspackfuturebundlerinfo). * `version`: Default to version in `@rspack/core/package.json` and can be modified through [experiments.rspackFuture.bundlerInfo.version](/config/experiments.md#rspackfuturebundlerinfo). ```js title=Source __rspack_unique_id__ ``` ```js title=Compiled __webpack_require__.ruid; // webpack/runtime/rspack_unique_id __webpack_require__.ruid = 'bundler=rspack@0.7.4'; ``` --- url: /api/runtime-api/hmr.md --- # Hot module replacement Rspack provides the same interface as webpack for implementing HMR. If you have enabled Hot Module Replacement via the [HotModuleReplacementPlugin](/plugins/webpack/hot-module-replacement-plugin.md), its interface will be exposed under the `module.hot` and `import.meta.webpackHot` objects. Note that in ESM, please use `import.meta.webpackHot` instead of `module.hot`. ## Example Typically, you will need to check to see if the interface is accessible, then begin working with it. As an example, here's how you might `accept` an updated module: ```js if (module.hot) { module.hot.accept('./library.js', function () { // Do something with the updated library module... }); } // or if (import.meta.webpackHot) { import.meta.webpackHot.accept('./library.js', function () { // Do something with the updated library module… }); } ``` The following methods are supported by `module.hot` and `import.meta.webpackHot`. ## Module API ### accept Accept updates for the given `dependencies` and fire a `callback` to react to those updates, in addition, you can attach an optional error handler: ```js module.hot.accept( dependencies, // Either a string or an array of strings callback, // Function to fire when the dependencies are updated errorHandler, // (err, {moduleId, dependencyId}) => {} ); // or import.meta.webpackHot.accept( dependencies, // Either a string or an array of strings callback, // Function to fire when the dependencies are updated errorHandler, // (err, {moduleId, dependencyId}) => {} ); ``` When using ESM `import` all imported symbols from `dependencies` are automatically updated. Note: The dependency string must match exactly with the `from` string in the `import`. In some cases `callback` can even be omitted. Using `require()` in the `callback` doesn't make sense here. When using CommonJS you need to update dependencies manually by using `require()` in the `callback`. Omitting the `callback` doesn't make sense here. #### errorHandler for accept `(err, {moduleId, dependencyId}) => {}` * `err`: the error thrown by the callback in second argument or during dependency execution when using ESM dependencies. * `moduleId`: the current module id. * `dependencyId`: the module id of the (first) changed dependency. ### accept (self) Accept updates for itself. ```js module.hot.accept( errorHandler, // Function to handle errors when evaluating the new version ); // or import.meta.webpackHot.accept( errorHandler, // Function to handle errors when evaluating the new version ); ``` When this module or dependencies are updated, this module can be disposed and re-evaluated without informing parents. This makes sense if this module has no exports (or exports are updated in another way). The `errorHandler` is fired when the evaluation of this module (or dependencies) has thrown an exception. #### errorHandler for self accept `(err, {moduleId, module}) => {}` * `err`: the error when evaluating the new version. * `moduleId`: the current module id. * `module`: the current module instance. * `module.hot`: allow to use the HMR API of the errored module instance. A common scenario is to self accept it again. It also makes sense to add a dispose handler to pass data along. Note that the errored module might be already partially executed, so make sure to not get into a inconsistent state. You can use `module.hot.data` to store partial state. * `module.exports`: can be overridden, but be careful since property names might be mangled in production mode. ### decline Reject updates for the given `dependencies` forcing the update to fail with a `'decline'` code. ```js module.hot.decline( dependencies, // Either a string or an array of strings ); // or import.meta.webpackHot.decline( dependencies, // Either a string or an array of strings ); ``` Flag a dependency as not-update-able. This makes sense when changing exports of this dependency can't be handled or handling is not implemented yet. Depending on your HMR management code, an update to these dependencies (or unaccepted dependencies of it) usually causes a full-reload of the page. ### decline (self) Reject updates for itself. ```js module.hot.decline(); // or import.meta.webpackHot.decline(); ``` Flag this module as not-update-able. This makes sense when this module has irreversible side-effects, or HMR handling is not implemented for this module yet. Depending on your HMR management code, an update to this module (or unaccepted dependencies) usually causes a full-reload of the page. ### dispose (or addDisposeHandler) Add a handler which is executed when the current module code is replaced. This should be used to remove any persistent resource you have claimed or created. If you want to transfer state to the updated module, add it to the given `data` parameter. This object will be available at `module.hot.data` after the update. ```js module.hot.dispose(data => { // Clean up and pass data to the updated module... }); // or import.meta.webpackHot.dispose(data => { // Clean up and pass data to the updated module... }); ``` ### invalidate Calling this method will invalidate the current module, which disposes and recreates it when the HMR update is applied. This bubbles like a normal update of this module. `invalidate` can't be self-accepted by this module. When called during the `idle` state, a new HMR update will be created containing this module. HMR will enter the `ready` state. When called during the `ready` or `prepare` state, this module will be added to the current HMR update. When called during the `check` state, this module will be added to the update when an update is available. If no update is available it will create a new update. HMR will enter the `ready` state. When called during the `dispose` or `apply` state, HMR will pick it up after getting out of those states. #### Use cases **Conditional Accepting** A module can accept a dependency, but can call `invalidate` when the change of the dependency is not handleable: ```js import { x, y } from './dep'; import { processX, processY } from 'anotherDep'; const oldY = y; processX(x); export default processY(y); module.hot.accept('./dep', () => { if (y !== oldY) { // This can't be handled, bubble to parent module.hot.invalidate(); return; } // This can be handled processX(x); }); ``` **Conditional self accept** A module can self-accept itself, but can invalidate itself when the change is not handleable: ```js const VALUE = 'constant'; export default VALUE; if ( module.hot.data && module.hot.data.value && module.hot.data.value !== VALUE ) { module.hot.invalidate(); } else { module.hot.dispose(data => { data.value = VALUE; }); module.hot.accept(); } ``` **Triggering custom HMR updates** ```js const moduleId = chooseAModule(); const code = __webpack_modules__[moduleId].toString(); __webpack_modules__[moduleId] = eval(`(${makeChanges(code)})`); if (require.cache[moduleId]) { require.cache[moduleId].hot.invalidate(); module.hot.apply(); } ``` T> When `invalidate` is called, the [`dispose`](#dispose-or-adddisposehandler) handler will be eventually called and fill `module.hot.data`. If [`dispose`](#dispose-or-adddisposehandler) handler is not registered, an empty object will be supplied to `module.hot.data`. W> Do not get caught in an `invalidate` loop, by calling `invalidate` again and again. This will result in stack overflow and HMR entering the `fail` state. ### removeDisposeHandler Remove the handler added via `dispose` or `addDisposeHandler`. ```js module.hot.removeDisposeHandler(callback); // or import.meta.webpackHot.removeDisposeHandler(callback); ``` ## Management API ### status Retrieve the current status of the hot module replacement process. ```js module.hot.status(); // Will return one of the following strings... // or import.meta.webpackHot.status(); ``` | Status | Description | | ------- | ----------------------------------------------------------------------------------- | | idle | The process is waiting for a call to [`check`](#check) | | check | The process is checking for updates | | prepare | The process is getting ready for the update (e.g. downloading the updated module) | | ready | The update is prepared and available | | dispose | The process is calling the `dispose` handlers on the modules that will be replaced | | apply | The process is calling the `accept` handlers and re-executing self-accepted modules | | abort | An update was aborted, but the system is still in its previous state | | fail | An update has thrown an exception and the system's state has been compromised | ### check Test all loaded modules for updates and, if updates exist, `apply` them. ```js module.hot .check(autoApply) .then(outdatedModules => { // outdated modules... }) .catch(error => { // catch errors }); // or import.meta.webpackHot .check(autoApply) .then(outdatedModules => { // outdated modules... }) .catch(error => { // catch errors }); ``` The `autoApply` parameter can either be a boolean or `options` to pass to the `apply` method when called. ### apply Continue the update process (as long as `module.hot.status() === 'ready'`). ```js module.hot .apply(options) .then(outdatedModules => { // outdated modules... }) .catch(error => { // catch errors }); // or import.meta.webpackHot .apply(options) .then(outdatedModules => { // outdated modules... }) .catch(error => { // catch errors }); ``` The optional `options` object can include the following properties: * `ignoreUnaccepted` (boolean): Ignore changes made to unaccepted modules. * `ignoreDeclined` (boolean): Ignore changes made to declined modules. * `ignoreErrored` (boolean): Ignore errors thrown in accept handlers, error handlers and while reevaluating module. * `onDeclined` (function(info)): Notifier for declined modules * `onUnaccepted` (function(info)): Notifier for unaccepted modules * `onAccepted` (function(info)): Notifier for accepted modules * `onDisposed` (function(info)): Notifier for disposed modules * `onErrored` (function(info)): Notifier for errors The `info` parameter will be an object containing some of the following values: ```ts { type: 'self-declined' | 'declined' | 'unaccepted' | 'accepted' | 'disposed' | 'accept-errored' | 'self-accept-errored' | 'self-accept-error-handler-errored', moduleId: 4, // The module in question. dependencyId: 3, // For errors: the module id owning the accept handler. chain: [1, 2, 3, 4], // For declined/accepted/unaccepted: the chain from where the update was propagated. parentId: 5, // For declined: the module id of the declining parent outdatedModules: [1, 2, 3, 4], // For accepted: the modules that are outdated and will be disposed outdatedDependencies: { // For accepted: The location of accept handlers that will handle the update 5: [4] }, error: new Error(...), // For errors: the thrown error originalError: new Error(...) // For self-accept-error-handler-errored: // the error thrown by the module before the error handler tried to handle it. } ``` ### addStatusHandler Register a function to listen for changes in `status`. ```js module.hot.addStatusHandler(status => { // React to the current status... }); // or import.meta.webpackHot.addStatusHandler(status => { // React to the current status... }); ``` Bear in mind that when the status handler returns a `Promise`, the HMR system will wait for the `Promise` to resolve before continuing. ### removeStatusHandler Remove a registered status handler. ```js module.hot.removeStatusHandler(callback); // or import.meta.webpackHot.removeStatusHandler(callback); ``` --- url: /api/javascript-api/compiler.md --- # Compiler ## Compiler methods ### run Start a compilation, and callbacked when the compilation is completed or aborted due to an error. ```ts function run( callback: ( error: Error, // Only including compiler-related errors, such as configuration errors, not including compilation errors stats: Stats, // detailed information generated during the compilation ) => void, options?: { modifiedFiles?: ReadonlySet; // Modified files included in this compilation removedFiles?: ReadonlySet; // Deleted files included in this compilation }, ): void; ``` :::warning If you need to call the `run` method of the same `compiler` object multiple times, please note the following: 1. This API does not support concurrent compilation. Before starting a new compilation, you must call `compiler.close()` in the callback function of `compiler.run` and wait for it to finish. Only then can you proceed with the next `compiler.run` call. Running multiple compilation processes simultaneously can lead to unexpected results in the output files. 2. Rspack's cache invalidation detection relies on the `modifiedFiles` and `removedFiles` parameters. When caching is enabled and you're using a custom watcher to watch file changes, you need to pass these values to Rspack via the `options` parameter. ::: ```js compiler.run((err, stats) => { // Deal with the compiler errors handlerCompilerError(err); // Deal with the compilation errors handlerModuleErrors(stats.toJson().errors); // Deal with the result handleBuildResult(stats); // End this compilation compiler.close(closeErr => { // Start a new compilation compiler.run((err, stats) => {}); }); }); ``` ```ts type Stats = { compilation: Compilation; hash: Readonly; startTime?: number; endTime?: number; hasErrors(): bool; hasWarnings(): bool; toJson(opts?: StatsValue): StatsCompilation; toString(opts?: StatsValue): string; }; ``` ### watch Watching files and directories, start a compilation process after they change, and callbacked every time the compilation is completed or aborted due to an error. ```ts function watch( watchOptions: WatchOptions, // options for starting the watching handler: (error: Error, stats: Stats) => void, // callback when every compilation ends ): Watching; // watching controller ``` :::warning Warning This API only supports one compilation at a time. Please call `compiler.close` in the `compiler.watch` callback and wait for it to finish before executing `compiler.watch` again. Concurrent compilations will damage the output files. ::: ```js const watching = compiler.watch( { aggregateTimeout: 300, poll: undefined, }, (err, stats) => { // Deal with the result handleBuildResult(stats); }, ); ``` The Watching object provides the following methods: * `watch`: * **Type**: `(files: string[], dirs: string[], missing: string[]): void` * **Usage**: Add the files and directories that need to be watched. * `invalidate`: * **Type**: `(callback: () => void): void` * **Usage**: Immediately end this round of watching and start a compilation with the currently recorded file changes, without stopping the watcher. * `suspend`: * **Type**: `(): void` * **Usage**: Enter the state of only watching and will not start a new compilation. * `resume`: * **Type**: `(): void` * **Usage**: Exit the state of only watching and start a compilation with the currently recorded file changes. * `close`: * **Type**: `(callback: () => void): void` * **Usage**: Stop the watcher. > See [watch options](/config/watch.md#watchoptions) for more details. ```ts type Stats = { compilation: Compilation; hash: Readonly; startTime?: number; endTime?: number; hasErrors(): bool; hasWarnings(): bool; toJson(opts?: StatsValue): StatsCompilation; toString(opts?: StatsValue): string; }; ``` ### close Close the current compiler, and handle low-priority tasks such as caching during this period. ```ts function close( callback: (err: Error) => void, // callback after closing ): void; ``` ### getInfrastructureLogger Create a [logger object](/api/javascript-api/logger.md) that is not associated with any compilation, which is used to print global logs. ```ts function getInfrastructureLogger(name: string): Logger; ``` > See [Logger API](/api/javascript-api/logger.md) for more details ```ts type Logger = { getChildLogger: (name: string | (() => string)) => Logger; // create a child logger error(...args: any[]): void; // display errors warn(...args: any[]): void; // display warnings info(...args: any[]): void; // display important information log(...args: any[]): void; // display unimportant information debug(...args: string[]): void; // display debug information assert(assertion: any, ...args: any[]): void; // display errors if assertion failed trace(): void; // display a stack trace clear(): void; // clear all logs status(...args: any[]): void; // display status information group(...args: any[]): void; // start a logging group groupEnd(...args: any[]): void; // end a logging group groupCollapsed(...args: any[]): void; // group logs together profile(label: any): void; // start capturing a profile profileEnd(label: any): void; // end capturing a profile time(label: any): void; // start a timer timeLog(label: any): void; // not end the timer and record the time difference timeEnd(label: any): void; // end the timer and record the time difference timeAggregate(label: any): void; // aggregate capture the time difference timeAggregateEnd(label: any): void; // end the aggregate capturing }; ``` ### getCache Create a cache object to share data in the build process. ```ts function getCache(name: string): CacheFacade; ``` > See [cache object](/api/javascript-api/cache.md) for more details. ```ts type CacheFacade = { getChildCache(name: string): CacheFacade; // create a named child cache object getItemCache(identifier, etag): ItemCacheFacade; // create a cache object for an data item getLazyHashedEtag(obj: HashableObject): Etag; // create a lazy computed etag mergeEtags(a: Etag, b: Etag): Etag; // merge two etags get( // async data getter, callback by function identifier: string, etag: Etag, callback: (err: Error, result: T) => void, ): void; getPromise( // async data getter, callback by promise identifier: string, etag: Etag, ): Promise; store( // async data setter, callback by function identifier: string, etag: Etag, data: T, callback: (err: Error) => void, ): void; storePromise( // async data setter, callback by promise identifier: string, etag: Etag, data: T, ): Promise; provide( // try to get the data, use function to compute if not exists, callback by function identifier: string, etag: Etag, computer: () => T | Promise, callback: (err: Error, result: T) => void, ): void; providePromise( // try to get the data, use function to compute if not exists, callback by function identifier: string, etag: Etag, computer: () => T | Promise, ): Promise; }; ``` ### purgeInputFileSystem Stop the read loop of the input file system, which internally contains a timer and may cause the process to still not be able to exit after calling `compiler.close`. ```ts function purgeInputFileSystem(): void; ``` ### createChildCompiler Allows running another instance of Rspack inside of Rspack. However, as a child with different settings and configurations applied. It copies all hooks and plugins from the parent (or top-level compiler) and creates a child `Compiler` instance. Returns the created `Compiler`. ```ts function createChildCompiler( compilation: Compilation, compilerName: string, compilerIndex: number, outputOptions: OutputOptions, plugins: RspackPlugin[], ): Compiler; ``` > See [compilation object](/api/javascript-api/compilation.md) for more details. ```ts type Compilation = { emitAsset(): void; // add a new asset updateAsset(): void; // update content of the asset renameAsset(): void; // rename the asset deleteAsset(): void; // delete an existing asset getAssets(): Asset[]; // get all assets getAsset(): Asset; // get asset from name getPath(): string; // generate path from template getPathWithInfo(): PathWithInfo; // generate path and asset info from template getStats(): Stats; // get stats object createChildCompiler(): Compiler; // create a child compiler rebuildModule(): void; // run module.build again getLogger(): Logger; // get compilation related logger object getCache(): CacheFacade; // get compilation related cache object options: RspackOptionsNormalized; // the compiler options compiler: Compiler; // current compiler hooks: CompilationHooks; // hooks of compilation hash: string | null; // hash of this compilation fullhash: string | null; // same as 'hash' assets: Record; // mapping from filename to asset content chunkGroups: ChunkGroup[]; // list of chunk groups entrypoints: Map; // mapping from name to entrypoint namedChunkGroups: Map; // mapping named chunk groups modules: Set; // set of all modules chunks: Set; // set of all chunks namedChunks: Map; // mapping of named chunks fileDependencies: CompilationDependencies; // dependent files contextDependencies: CompilationDependencies; // dependent directories missingDependencies: CompilationDependencies; // dependent missing files buildDependencies: CompilationDependencies; // dependent build files errors: RspackError[]; // errors during compilation warnings: RspackError[]; // warnings during compilation }; ``` > See [output options](/config/output.md) for more details. > See [plugins options](/config/plugins.md) for more details ### runAsChild Running the child compiler, which will doing a complete compiling and generate the assets. ```ts function runAsChild( callback( err: Error, // error related to the child compiler entries: Chunk[], // chunks generated by the child compiler compilation: Compilation, // the compilation created by the child compiler ): void; ): void; ``` > See [cache object](/api/javascript-api/cache.md) for more details. ```ts type CacheFacade = { getChildCache(name: string): CacheFacade; // create a named child cache object getItemCache(identifier, etag): ItemCacheFacade; // create a cache object for an data item getLazyHashedEtag(obj: HashableObject): Etag; // create a lazy computed etag mergeEtags(a: Etag, b: Etag): Etag; // merge two etags get( // async data getter, callback by function identifier: string, etag: Etag, callback: (err: Error, result: T) => void, ): void; getPromise( // async data getter, callback by promise identifier: string, etag: Etag, ): Promise; store( // async data setter, callback by function identifier: string, etag: Etag, data: T, callback: (err: Error) => void, ): void; storePromise( // async data setter, callback by promise identifier: string, etag: Etag, data: T, ): Promise; provide( // try to get the data, use function to compute if not exists, callback by function identifier: string, etag: Etag, computer: () => T | Promise, callback: (err: Error, result: T) => void, ): void; providePromise( // try to get the data, use function to compute if not exists, callback by function identifier: string, etag: Etag, computer: () => T | Promise, ): Promise; }; ``` > See [compilation object](/api/javascript-api/compilation.md) for more details. ```ts type Compilation = { emitAsset(): void; // add a new asset updateAsset(): void; // update content of the asset renameAsset(): void; // rename the asset deleteAsset(): void; // delete an existing asset getAssets(): Asset[]; // get all assets getAsset(): Asset; // get asset from name getPath(): string; // generate path from template getPathWithInfo(): PathWithInfo; // generate path and asset info from template getStats(): Stats; // get stats object createChildCompiler(): Compiler; // create a child compiler rebuildModule(): void; // run module.build again getLogger(): Logger; // get compilation related logger object getCache(): CacheFacade; // get compilation related cache object options: RspackOptionsNormalized; // the compiler options compiler: Compiler; // current compiler hooks: CompilationHooks; // hooks of compilation hash: string | null; // hash of this compilation fullhash: string | null; // same as 'hash' assets: Record; // mapping from filename to asset content chunkGroups: ChunkGroup[]; // list of chunk groups entrypoints: Map; // mapping from name to entrypoint namedChunkGroups: Map; // mapping named chunk groups modules: Set; // set of all modules chunks: Set; // set of all chunks namedChunks: Map; // mapping of named chunks fileDependencies: CompilationDependencies; // dependent files contextDependencies: CompilationDependencies; // dependent directories missingDependencies: CompilationDependencies; // dependent missing files buildDependencies: CompilationDependencies; // dependent build files errors: RspackError[]; // errors during compilation warnings: RspackError[]; // warnings during compilation }; ``` ### isChild Whether this compiler is a child compiler. ```ts function isChild(): boolean; ``` ## Compiler properties ### hooks See [compiler hooks](/api/plugin-api/compiler-hooks.md) for more details. ### rspack * **Type:** `typeof rspack` Get the exports of @rspack/core to obtain the associated internal objects. This is especially useful when you cannot directly reference `@rspack/core` or there are multiple Rspack instances. A common example is accessing the [sources](/api/javascript-api/index.md#sources-object) object in a Rspack plugin: ```js const { RawSource } = compiler.rspack.sources; const source = new RawSource('console.log("Hello, world!");'); ``` ### webpack * **Type:** `typeof rspack` Equivalent to `compiler.rspack`, this property is used for compatibility with webpack plugins. If the Rspack plugin you are developing needs to be webpack compatible, you can use this property instead of `compiler.rspack`. ```js console.log(compiler.webpack === compiler.rspack); // true ``` ### name * **Type:** `string` Get the name: * For the root compiler, it is equivalent to [`name`](/config/other-options.md#name). * For the child compiler, it is the value passed into `createChildCompiler`. * For the MultiCompiler and in the KV form, it is the key. ### context Current project root directory: * Created through `new Compiler`, it is the value passed in. * Created through `rspack({})`, it is [context configuration](/config/context.md). ### root * **Type:** `Compiler` Get the root of the child compiler tree. ### options * **Type:** `RspackOptionsNormalized` Get the full options used by this compiler. ### watchMode * **Type:** `boolean` Whether started through `compiler.watch`. ### watching * **Type:** `Watching` Get the watching object, see [watch method](#watch) for more details. ### running * **Type:** `boolean` Whether the compilation is currently being executed. ### inputFileSystem * **Type:** `InputFileSystem` Get the proxy object used for reading from the file system, which has optimizations such as caching inside to reduce duplicate reading of the same file. ```ts import fs from 'fs'; type InputFileSystem = { readFile: typeof fs.readFile; readFileSync: typeof fs.readFileSync; readlink: typeof fs.readlink; readlinkSync: typeof fs.readlinkSync; readdir: typeof fs.readdir; readdirSync: typeof fs.readdirSync; stat: typeof fs.stat; statSync: typeof fs.statSync; lstat: typeof fs.lstat; lstatSync: typeof fs.lstatSync; realpath: typeof fs.realpath; realpathSync: typeof fs.realpathSync; readJson: typeof fs.readJson; readJsonSync: typeof fs.readJsonSync; purge: (arg0?: (string | string[] | Set) | undefined) => void; }; ``` ### outputFileSystem * **Type:** `OutputFileSystem` Get the proxy object used for writing to the file system, `fs` by default. ```ts import fs from 'fs'; type OutputFileSystem = { writeFile: typeof fs.writeFile; mkdir: typeof fs.mkdir; readdir: typeof fs.readdir; rmdir: typeof fs.rmdir; unlink: typeof fs.unlink; stat: typeof fs.stat; lstat: typeof fs.lstat; readFile: typeof fs.readFile; }; ``` ### watchFileSystem * **Type:** `WatchFileSystem` Get the proxy object used for watching files or directories changes, which provides a `watch` method to start watching, and passes in the changed and removed items in the callback. ```ts type WatchFileSystem = { watch( files: string[], directories: string[], missing: string[], startTime: number, options: WatchOptions, callback: ( err: Error | null, fileEntries: Map, contextEntries: Map, changes: Set, removals: Set ): void, callbackUndelayed: ( // Triggered immediately after the first change file: string, time: number ): void; ): { close(): void, pause(): void, getAggregatedChanges(): Set, getAggregatedRemovals(): Set, getFileTimeInfoEntries(): Map, getContextTimeInfoEntries(): Map, getInfo: WatcherInfo } }; ``` ## MultiCompiler The `MultiCompiler` module allows Rspack to run multiple configurations in separate compilers. If the options parameter in the Rspack's JavaScript API is an array of options, Rspack applies separate compilers and calls the callback after all compilers have been executed. ```js const { rspack } = require('@rspack/core'); rspack( [ { entry: './index1.js', output: { filename: 'bundle1.js' } }, { entry: './index2.js', output: { filename: 'bundle2.js' } }, ], (err, stats) => { process.stdout.write(stats.toString() + '\n'); }, ); ``` It can also be created through `new MultiCompiler`: ```js const compiler1 = new Compiler({ /* */ }); const compiler2 = new Compiler({ /* */ }); new MultiCompiler([compiler1, compiler2]); new MultiCompiler([compiler1, compiler2], { parallelism: 1, // the maximum number of parallel compilers }); new MultiCompiler({ name1: compiler1, name2: compiler2, }); ``` `MultiCompiler` also provides some methods and attributes of the `Compiler`. ### MultiCompiler methods #### setDependencies Specify the dependency relationship between the compilers, using `compiler.name` as the identifier, to ensure the execution order of the compilers. ```ts setDependencies(compiler: Compiler, dependencies: string[]): void; ``` #### validateDependencies Check whether the dependency relationship between the compilers is legal. If there is a cycle or a missing dependency, it will trigger the callback. ```ts validateDependencies( callback: (err: Error) => void; // callback when there is an error ): boolean ``` #### run Execute the `run` method of each compiler according to the dependency relationship to start the compilation process. ```ts run( callback: (err: Error, stats: MultiStats) => void, options?: { modifiedFiles?: ReadonlySet; // Modified files included in this compilation removedFiles?: ReadonlySet; // Deleted files included in this compilation }, ): void; ``` #### watch Execute the `watch` method of each compiler according to the dependency relationship to start watching, and start a compilation process after the file changes. ```ts watch( watchOptions: WatchOptions, handler: (err: Error, stats: MultiStats) => void, ): MultiWatching ``` #### close Execute the `close` method of each compiler to close them, and handle low-priority tasks such as caching during this period. ```ts close(callback: (err: Error) => void): void; ``` #### purgeInputFileSystem Execute the `purgeInputFileSystem` of each compiler to stop the read loop of the file system ```ts purgeInputFileSystem(): void; ``` #### getInfrastructureLogger Create a [logger object](/api/javascript-api/logger.md) that is not associated with any compilation, which is used to print global logs. ```ts getInfrastructureLogger(name: string): Logger; ``` > Same with `compilers[0].getInfrastructureLogger()` > See [Logger API](/api/javascript-api/logger.md) for more details ```ts type Logger = { getChildLogger: (name: string | (() => string)) => Logger; // create a child logger error(...args: any[]): void; // display errors warn(...args: any[]): void; // display warnings info(...args: any[]): void; // display important information log(...args: any[]): void; // display unimportant information debug(...args: string[]): void; // display debug information assert(assertion: any, ...args: any[]): void; // display errors if assertion failed trace(): void; // display a stack trace clear(): void; // clear all logs status(...args: any[]): void; // display status information group(...args: any[]): void; // start a logging group groupEnd(...args: any[]): void; // end a logging group groupCollapsed(...args: any[]): void; // group logs together profile(label: any): void; // start capturing a profile profileEnd(label: any): void; // end capturing a profile time(label: any): void; // start a timer timeLog(label: any): void; // not end the timer and record the time difference timeEnd(label: any): void; // end the timer and record the time difference timeAggregate(label: any): void; // aggregate capture the time difference timeAggregateEnd(label: any): void; // end the aggregate capturing }; ``` ### MultiCompiler properties #### compilers * **Type:** `Compiler[]` Get all included compilers. ```ts type Compiler = { hooks: CompilerHooks; inputFileSystem: InputFileSystem | null; outputFileSystem: OutputFileSystem | null; watchFileSystem: WatchFileSystem | null; options: RspackOptionsNormalized; watching: Watching; getInfrastructureLogger(name: string | (() => string)): Logger; getCache(name: string): CacheFacade; watch( watchOptions: Watchpack.WatchOptions, handler: liteTapable.Callback, ): Watching; run(callback: liteTapable.Callback): void; runAsChild( callback: ( err?: null | Error, entries?: Chunk[], compilation?: Compilation, ) => any, ): void; createChildCompiler( compilation: Compilation, compilerName: string, compilerIndex: number, outputOptions: OutputNormalized, plugins: RspackPluginInstance[], ): Compiler; compile(callback: liteTapable.Callback): void; close(callback: (error?: Error | null) => void): void; }; ``` #### options * **Type:** `RspackOptionsNormalized[]` Get all the [full options](/config/index.md) used by the compilers. #### inputFileSystem * **Type:** `InputFileSystem` Set the proxy object used for reading from the file system for each compiler. ```ts import fs from 'fs'; type InputFileSystem = { readFile: typeof fs.readFile; readFileSync: typeof fs.readFileSync; readlink: typeof fs.readlink; readlinkSync: typeof fs.readlinkSync; readdir: typeof fs.readdir; readdirSync: typeof fs.readdirSync; stat: typeof fs.stat; statSync: typeof fs.statSync; lstat: typeof fs.lstat; lstatSync: typeof fs.lstatSync; realpath: typeof fs.realpath; realpathSync: typeof fs.realpathSync; readJson: typeof fs.readJson; readJsonSync: typeof fs.readJsonSync; purge: (arg0?: (string | string[] | Set) | undefined) => void; }; ``` #### outputFileSystem * **Type:** `OutputFileSystem` Set the proxy object used for writing from the file system for each compiler. ```ts import fs from 'fs'; type OutputFileSystem = { writeFile: typeof fs.writeFile; mkdir: typeof fs.mkdir; readdir: typeof fs.readdir; rmdir: typeof fs.rmdir; unlink: typeof fs.unlink; stat: typeof fs.stat; lstat: typeof fs.lstat; readFile: typeof fs.readFile; }; ``` #### watchFileSystem * **Type:** `WatchFileSystem` Set the proxy object used for watching files or directories changes for each compiler. ```ts type WatchFileSystem = { watch( files: string[], directories: string[], missing: string[], startTime: number, options: WatchOptions, callback: ( err: Error | null, fileEntries: Map, contextEntries: Map, changes: Set, removals: Set ): void, callbackUndelayed: ( // Triggered immediately after the first change file: string, time: number ): void; ): { close(): void, pause(): void, getAggregatedChanges(): Set, getAggregatedRemovals(): Set, getFileTimeInfoEntries(): Map, getContextTimeInfoEntries(): Map, getInfo: WatcherInfo } }; ``` #### running * **Type:** `boolean` Whether the compilation is currently being executed. --- url: /api/javascript-api/compilation.md --- # Compilation This page will list the methods and properties available on the compilation object. :::warning Notice In Rspack, the real compilation object runs on the Rust side, and the JavaScript compilation object is only a **proxy object** used to communicate with the Rust compilation object. Therefore, some complex data structures and methods will not be supported on the JavaScript compilation object, the data is **read-only** and the structure may differ from webpack. ::: ## Compilation methods ### emitAsset Emit a new asset, throw an error if the asset has already exists. ```ts emitAsset( filename: string, // filename of the new asset source: Source, // content of the new asset info?: AssetInfo // asset info of the new asset ): void; ``` The following code will add a new asset named `asset-name.js` and will not be compressed: ```js compiler.hooks.thisCompilation.tap('MyPlugin', compilation => { const { RawSource } = compiler.webpack.sources; compilation.hooks.processAssets.tap('MyPlugin', () => { const buffer = Buffer.from( 'i am content of emit asset, do not minimize me', ); const source = new RawSource(buffer, false); compilation.emitAsset('asset-name.js', source, { minimized: true, }); }); }); ``` ```ts type Source = { source(): string | ArrayBuffer; buffer(): Buffer; size(): number; map(options?: MapOptions): RawSourceMap | null; sourceAndMap(options?: MapOptions): SourceAndMapResult; }; ``` ```ts type AssetInfo = { immutable: boolean; minimized: boolean; fullhash: Array; chunkhash: Array; contenthash: Array; sourceFilename?: string; development: boolean; hotModuleReplacement: boolean; javascriptModule?: boolean; related: JsAssetInfoRelated; cssUnusedIdents?: Array; }; ``` ### updateAsset Update an existing asset, throw an error if the asset does not exist. ```ts updateAsset( filename: string, // filename of the updating asset source: Source | ((source: Source) => Source), // the new content or a function returns the new content info?: // the new info or a function returns the new info | AssetInfo | ((assetInfo: AssetInfo) => AssetInfo) ): void; ``` The following code replaces the content of `main.js` and not to minimize it: ```js compiler.hooks.thisCompilation.tap('MyPlugin', compilation => { const { RawSource } = compiler.webpack.sources; compilation.hooks.processAssets.tap('MyPlugin', () => { const updatedSource = new RawSource( `module.exports = "This is the updated"`, ); compilation.updateAsset('main.js', updatedSource, { minimized: true, }); }); }); ``` ```ts type Source = { source(): string | ArrayBuffer; buffer(): Buffer; size(): number; map(options?: MapOptions): RawSourceMap | null; sourceAndMap(options?: MapOptions): SourceAndMapResult; }; ``` ```ts type AssetInfo = { immutable: boolean; minimized: boolean; fullhash: Array; chunkhash: Array; contenthash: Array; sourceFilename?: string; development: boolean; hotModuleReplacement: boolean; javascriptModule?: boolean; related: JsAssetInfoRelated; cssUnusedIdents?: Array; }; ``` ### renameAsset Rename an existing asset. ```ts renameAsset( filename: string, // filename of the renaming asset newFilename: string // new filename ): void; ``` The following code renames the asset named `main.js` to `my-asset-name.js`: ```js compiler.hooks.thisCompilation.tap('MyPlugin', compilation => { compilation.hooks.processAssets.tap('MyPlugin', () => { compilation.renameAsset('main.js', 'my-asset-name.js'); }); }); ``` ### deleteAsset Delete an existing asset. ```ts deleteAsset( filename: string // filename of the deleting asset ): void; ``` The following code will delete the asset named `no-need.js`: ```js compiler.hooks.thisCompilation.tap('MyPlugin', compilation => { compilation.hooks.processAssets.tap('MyPlugin', () => { compilation.deleteAsset('no-need.js'); }); }); ``` ### getAssets Get the list of asset objects. ```ts getAssets(): ReadonlyArray<{ filename: string; source: Source; info: AssetInfo; }>; ``` The following code will print the total size of all assets: ```js compiler.hooks.compilation.tap('MyPlugin', compilation => { compilation.hooks.processAssets.tap('MyPlugin', () => { const assets = compilation.getAssets(); const totalSize = assets.reduce( (total, asset) => total + asset.source.size(), 0, ); console.log(`total size: ${totalSize}`); }); }); ``` ```ts type Source = { source(): string | ArrayBuffer; buffer(): Buffer; size(): number; map(options?: MapOptions): RawSourceMap | null; sourceAndMap(options?: MapOptions): SourceAndMapResult; }; ``` ```ts type AssetInfo = { immutable: boolean; minimized: boolean; fullhash: Array; chunkhash: Array; contenthash: Array; sourceFilename?: string; development: boolean; hotModuleReplacement: boolean; javascriptModule?: boolean; related: JsAssetInfoRelated; cssUnusedIdents?: Array; }; ``` ### getAsset Get the asset object with the specified name. ```ts getAsset( filename: string // filename of the getting asset ): Readonly<{ filename: string; source: Source; info: AssetInfo; }> | void; ``` The following code will print the size of the asset named `main.js`: ```js compiler.hooks.compilation.tap('MyPlugin', compilation => { compilation.hooks.processAssets.tap('MyPlugin', () => { const assetSize = compilation.getAsset('main.js')?.source.size(); console.log(`main size: ${assetSize}`); }); }); ``` ```ts type Source = { source(): string | ArrayBuffer; buffer(): Buffer; size(): number; map(options?: MapOptions): RawSourceMap | null; sourceAndMap(options?: MapOptions): SourceAndMapResult; }; ``` ```ts type AssetInfo = { immutable: boolean; minimized: boolean; fullhash: Array; chunkhash: Array; contenthash: Array; sourceFilename?: string; development: boolean; hotModuleReplacement: boolean; javascriptModule?: boolean; related: JsAssetInfoRelated; cssUnusedIdents?: Array; }; ``` ### getPath Generate path string based on the Filename template, see [Template String](/config/output.md#template-string) for the template rules. ```ts getPath( filename: Filename, // filename template data: PathData = {} // generating path data ): string; ``` The following code will replace the placeholder in the template to generate the path: ```js const path = compilation.getPath('[contenthash]-[fullhash].js', { contentHash: 'some1', hash: 'some2', }); console.log(path); // "some1-some2.js" ``` ```ts type Filename = string | (data: PathData, info: AssetInfo) => string; ``` ```ts type PathData = { filename?: string; hash?: string; contentHash?: string; runtime?: string; url?: string; id?: string; chunk?: JsChunkPathData; }; ``` ### getPathWithInfo Generate path string and asset info based on the Filename template, see [Template String](/config/output.md#template-string). ```ts getPathWithInfo( filename: Filename, // filename template data: PathData = {} // generating path data ): { path: string; info: AssetInfo; }; ``` The following code will replace the placeholder in the template to generate the path and asset info: ```ts const { path, info } = compilation.getPathWithInfo( '[contenthash]-[fullhash].js', { contentHash: 'some1', hash: 'some2', }, ); console.log(path); // "some1-some2.js" console.log(info); /* Object { immutable: true, minimized: false, fullhash: [ 'some2' ], chunkhash: [], contenthash: [ 'some1' ], development: false, hotModuleReplacement: false, related: {}, extras: {} } */ ``` ```ts type Filename = string | (data: PathData, info: AssetInfo) => string; ``` ```ts type PathData = { filename?: string; hash?: string; contentHash?: string; runtime?: string; url?: string; id?: string; chunk?: JsChunkPathData; }; ``` ```ts type AssetInfo = { immutable: boolean; minimized: boolean; fullhash: Array; chunkhash: Array; contenthash: Array; sourceFilename?: string; development: boolean; hotModuleReplacement: boolean; javascriptModule?: boolean; related: JsAssetInfoRelated; cssUnusedIdents?: Array; }; ``` ### getStats Get the stats object of current compilation: ```ts getStats(): Stats; ``` The following code prints the total number of modules: ```js compiler.hooks.emit.tapAsync('MyPlugin', compilation => { const modules = compilation.getStats().toJson({ modules: true }).modules; console.log(`Total modules: ${modules.length}`); }); ``` ```ts type Stats = { compilation: Compilation; hash: Readonly; startTime?: number; endTime?: number; hasErrors(): bool; hasWarnings(): bool; toJson(opts?: StatsValue): StatsCompilation; toString(opts?: StatsValue): string; }; ``` ### createChildCompiler Allows running another instance of Rspack inside of Rspack. However, as a child with different settings and configurations applied. It copies all hooks and plugins from the parent (or top-level compiler) and creates a child `Compiler` instance. Returns the created `Compiler`. ```ts createChildCompiler( name: string, // name for the child `Compiler` outputOptions: OutputNormalized, // Output options object plugins: RspackPluginInstance[] // Plugins that will be applied ): Compiler; ``` The following code will start a child compiler with `child-entry.js` as the entry, and output to `dist/child`: ```js compiler.hooks.make.tap('MyPlugin', compilation => { const childCompiler = compilation.createChildCompiler( 'ChildCompiler', { path: 'dist/child', }, [new compiler.webpack.EntryPlugin(compiler.context, './child-entry.js')], ); childCompiler.compile((err, childCompilation) => {}); }); ``` ```ts type Compiler = { hooks: CompilerHooks; inputFileSystem: InputFileSystem | null; outputFileSystem: OutputFileSystem | null; watchFileSystem: WatchFileSystem | null; options: RspackOptionsNormalized; watching: Watching; getInfrastructureLogger(name: string | (() => string)): Logger; getCache(name: string): CacheFacade; watch( watchOptions: Watchpack.WatchOptions, handler: liteTapable.Callback, ): Watching; run(callback: liteTapable.Callback): void; runAsChild( callback: ( err?: null | Error, entries?: Chunk[], compilation?: Compilation, ) => any, ): void; createChildCompiler( compilation: Compilation, compilerName: string, compilerIndex: number, outputOptions: OutputNormalized, plugins: RspackPluginInstance[], ): Compiler; compile(callback: liteTapable.Callback): void; close(callback: (error?: Error | null) => void): void; }; ``` ### addRuntimeModule Add a custom runtime module to the compilation. ```ts addRuntimeModule( c: Chunk, // the runtime chunk which to add the runtime module m: RuntimeModule, // the runtime module instance to add ): void; ``` The following code will add a runtime module which define `__webpack_require__.mock` to the `"main"` chunk: ```js title="rspack.config.mjs" export default { entry: './index.js', plugins: [ { apply(compiler) { const { RuntimeModule } = compiler.webpack; class CustomRuntimeModule extends RuntimeModule { constructor() { super('custom'); } generate() { const compilation = this.compilation; return ` __webpack_require__.mock = function() { // ... }; `; } } compiler.hooks.thisCompilation.tap('CustomPlugin', compilation => { compilation.hooks.runtimeRequirementInTree .for(RuntimeGlobals.ensureChunkHandlers) .tap('CustomPlugin', (chunk, set) => { if (chunk.name === 'main') { compilation.addRuntimeModule(chunk, new CustomRuntimeModule()); } }); }); }, }, ], }; ``` When implementing a custom runtime module class, the following methods/properties can be overridden to control the behavior of the runtime module: * Pass the `name` and `stage` parameters in the constructor to specify the module name and the insertion stage. * Override the `generate()` method to control the generated code of the module. * Override the `shouldIsolate()` method to control whether the module is wrapped in an IIFE. * Override the `attach()` method to modify the behavior when the module is added. * Modify its `fullHash` or `dependentHash` properties to control whether the module can be cached. ### rebuildModule Triggers a re-build of the module. ```ts rebuildModule( m: Module, // module to be rebuilt f: (err: Error | null, m: Module | null) => void // function to be invoked when the module finishes rebuilding ): void; ``` The following code will rebuild the module ending with `a.js`: ```js compiler.hooks.compilation.tap('MyPlugin', compilation => { compilation.hooks.finishModules.tapPromise('MyPlugin', async modules => { const oldModule = Array.from(modules).find(item => item.resource.endsWith('a.js'), ); compilation.rebuildModule(oldModule, (err, m) => { console.log(`Rebuilt ${m.identifier()}.`); }); }); }); ``` ```ts type Module = { context?: string; resource?: string; request?: string; userRequest?: string; rawRequest?: string; factoryMeta?: JsFactoryMeta; buildInfo: Record; buildMeta: Record; originalSource(): { isRaw: boolean; isBuffer: boolean; source: Buffer; map?: Buffer; } | null; identifier(): string; nameForCondition(): string | null; }; ``` ### getLogger Get a log output utility object with the specified name, which can be used to print logs with unified format in the plugin. ```ts getLogger(name: string | (() => string)): Logger; ``` The following code prints the asset to the debug log in `processAssets`: ```js compiler.hooks.compilation.tap('MyPlugin', compilation => { const logger = compilation.getLogger('MyPlugin'); compilation.hooks.processAssets.tap('MyPlugin', () => { for (const asset of compilation.getAssets()) { logger.debug(`asset name: ${asset.name}`); logger.debug(`asset info: ${asset.info}`); } }); }); ``` > See [Logger API](/api/javascript-api/logger.md) for more details ```ts type Logger = { getChildLogger: (name: string | (() => string)) => Logger; // create a child logger error(...args: any[]): void; // display errors warn(...args: any[]): void; // display warnings info(...args: any[]): void; // display important information log(...args: any[]): void; // display unimportant information debug(...args: string[]): void; // display debug information assert(assertion: any, ...args: any[]): void; // display errors if assertion failed trace(): void; // display a stack trace clear(): void; // clear all logs status(...args: any[]): void; // display status information group(...args: any[]): void; // start a logging group groupEnd(...args: any[]): void; // end a logging group groupCollapsed(...args: any[]): void; // group logs together profile(label: any): void; // start capturing a profile profileEnd(label: any): void; // end capturing a profile time(label: any): void; // start a timer timeLog(label: any): void; // not end the timer and record the time difference timeEnd(label: any): void; // end the timer and record the time difference timeAggregate(label: any): void; // aggregate capture the time difference timeAggregateEnd(label: any): void; // end the aggregate capturing }; ``` ### getCache Get a cache object with the specified name, which can be used for the plugin to share data during multiple compilations. ```ts getCache(name: string): CacheFacade; ``` > See [cache object](/api/javascript-api/cache.md) for more details. ```ts type CacheFacade = { getChildCache(name: string): CacheFacade; // create a named child cache object getItemCache(identifier, etag): ItemCacheFacade; // create a cache object for an data item getLazyHashedEtag(obj: HashableObject): Etag; // create a lazy computed etag mergeEtags(a: Etag, b: Etag): Etag; // merge two etags get( // async data getter, callback by function identifier: string, etag: Etag, callback: (err: Error, result: T) => void, ): void; getPromise( // async data getter, callback by promise identifier: string, etag: Etag, ): Promise; store( // async data setter, callback by function identifier: string, etag: Etag, data: T, callback: (err: Error) => void, ): void; storePromise( // async data setter, callback by promise identifier: string, etag: Etag, data: T, ): Promise; provide( // try to get the data, use function to compute if not exists, callback by function identifier: string, etag: Etag, computer: () => T | Promise, callback: (err: Error, result: T) => void, ): void; providePromise( // try to get the data, use function to compute if not exists, callback by function identifier: string, etag: Etag, computer: () => T | Promise, ): Promise; }; ``` ## Compilation properties ### options **Type**: `RspackOptionsNormalized` The normalized options used by this Compilation, see [Configure Rspack](/config/index.md) for details. ### compiler **Type**: `Compiler` Current [compiler object](/api/javascript-api/index.md). ```ts type Compiler = { hooks: CompilerHooks; inputFileSystem: InputFileSystem | null; outputFileSystem: OutputFileSystem | null; watchFileSystem: WatchFileSystem | null; options: RspackOptionsNormalized; watching: Watching; getInfrastructureLogger(name: string | (() => string)): Logger; getCache(name: string): CacheFacade; watch( watchOptions: Watchpack.WatchOptions, handler: liteTapable.Callback, ): Watching; run(callback: liteTapable.Callback): void; runAsChild( callback: ( err?: null | Error, entries?: Chunk[], compilation?: Compilation, ) => any, ): void; createChildCompiler( compilation: Compilation, compilerName: string, compilerIndex: number, outputOptions: OutputNormalized, plugins: RspackPluginInstance[], ): Compiler; compile(callback: liteTapable.Callback): void; close(callback: (error?: Error | null) => void): void; }; ``` ### hooks The [Compilation hooks](/api/plugin-api/compilation-hooks.md). ### hash/fullhash **Type**: `Readonly` The hash of this compilation. ### assets **Type**: `Record` The mapping from asset filenames and content sources. ```ts type Source = { source(): string | ArrayBuffer; buffer(): Buffer; size(): number; map(options?: MapOptions): RawSourceMap | null; sourceAndMap(options?: MapOptions): SourceAndMapResult; }; ``` ### chunkGroups **Type**: `ReadonlyArray` The list of chunk group objects, with the structure as follows: ```ts type ChunkGroup = { name?: Readonly; // name of this chunk group index?: Readonly; // creating index of chunk group chunks: ReadonlyArray; // chunks in this chunk group origins: ReadonlyArray<{ // where this chunk group is imported module?: Module; request?: string; }>; isInitial(): boolean; // whether this chunk group will be loaded on initial page load getFiles(): ReadonlyArray; // the files contained this chunk group getParents(): ReadonlyArray; // returns the parent chunk groups }; ``` ### entrypoints **Type**: `ReadonlyMap` The mapping from name to entrypoint, which is a special chunk group and include a runtime chunk. ```ts type Entrypoint = { name?: Readonly; // name of this chunk group index?: Readonly; // creating index of chunk group chunks: ReadonlyArray; // chunks in this chunk group origins: ReadonlyArray<{ // the origin request of this entrypoint module?: Module; request?: string; }>; isInitial(): boolean; // whether this chunk group will be loaded on initial page load getFiles(): ReadonlyArray; // the files contained this chunk group getParents(): ReadonlyArray; // returns the parent chunk groups getRuntimeChunk(): Readonly; // get the runtime chunk of this entrypoint (runtime chunk refers to a chunk that contains runtime code. Generally, the runtime chunk and the entrypoint chunk are the same chunk. Only when the runtime is split into a separate chunk via `dependOn` or `optimization.runtimeChunk` do they refer to different chunks) getEntrypointChunk(): Readonly; // get the entrypoint chunk of this entrypoint (entrypoint chunk refers to a chunk that contains entry modules) }; ``` ### namedChunkGroups **Type**: `ReadonlyMap>` The mapping from names to chunk groups. ```ts type ChunkGroup = { name?: Readonly; // name of this chunk group index?: Readonly; // creating index of chunk group chunks: ReadonlyArray; // chunks in this chunk group origins: ReadonlyArray<{ // where this chunk group is imported module?: Module; request?: string; }>; isInitial(): boolean; // whether this chunk group will be loaded on initial page load getFiles(): ReadonlyArray; // the files contained this chunk group getParents(): ReadonlyArray; // returns the parent chunk groups }; ``` ### modules **Type:** `ReadonlySet` List of all modules, with the structure as follows: ```ts type Module = { context?: string; resource?: string; request?: string; userRequest?: string; rawRequest?: string; factoryMeta?: JsFactoryMeta; buildInfo: Record; buildMeta: Record; originalSource(): { isRaw: boolean; isBuffer: boolean; source: Buffer; map?: Buffer; } | null; identifier(): string; nameForCondition(): string | null; }; ``` ### builtModules **Type:** `ReadonlySet` List of built modules that were not be cached, with the structure as follows: ```ts type Module = { context?: string; resource?: string; request?: string; userRequest?: string; rawRequest?: string; factoryMeta?: JsFactoryMeta; buildInfo: Record; buildMeta: Record; originalSource(): { isRaw: boolean; isBuffer: boolean; source: Buffer; map?: Buffer; } | null; identifier(): string; nameForCondition(): string | null; }; ``` ### chunks **Type:** `ReadonlySet` List of all chunks, with the structure as follows: ```ts type Chunk = { auxiliaryFiles: ReadonlySet; canBeInitial(): boolean; chunkReason?: Readonly; contentHash: Readonly>; cssFilenameTemplate?: Readonly; filenameTemplate?: Readonly; files: ReadonlySet; getAllAsyncChunks(): Iterable; getAllInitialChunks(): Iterable; getAllReferencedChunks(): Iterable; getEntryOptions(): EntryOptions | undefined; get groupsIterable(): Iterable; hash?: Readonly; hasRuntime(): boolean; id?: Readonly; idNameHints: ReadonlyArray; ids: ReadonlyArray; isOnlyInitial(): boolean; name?: Readonly; renderedHash?: Readonly; runtime: ReadonlySet; }; ``` ### namedChunks **Type:** `ReadonlyMap>` The mapping from names to chunks. ```ts type Chunk = { auxiliaryFiles: ReadonlySet; canBeInitial(): boolean; chunkReason?: Readonly; contentHash: Readonly>; cssFilenameTemplate?: Readonly; filenameTemplate?: Readonly; files: ReadonlySet; getAllAsyncChunks(): Iterable; getAllInitialChunks(): Iterable; getAllReferencedChunks(): Iterable; getEntryOptions(): EntryOptions | undefined; get groupsIterable(): Iterable; hash?: Readonly; hasRuntime(): boolean; id?: Readonly; idNameHints: ReadonlyArray; ids: ReadonlyArray; isOnlyInitial(): boolean; name?: Readonly; renderedHash?: Readonly; runtime: ReadonlySet; }; ``` ### fileDependencies **Type:** `CompilationDependencies` List of files this compilation depends on. ```ts type CompilationDependencies = { has(dep: string): boolean; add(dep: string): void; addAll(deps: Iterable): void; }; ``` ### contextDependencies **Type:** `CompilationDependencies` List of directories this compilation depends on. ```ts type CompilationDependencies = { has(dep: string): boolean; add(dep: string): void; addAll(deps: Iterable): void; }; ``` ### missingDependencies **Type:** `CompilationDependencies` List of not existing files this compilation depends on. ```ts type CompilationDependencies = { has(dep: string): boolean; add(dep: string): void; addAll(deps: Iterable): void; }; ``` ### buildDependencies **Type:** `CompilationDependencies` List of build dependencies this compilation depends on. ```ts type CompilationDependencies = { has(dep: string): boolean; add(dep: string): void; addAll(deps: Iterable): void; }; ``` ### errors **Type:** `RspackError[]` List of emitted errors during this compilation, with the structure as follows: ```ts type RspackError = { name: string; message: string; moduleIdentifier?: string; file?: string; stack?: string; hideStack?: boolean; }; ``` ### warnings **Type:** `RspackError[]` List of emitted warnings during this compilation. ```ts type RspackError = { name: string; message: string; moduleIdentifier?: string; file?: string; stack?: string; hideStack?: boolean; }; ``` --- url: /api/javascript-api/stats.md --- # Stats The `stats` object that is passed as a second argument of the [`rspack()`](/api/javascript-api/index.md#rspack) callback, is a good source of information about the code compilation process. It includes: * Errors and Warnings (if any) * Timings * Module and Chunk information The `Stats` object provides two important methods: * `toJson()`: Output information in the form of a [Stats JSON](/api/javascript-api/stats-json.md) object, which is often used in analysis tools. * `toString()`: Output information in the form of a string, which is often used in the CLI tools. Rspack also provides `StatsFactory` and `StatsPrinter` to fine-grained control the output object or string. ```txt title=Stats Output Compilation ===============> Stats JSON =================> Stats Output ╰─ StatsFactory ─╯ ╰─ StatsPrinter ─╯ ╰─────────── stats.toJson() ───────────╯ ╰───────────────────────── stats.toString() ──────────────────────────╯ ``` Create a stats object related to a compilation through [`compilation.getStats()`](/api/javascript-api/compilation.md#getstats) or `new Stats(compilation)`. ## Stats methods ### hasErrors Can be used to check if there were errors while compiling. ```ts hasErrors(): boolean; ``` ### hasWarnings Can be used to check if there were warnings while compiling. ```ts hasWarnings(): boolean; ``` ### toJson Return the compilation information in the form of a [Stats JSON](/api/javascript-api/stats-json.md) object. The [Stats configuration](/config/stats.md) can be a string (preset value) or an object for granular control: ```js stats.toJson('minimal'); ``` ```js stats.toJson({ assets: false, hash: true, }); ``` ### toString Return the compilation information in the form of a formatted string (similar to the output of [CLI](/api/cli.md)). ```ts toJson(opts?: StatsValue): string; ``` Options are the same as `stats.toJson(options)` with one addition: ```js stats.toString({ // Add console colors colors: true, }); ``` Here's an example of `stats.toString()` usage: ```js import { rspack } from '@rspack/core'; rspack( { // ... }, (err, stats) => { if (err) { console.error(err); return; } console.log( stats.toString({ chunks: false, // Makes the build much quieter colors: true, // Shows colors in the console }), ); }, ); ``` ## Stats properties ### compilation **Type:** `Compilation` Get the related compilation object. > See [compilation object](/api/javascript-api/compilation.md) for more details. ```ts type Compilation = { emitAsset(): void; // add a new asset updateAsset(): void; // update content of the asset renameAsset(): void; // rename the asset deleteAsset(): void; // delete an existing asset getAssets(): Asset[]; // get all assets getAsset(): Asset; // get asset from name getPath(): string; // generate path from template getPathWithInfo(): PathWithInfo; // generate path and asset info from template getStats(): Stats; // get stats object createChildCompiler(): Compiler; // create a child compiler rebuildModule(): void; // run module.build again getLogger(): Logger; // get compilation related logger object getCache(): CacheFacade; // get compilation related cache object options: RspackOptionsNormalized; // the compiler options compiler: Compiler; // current compiler hooks: CompilationHooks; // hooks of compilation hash: string | null; // hash of this compilation fullhash: string | null; // same as 'hash' assets: Record; // mapping from filename to asset content chunkGroups: ChunkGroup[]; // list of chunk groups entrypoints: Map; // mapping from name to entrypoint namedChunkGroups: Map; // mapping named chunk groups modules: Set; // set of all modules chunks: Set; // set of all chunks namedChunks: Map; // mapping of named chunks fileDependencies: CompilationDependencies; // dependent files contextDependencies: CompilationDependencies; // dependent directories missingDependencies: CompilationDependencies; // dependent missing files buildDependencies: CompilationDependencies; // dependent build files errors: RspackError[]; // errors during compilation warnings: RspackError[]; // warnings during compilation }; ``` ### hash **Type:** `string` Get the hash of this compilation, same as [`Compilation.hash`](/api/javascript-api/compilation.md#hashfullhash). ## MultiStats When using `MultiCompiler` to execute multiple compilation tasks, their compilation stats will be packaged as a `MultiStats` object, which provides similar methods and properties as `Stats`. ### hash **Type:** `string` Get the unique hash after merging the hashes of all compilations. ### hasErrors Used to check if there are errors during the compilation period, and only if there are no errors in all compilations will it return `false`. ```ts hasErrors(): boolean; ``` ### hasWarnings Used to check if there are warnings during the compilation period, and only if there are no warnings in all compilations will it return `false`. ```ts hasWarnings(): boolean; ``` ### toJson According to the [stats configuration](/config/stats.md), generate all the [stats json](/api/javascript-api/stats-json.md) objects, wrap them in the `children` field, and also summarize the `errors` and `warnings`. ```ts toJson(options?: StatsValue): { hash: string; errorsCount: number; warningsCount: number; errors: StatsError[]; warnings: StatsError[]; children: StatsCompilation[]; }; ``` ### toString Concatenate the stats output strings of all compilations according to the [stats configuration](/config/stats.md). ```ts toString(options?: StatsValue): string; ``` ## Stats factory Used to generate the stats json object from the Compilation, and provides hooks for fine-grained control during the generation process. It can be got through [`compilation.hooks.statsFactory`](/api/plugin-api/compilation-hooks.md#statsfactory). Or create a new one by `new StatsFactory()`. ### Hooks See [StatsFactory hooks](/api/plugin-api/stats-hooks.md#statsfactory) for more details. ### create The core method of `StatsFactory`, according to the `type` to specify the current data structure, find and run the corresponding generator to generate the stats json item. ```ts stats = statsFactory.create('compilation', compilation, {}); ``` > The `StatsFactory` object only handles the calling of hooks, and the processing code of the corresponding type can be found in [`DefaultStatsFactoryPlugin`](https://github.com/web-infra-dev/rspack/blob/main/packages/rspack/src/stats/DefaultStatsFactoryPlugin.ts). ## Stats printer Used to generate the output string from the stats json object, and provides hooks for fine-grained control during the generation process. It can be got through [`compilation.hooks.statsPrinter`](/api/plugin-api/compilation-hooks.md#statsprinter). Or create a new one by `new StatsPrinter()`. ### Hooks See [StatsPrinter hooks](/api/plugin-api/stats-hooks.md#statsprinter) for more details. ### print The core method of `StatsPrinter`, according to the type to specify the current data structure, find and run the corresponding generator to generate the output string of the stats item. ```ts stats = statsPrinter.print('compilation', stats, {}); ``` > The `StatsPrinter` object only handles the calling of hooks, and the processing code of the corresponding type can be found in [`DefaultStatsPrinterPlugin`](https://github.com/web-infra-dev/rspack/blob/main/packages/rspack/src/stats/DefaultStatsPrinterPlugin.ts). --- url: /api/javascript-api/stats-json.md --- # Stats JSON While using Rspack, you can use the following command to generate a JSON file of the statistics module information to analyze the module dependency relationship: ```bash # Generate a statistical information JSON file named `compilation-stats.json` $ rspack --json=compilation-stats.json ``` ## Structure The top-level structure of the output object is as follows: ```ts type StatsCompilation = { // Fixed simulated webpack version number for compatibility with plugins version?: string; // Current version number of rspack rspackVersion?: string; // Compilation name name?: string; // Compilation specific hash hash?: string; // Compilation time in milliseconds time?: number; // Compilation build end timestamp builtAt?: number; // The `output.publicPath` in the configuration publicPath?: string; // Path to rspack output directory outputPath?: string; // Chunk name to emitted asset(s) mapping assetsByChunkName?: Record; // List of asset objects, refer to the "Asset Object" assets?: StatsAsset[]; // List of chunk objects, refer to the "Chunk Object" chunks?: StatsChunk[]; // List of module objects, refer to the "Module Object" modules?: StatsModule[]; // Map of entry objects, refer to the "Entry/ChunkGroup Object" entrypoints?: Record; // Map of named chunk groups, refer to the "Entry/ChunkGroup Object" namedChunkGroups?: Record; // List of error objects, refer to the "Error/Warning Object" errors?: StatsError[]; // Number of errors errorsCount?: number; // List of warning objects, refer to the "Error/Warning Object" warnings?: StatsWarnings[]; // Number of warnings warningsCount?: number; }; ``` ## Asset object Each asset object represents an output file emitted from the compilation, and its structure is as follows: ```ts type StatsAsset = { // The `output` filename name: string; // The size of the file in bytes size: number; // Indicates whether or not the asset made it to the `output` directory emitted: boolean; // The chunk IDs this asset related chunks: Array; // The chunks this asset related chunkNames: Array; // The chunk idHints this asset related chunkIdHints: Array; // The chunk IDs this auxiliary asset related auxiliaryChunks: Array; // The chunks this auxiliary asset related auxiliaryChunkNames: Array; // The chunk idHints this auxiliary asset related auxiliaryChunkIdHints: Array; info: { // whether the asset is minimized minimized: boolean; // A flag telling whether the asset is only used for development and doesn't count towards user-facing assets development: boolean; // A flag telling whether the asset ships data for updating an existing application (HMR) hotModuleReplacement: boolean; // sourceFilename when asset was created from a source file (potentially transformed) sourceFilename?: string; // true, if the asset can be long term cached forever (contains a hash) immutable: boolean; // true, when asset is javascript and an ESM javascriptModule?: boolean; // the value(s) of the chunk hash used for this asset chunkHash: Array; // the value(s) of the content hash used for this asset contentHash: Array; }; // related assets, like source-map related: StatsAsset[]; // whether the asset exceeds performance.maxAssetSize isOverSizeLimit?: boolean; }; ``` ## Chunk object Each chunk object represents a group of modules known as a chunk, and its structure is as follows: ```ts type StatsChunk = { // The list of product files contained in the chunk files: Array; // The list of attached product files contained in the chunk auxiliaryFiles: Array; // Chunk ID id?: string; // List of chunk names contained within this chunk names: Array; // The runtime used by the chunk runtime: Array; // Size of the chunk (in bytes) size: number; // Total size of chunk modules group by the output type (in bytes) sizes: Record; // Chunk hash hash?: string; // Whether the chunk contains the rspack runtime entry: boolean; // Whether the chunk is loaded on initial page load or on demand initial: boolean; // Whether the chunk went through Code Generation rendered: boolean; // Parent chunk IDs parents?: Array; // Children chunk IDs children?: Array; // Sibling chunk IDs siblings?: Array; // Chunk create reason when splitting hunks (need to enable `optimization.splitChunks`). reason?: string; // List of idHints of the cache groups hit when splitting chunks (need to enable `optimization.splitChunks`). idHints: Array; // List of origins describing how the given chunk originated origins: Array<{ // Path to the module module: string; // ID of the module moduleId: string; // The identifier of the module moduleIdentifier: string; // Relative path to the module moduleName: string; // Lines of code that generated this chunk loc: string; // The dependency request in the module request: string; }>; // List of modules contained in the chunk, for details, refer to the "Module Object" modules?: Array; }; ``` ## Module object Each module object represents a module in the dependency graph, and its structure is as follows: ```ts type StatsModule = { // Module ID id?: string; // Module source type moduleType: string; // A unique identifier used internally identifier: string; // Path to the actual file name: string; // Estimated size of the module in bytes size: number; // Total size of module group by the output type (in bytes) sizes: Record; // Whether the module went through loaders and parsing built: boolean; // Whether the module went through code generation codeGenerated: boolean; // Whether the module is run during the compilation (you can see it while using css-extract) buildTimeExecuted: boolean; // Whether the module is cached cached: boolean; // Whether the module can be cached cacheable: boolean; // Whether the module is optional, and if it is optional, only a warning will be issued when the module is not found optional: boolean; // Whether the module is dependent by other modules dependent?: boolean; // List of reasons why the module is introduced, similar to the structure of chunk.origins reasons?: Array; // Unique identifier of the parent module issuer?: string; // Parent module ID issuerId?: string; // Path to the actual file of parent module issuerName?: string; // Reference path from the entry to the current module issuerPath: Array; // Absolute path used by the module for conditional matching (usually the resource path) nameForCondition?: string; // The top-down index of the module in the ChunkGroup preOrderIndex?: number; // The bottom-up index of the module in the ChunkGroup postOrderIndex?: number; // The level in module graph depth?: number; // Whether the module is not included by any chunk orphan: boolean; // List of IDs of chunks that contain the module chunks: Array; // List of assets generated by the module assets?: Array; // Whether the module compiles failed failed: boolean; // Number of errors errors: number; // Number of warnings warnings: number; // Used module exports, true indicates that all are used, string[] indicates that some fields are used (need to enable `optimization.usedExports`) usedExports?: null | string[] | boolean; // List of fields exported by the module (need to enable `optimization.providedExports`) providedExports?: null | string[]; // Optimization bailout reasons (need to enable `optimization.concatenateModules`) optimizationBailout?: null | string[]; // If current module is generated by scope hoisting, this is the list of the original modules (need to enable `optimization.concatenateModules`) modules?: Array; // Source code source?: string | Buffer; // The compilation time statistics for each phase (in milliseconds, need to enable `profile`) profile?: { // Finding the module resolving: number; // Compiling the module building: number; }; }; ``` ## Entry/ChunkGroup Object Each entrypoint or chunk group object represents an group of chunks and assets, and its structure is as follows: ```ts type StatsEntrypoints = Record; type StatsNamedChunkGroups = Record; type StatsChunkGroup = { // Name of the entry name: string; // List of IDs of the chunks included chunks: Array; // Assets generated by the chunk group assets: Array<{ // File name name: string; // File size size: number; }>; // Total size of the assets generated by the chunk group assetsSize: number; // Auxiliary assets generated by the chunk group auxiliaryAssets?: Array<{ // File name name: string; // File size size: number; }>; // Total size of the auxiliary assets generated by the chunk group auxiliaryAssetsSize?: number; // Ordered children chunk groups, order by preload/prefetch children?: { // preload children chunk groups preload?: Array; // prefetch children chunk groups prefetch?: Array; }; // Assets of ordered children chunk groups, order by preload/prefetch children?: { // preload assets preload?: Array; // prefetch assets prefetch?: Array; }; // Whether the assets of this entrypoint exceeds performance.maxEntrypointSize isOverSizeLimit?: boolean; }; ``` ## Error/Warning Object Each error or warning object represents an error/warning threw during the build process, and its structure is as follows: ```ts type StatsError = { // Visual message of the error/warning message: string; // Related source file file?: string; // Detail info of the error/warning details?: string; // Stack info of the error/warning stack?: string; // Unique identifier of the module where the error/warning occurs moduleIdentifier?: string; // Relative path of the module where the error/warning occurs moduleName?: string; // ID of the module where the error/warning occurs moduleId?: string; // Module import trace from entry module moduleTrace: Array<{ // parent module origin: { identifier: string; name?: string; id?: string; }; // imported module module: { identifier: string; name?: string; id?: string; }; }>; // ID of the related chunk chunkId?: string; // Name of the related chunk chunkName?: string; // Whether the related chunk is an entry chunk chunkEntry?: boolean; // Whether the related chunk is an initial chunk chunkInitial?: boolean; }; ``` --- url: /api/javascript-api/logger.md --- # Logger Logging output is an additional way to display messages to the end users. Rspack logger is available to [loaders](/guide/features/loader.md) and [plugins](/guide/features/plugin.md). Emitting as part of the [Stats](/api/javascript-api/stats-json.md) and configured by the user in [rspack configuration](/config/index.md). Benefits of custom logging API in Rspack: * Common place to configure the logging display level * Logging output exportable as part of the `stats.json` * Stats presets affect logging output * Plugins can affect logging capturing and display level * When using multiple plugins and loaders they use a common logging solution * CLI, UI tools for Rspack may choose different ways to display logging * Rspack core can emit logging output, e.g. timing data By introducing Rspack logging API we hope to unify the way Rspack plugins and loaders emit logs and allow better ways to inspect build problems. Integrated logging solution supports plugins and loaders developers by improving their development experience. Paves the way for non-CLI Rspack solutions like dashboards or other UIs. :::warning Avoid noise in the log **Avoid noise in the log!** Keep in mind that multiple plugins and loaders are used together. Loaders are usually processing multiple files and are invoked for every file. Choose a logging level as low as possible to keep the log output informative. ::: ## Examples ### In plugin There are two types of logging methods: 1. [compilation.getLogger](/api/javascript-api/compilation.md#getlogger): the content will be stored within the stats, use this when logging is related to the compilation. 2. `compiler.getInfrastructureLogger`: the content will not be stored, used this when logging is outside the compilation cycle. You can use them in your plugin like below: ```js title=MyPlugin.js const PLUGIN_NAME = 'my-plugin'; export class MyRspackPlugin { apply(compiler) { // access Logger from compiler const logger = compiler.getInfrastructureLogger(PLUGIN_NAME); logger.log('log from compiler'); compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => { // access Logger from compilation const logger = compilation.getLogger(PLUGIN_NAME); logger.info('log from compilation'); }); } } ``` ### In loader You can get the logger from loader context like below: ```js title=MyLoader.js module.exports = function (source) { // access Logger from loader const logger = this.getLogger('my-loader'); logger.info('hello Logger'); return source; }; ``` ## Logger API ### Basic API **Type:** `(...args: any[]): void;` Methods are in turn from high to low according to the log level: * `error`: for error messages. * `warn`: for warnings. * `info`: for important information messages. These messages are displayed by default. Only use this for messages that the user really needs to see. * `log`: for unimportant information messages. These messages are displayed only when user had opted-in to see them. * `debug`: for debugging information. These messages are displayed only when user had opted-in to see debug logging for specific modules. While using `compilation.getLogger`, the output level can be controlled by `stats.logging` and `stats.loggingDebug`: ```js title="rspack.config.mjs" export default { plugins: [{ apply(compiler) { compiler.hooks.thisCompilation.tap("test plugin", compilation => { const logger = compilation.getLogger("TEST"); logger.error("I am an error"); logger.warn("I am a warning"); logger.info("I am an information"); logger.log("I am a log"); logger.debug("I am a debug log"); }); } }], stats: { logging: "verbose", loggingDebug: true }, }; ``` ```js title=Output asset main.js 264 bytes [emitted] (name: main) runtime modules 124 bytes 2 modules ./index.js 15 bytes [built] [code generated] DEBUG LOG from TEST I am an error I am a warning I am an information I am a log I am a debug log ``` While using `compiler.getInfrastructureLogger`, the output level can be controlled by `infrastructureLogging.level` and `infrastructureLogging.debug`: ```js title="rspack.config.mjs" export default { plugins: [{ apply(compiler) { compiler.hooks.thisCompilation.tap("test plugin", compilation => { const logger = compiler.getInfrastructureLogger("TEST"); logger.error("I am an error"); logger.warn("I am a warning"); logger.info("I am an information"); logger.log("I am a log"); logger.debug("I am a debug log"); }); } }], infrastructureLogging: { level: "verbose", debug: true }, }; ``` ```js title=Output [TEST] I am an error [TEST] I am a warning [TEST] I am an information [TEST] I am a log [TEST] I am a debug log Rspack compiled successfully in 49 ms ``` ### assert Display errors when assertion is false. * **Level:** `error` * **Type:**: `assert(assertion: any, ...args: any[]): void;` ```js logger.assert(false, "I am an assert error"); logger.assert(true, "Never displayed"); ``` ```js title=Output LOG from TEST I am an assert error ``` ### status Display progress status information, use `console.status` if exists, otherwise fallback to \`console.info. * **Level:** `info` * **Type:** `status(...args: any[]): void` ```js logger.status("status info"); ``` ```js title=Output [TEST] status info ``` ### trace Display a stack trace, only available while using compilation logger and also need to enable the `stats.loggingTrace`. * **Level:** `debug` * **Type:** `trace(): void` ```js logger.trace(); ``` ```js title=Output DEBUG LOG from TEST Trace | at Object.fn | at SyncHook.callAsyncStageRange ``` ### clear Clean all logs, just like `console.clear()`. * **Level:** `log` * **Type:** `clear(): void;` ```js logger.debug("not displayed"); logger.clear(); logger.debug("will displayed"); ``` ```js title=Output [TEST] will displayed ``` ### Group API Includes these methods: * `group(...args: any[]): void`: to group messages. Displayed collapsed like `logger.log`. * `groupEnd(...args: any[]): void`: to end a logging group. * `groupCollapsed(...args: any[]): void`: to group messages together. Displayed collapsed like `logger.log`. Displayed expanded when logging level is set to `'verbose'` or `'debug'`. ```js logger.group("Group"); logger.info("Info"); logger.log("Log"); logger.debug("Debug"); logger.groupCollapsed("Collapsed group"); logger.log("Log inside collapsed group"); logger.group("Inner group"); logger.log("Inner inner message"); logger.groupEnd(); logger.groupEnd(); logger.log("Log"); logger.groupEnd(); logger.log("End"); ``` ```js title=Output <-> [TEST] Group [TEST] Info [TEST] Log [TEST] Debug <-> [TEST] Collapsed group [TEST] Log inside collapsed group <-> [TEST] Inner group [TEST] Inner inner message [TEST] Log [TEST] End ``` ### Time API Includes these methods: * `time(label: any): void`: to start a timer. * `timeLog(label: any): void`: record time difference without ending the timer. * `timeEnd(label: any): void`: to end the timer and record the time difference. * `timeAggregate(label: any): void`: to aggregate capture the time difference. * `timeAggregateEnd(label: any): void`: to end the aggregate capturing and record the total difference. ```js const wait = time => new Promise(resolve => setTimeout(resolve, time)) logger.time("normal"); await wait(100); logger.timeLog("normal"); await wait(100); logger.timeEnd("normal"); for (let i = 10;i--;) { logger.time("aggregate") await wait(i \* 10); logger.timeAggregate("aggregate") } logger.timeAggregateEnd("aggregate") ``` ```js title=Output [TEST] normal: 101.091167 ms [TEST] normal: 202.565 ms [TEST] aggregate: 460.416124 ms ``` ### Profile API Includes these methods: * `profile(label: any): void`: to start capturing a profile. Delegated to `console.profile` when supported. * `profileEnd(label: any): void`: to end capturing a profile. Delegated to `console.profileEnd` when supported. ### Child logger You can also create a child logger with `logger.getChildLogger()`. Child logger has same methods. ```js const logger = compiler.getInfrastructureLogger("TEST"); logger.info("logger info"); const childLogger = logger.getChildLogger("CHILD"); childLogger.info("child logger info"); ``` ```js title=Output [TEST] logger info [TEST/CHILD] child logger info ``` --- url: /api/javascript-api/cache.md --- # Cache When writing Rspack plugins, you can use `compiler.getCache(name: string)` or `compilation.getCache(name: string)` to get the cache object which can share data in the build process. The cache data is stored on the `Compiler`, so it can be used in multiple `Compilation`s in the watch mode. :::warning Notice * Only available when [cache: true](/config/cache.md) which it is enabled in `mode="development"` by default. * Only used for the JavaScript plugins, the Rust cache cannot be accessed. * Only memory cache is provided, persistent cache is not supported yet. ::: ## Example The following code finds out the newly added assets in the `processAssets`: ```js compiler.hooks.compilation.tap('MyPlugin', compilation => { compilation.hooks.processAssets.tapPromise('MyPlugin', async () => { const cache = compilation.getCache('MyPlugin'); const currentAssets = compilation.getAssets().map(i => i.name); const lastAssets = await cache.getPromise('assets', null); if (lastAssets) { for (const asset of currentAssets) { if (!lastAssets.includes(asset)) { console.log(`New asset: ${asset}`); } } } await cache.storePromise('assets', null, currentAssets); }); }); ``` ## Methods ### Caching #### get/getPromise Get cache data asynchronously, callback by function or promise. * **Type:** * `get`: `(identifier: string, etag: Etag | null, callback: (err: Error, result: T) => void): void` * `getPromise`: `(identifier: string, etag: Etag | null): Promise;` * **Arguments:** * identifier: ID of data item * etag: Etag of the data item, can be generated by `getLazyHashedEtag` #### store/storePromise Store cache data asynchronously, callback by function or promise. * **Type:** * `store`: `(identifier: string, etag: Etag | null, data: T, callback: (err: Error) => void): void;` * `storePromise`: `(identifier: string, etag: Etag | null): Promise;` * **Arguments:** * identifier: ID of data item * etag: Etag of the data item, can be generated by `getLazyHashedEtag` #### provide/providePromise Try to get cache data asynchronously, call the computer function to generate when not exists, callback by function or promise. * **Type:** * `provide`: ```ts provide( identifier: string, etag: Etag | null, computer: (fn: (err: Error, result: T) => void) => void, callback: () => T | Promise, ): void; ``` * `providePromise` ```ts providePromise( identifier: string, etag: Etag | null, computer: () => T | Promise, ): Promise; ``` * **Arguments:** * identifier: ID of data item * etag: Etag of the data item, can be generated by `getLazyHashedEtag` * computer: The called generating function when cache is not exists ```js title=MyPlugin.js const createAssetsData = async () => { console.log('only called once'); return compilation.getAssets().map(i => i.name); }; compilation.hooks.processAssets.tapPromise('MyPlugin', async () => { const cache = compilation.getCache('MyPlugin'); console.log(await cache.getPromise('assets', null)); // undefined await cache.providePromise('assets', null, createAssetsData); // call createAssetsData console.log(await cache.getPromise('assets', null)); // ["main.js"] await cache.providePromise('assets', null, createAssetsData); // not call }); ``` ```txt title=Output undefined only called once [ 'main.js' ] ``` ### getLazyHashedEtag/mergeEtags By using the `getLazyHashedEtag` and `mergeEtags` methods, an etag can be created as the unique identifier of the data item. It will not be calculated immediately when created, but rather delayed until it is used, and also can be cached. This can be used to improve performance when complex data objects are used as the unique identifier. * `getLazyHashedEtag`: `(obj: HashableObject): Etag`, calculates the hash of the object to generate the etag as the data identifier, the object needs to implement the `updateHash(hash: Hash)`. * `mergeEtags`: `(a: Etag, b: Etag): Etag`, merges two etags to one. ```js title=MyPlugin.js const cache = compilation.getCache('MyPlugin'); const dataEtag = cache.getLazyHashedEtag({ content: 'a'.repeat(10000), updateHash(hash) { console.log("only called once"); hash.update(this.content); } }); const mergedEtag = cache.mergeEtags(dataEtag, "other etag"); await cache.storePromise("assets", mergedEtag, "cached value"); console.log(await cache.getPromise("assets", mergedEtag)); ``` ```txt title=Output only called once cached value ``` ### getItemCache By using the `getItemCache` method, a cache object for a single data item can be created. This cache object provides simplified data access methods, do not need identifier and etag as arguments any more. * **Type:** `(identifier, etag): ItemCacheFacade` ```ts type ItemCacheFacade = { get(callback: (err: Error, result: T) => void): void; // async data getter, callback by function getPromise(): Promise; // async data getter, callback by promise store(data: T, callback: (err: Error, result: T) => void): void; // async data setter, callback by function storePromise(data: T): Promise; // async data setter, callback by promise provide( // try to get the data, use function to compute if not exists, callback by function computer: (fn: (err: Error, result: T) => void) => void, callback: (err: Error, result: T) => void, ): void; providePromise( // try to get the data, use function to compute if not exists, callback by promise computer: (fn: (err: Error, result: T) => void) => void, ): Promise; }; ``` ```js title=MyPlugin.js const cache = compilation.getCache('MyPlugin'); const itemCache = cache.getItemCache('item'); await itemCache.storePromise('cached value'); console.log(await itemCache.getPromise()); ``` ```txt title=Output cached value ``` ### getChildCache By using the `getChildCache` method, a child cache object can be generated, with its interface being completely consistent, and it can be utilized when there are numerous caches that require grouping for storage. * **Type:** `(name: string): CacheFacade` --- url: /api/javascript-api/swc.md --- # SWC API Rspack uses [SWC](https://swc.rs/) under the hood to transform and minify JavaScript code, and experimentally exposes some SWC JavaScript APIs through `rspack.experiments.swc`. This allows you to directly call SWC methods like `transform` or `minify` without installing the additional [@swc/core](https://www.npmjs.com/package/@swc/core) package. ## Examples Here is a simple example demonstrating how to transform JavaScript code using Rspack: ```js import { rspack } from '@rspack/core'; const { swc } = rspack.experiments; const sourceCode = 'const a: number = 10;'; swc .transform(sourceCode, { filename: 'main.ts', jsc: { parser: { syntax: 'typescript', }, // ...other options }, }) .then(result => { console.log(result.code); }); ``` In addition to using the `swc` API directly, you can also use it in loaders or plugins to help with code transform or minify. ```js title="my-loader.mjs" export default function myLoader(source) { const { swc } = this._compiler.rspack.experiments; const customCode = ` const a = 10; const b = 20; // custom code `; const callback = this.async(); swc .minify(customCode, { compress: true, sourceMap: true, // ...other options }) .then(result => { callback(null, `${result.code}\n${source}`); }); } ``` ## Options The API options accepted by the above APIs are passed to SWC. You can learn more about configuration options in the SWC official documentation: * [SWC Transform API](https://swc.rs/docs/usage/core#transform) - Code transform options * [SWC Minify API](https://swc.rs/docs/usage/core#minify) - Code minify options ```ts declare namespace rspack { namespace experimental { declare const swc: { transform( code: string, options?: TransformOptions, ): Promise; minify(code: string, options?: JsMinifyOptions): Promise; }; declare interface JsMinifyOptions { compress?: TerserCompressOptions | boolean; format?: JsFormatOptions & ToSnakeCaseProperties; mangle?: TerserMangleOptions | boolean; ecma?: TerserEcmaVersion; keep_classnames?: boolean; keep_fnames?: boolean; module?: boolean | 'unknown'; safari10?: boolean; toplevel?: boolean; sourceMap?: boolean; outputPath?: string; inlineSourcesContent?: boolean; } declare interface TransformOptions { filename?: string; sourceMaps?: boolean; jsc?: { parser?: { syntax?: 'ecmascript' | 'typescript'; decorators?: boolean; dynamicImport?: boolean; exportDefaultFrom?: boolean; exportNamespaceFrom?: boolean; importAssertions?: boolean; tsx?: boolean; }; target?: string; loose?: boolean; externalHelpers?: boolean; keepClassNames?: boolean; keepFnName?: boolean; minifySyntax?: boolean; minifyWhitespace?: boolean; minifyIdentifiers?: boolean; }; // ... } declare interface TransformOutput { code: string; map?: string; } } } ``` --- url: /api/loader-api/examples.md --- # Examples The following sections provide some basic examples of the different types of loaders. Note that the `map` and `meta` parameters are optional, see [`this.callback`](#thiscallbackerr-error--null-content-string--buffer-sourcemap-sourcemap-meta-any) below. ## Sync loaders Either `return` or `this.callback` can be used to return the transformed `content` synchronously: ```js title="sync-loader.js" module.exports = function (content, map, meta) { return someSyncOperation(content); }; ``` The `this.callback` method is more flexible as it allows multiple arguments to be passed as opposed to only the `content`. ```js title="sync-loader-with-multiple-results.js" module.exports = function (content, map, meta) { this.callback(null, someSyncOperation(content), map, meta); return; // always return undefined when calling callback() }; ``` ::: info Rspack, internally, will convert loaders into async regardless of it's a synchronous loader for technical and performance reason. ::: ## Async loaders For async loaders, `this.async` is used to retrieve the `callback` function: ```js title="async-loader.js" module.exports = function (content, map, meta) { var callback = this.async(); someAsyncOperation(content, function (err, result) { if (err) return callback(err); callback(null, result, map, meta); }); }; ``` ```js title="async-loader-with-multiple-results.js" module.exports = function (content, map, meta) { var callback = this.async(); someAsyncOperation(content, function (err, result, sourceMaps, meta) { if (err) return callback(err); callback(null, result, sourceMaps, meta); }); }; ``` ## ESM loader Rspack supports ESM loaders, you can write loaders using ESM syntax and export the loader function using `export default`. When writing ESM loaders, the file name needs to end with `.mjs`, or set `type` to `module` in the nearest `package.json`. ```js title="my-loader.mjs" export default function loader(content, map, meta) { // ... } ``` If you need to set options like `raw` or `pitch`, you can use named exports: ```js title="my-loader.mjs" export default function loader(content) { // ... } // Set raw loader export const raw = true; // Add pitch function export function pitch(remainingRequest, precedingRequest, data) { // ... } ``` ::: tip ESM loader and CommonJS loader have the same functionality, but use different module syntax. You can choose the format based on your project needs. ::: ### Write with TypeScript If you write Rspack loader using TypeScript, you can import `LoaderContext` to add types to the loader: ```ts title="my-loader.ts" import type { LoaderContext } from '@rspack/core'; // Declare the type of loader options type MyLoaderOptions = { foo: string; }; export default function myLoader( this: LoaderContext, source: string, ) { const options = this.getOptions(); console.log(options); // { foo: 'bar' } return source; } ``` ## 'Raw' Loader By default, resource files are converted to UTF-8 strings and passed to the loader. loaders can receive raw `Buffer` by setting `raw` to `true`. Each loader can pass its processing results as `String` or `Buffer`, and the Rspack compiler will convert them to and from the loader. ```js title="raw-loader.js" module.exports = function (content) { assert(content instanceof Buffer); // ... }; module.exports.raw = true; ``` ## Pitching loader Loaders are **always** called from right to left. There are some instances where the loader only cares about the **metadata** behind a request and can ignore the results of the previous loader. The `pitch` method on loaders is called from **left to right** before the loaders are actually executed (from right to left). For the following configuration of `use`: ```js title="rspack.config.mjs" export default { //... module: { rules: [ { //... use: ['a-loader', 'b-loader', 'c-loader'], }, ], }, }; ``` These steps would occur: ``` |- a-loader `pitch` |- b-loader `pitch` |- c-loader `pitch` |- requested module is picked up as a dependency |- c-loader normal execution |- b-loader normal execution |- a-loader normal execution ``` Normally, if it the loader is simple enough which only exports the normal stage hook: ```js module.exports = function (source) {}; ``` Then, the pitching stage will be skipped. So why might a loader take advantage of the "pitching" phase? First, the data passed to the pitch method is exposed in the execution phase as well under this.data and could be useful for capturing and sharing information from earlier in the cycle. ```js module.exports = function (content) { return someSyncOperation(content, this.data.value); }; module.exports.pitch = function (remainingRequest, precedingRequest, data) { data.value = 42; }; ``` Second, if a loader delivers a result in the pitch method, the process turns around and skips the remaining loaders. In our example above, if the b-loaders pitch method returned something: ```js module.exports = function (content) { return someSyncOperation(content); }; module.exports.pitch = function (remainingRequest, precedingRequest, data) { if (someCondition()) { return ( 'module.exports = require(' + JSON.stringify('-!' + remainingRequest) + ');' ); } }; ``` The steps above would be shortened to: ``` |- a-loader `pitch` |- b-loader `pitch` returns a module |- a-loader normal execution ``` For a real world example, `style-loader` leverages the second advantage to dispatch requests. Please visit [style-loader](https://github.com/webpack-contrib/style-loader/blob/eb06baeb3ac4e3107732a21170b0a7f358c5423f/src/index.js#L39) for details. --- url: /api/loader-api/context.md --- # Loader context The loader context represents the properties that are available inside of a loader assigned to the `this` property. ## this.addContextDependency() * **Type:** ```ts function addContextDependency(directory: string): void; ``` Add the directory as a dependency for the loader results so that any changes to the files in the directory can be listened to. For example, adding `src/static` as a dependency. When the files in the `src/static` directory change, it will trigger a rebuild. ```js title="loader.js" const path = require('node:path'); module.exports = function loader(source) { this.addContextDependency(path.resolve(this.rootContext, 'src/static')); return source; }; ``` ## this.addDependency() * **Type:** ```ts function addDependency(file: string): void; ``` Add a file as a dependency on the loader results so that any changes to them can be listened to. For example, `sass-loader`, `less-loader` use this trick to recompile when the imported style files change. ```js title="loader.js" const path = require('node:path'); module.exports = function loader(source) { this.addDependency(path.resolve(this.rootContext, 'src/styles/foo.scss')); return source; }; ``` ## this.addMissingDependency() * **Type:** ```ts function addMissingDependency(file: string): void; ``` Add a currently non-existent file as a dependency of the loader result, so that its creation and any changes can be listened. For example, when a new file is created at that path, it will trigger a rebuild. ```js title="loader.js" const path = require('node:path'); module.exports = function loader(source) { this.addMissingDependency( path.resolve(this.rootContext, 'src/dynamic-file.json'), ); return source; }; ``` ## this.async() * **Type:** `() => LoaderContextCallback` Tells Rspack that this loader will be called asynchronously. Returns [this.callback](#thiscallback). ## this.cacheable() * **Type:** ```ts function cacheable(flag: boolean = true): void; ``` A function that sets the cacheable flag. By default, the processing results of the loader are marked as cacheable. Calling this method and passing `false` turns off the loader's ability to cache processing results. ```js title="loader.js" module.exports = function loader(source) { this.cacheable(false); return source; }; ``` ## this.callback() * **Type:** ```ts function callback( err: Error | null, content: string | Buffer, sourceMap?: SourceMap, meta?: any, ): void; ``` A function that can be called synchronously or asynchronously in order to return multiple results. The expected arguments are: 1. The first parameter must be `Error` or `null`, which marks the current module as a compilation failure. 2. The second argument is a `string` or `Buffer`, which indicates the contents of the file after the module has been processed by the loader. 3. The third parameter is a source map that can be processed by the loader. 4. The fourth parameter is ignored by Rspack and can be anything (e.g. some metadata). :::warning In case this function is called, you should return `undefined` to avoid ambiguous loader results. The value passed to `this.callback` will be passed to the next loader in the chain. The `sourceMap` and `meta` parameters are optional. If they are not passed, the next loader will not receive them. ::: ## this.clearDependencies() * **Type:** ```ts function clearDependencies(): void; ``` Removes all dependencies of the loader result. ## this.context * **Type:** `string | null` The directory path of the currently processed module, which changes with the location of each processed module. For example, if the loader is processing `/project/src/components/Button.js`, then the value of `this.context` would be `/project/src/components`. ```js title="loader.js" module.exports = function loader(source) { console.log(this.context); // '/project/src/components' return source; }; ``` If the module being processed is not from the file system, such as a virtual module, then the value of `this.context` is `null`. ## this.loaderIndex * **Type:** `number` The index in the loaders array of the current loader. ## this.data * **Type:** `unknown` A data object shared between the pitch and the normal phase. ## this.dependency() * **Type:** ```ts function dependency(file: string): void; ``` Alias of [this.addDependency()](#thisadddependency). ## this.emitError() * **Type:** ```ts function emitError(error: Error): void; ``` Emit an error. Unlike `throw` and `this.callback(err)` in the loader, it does not mark the current module as a compilation failure, it just adds an error to Rspack's Compilation and displays it on the command line at the end of this compilation. ## this.emitWarning() * **Type:** ```ts function emitWarning(warning: Error): void; ``` Emit a warning. ## this.emitFile() * **Type:** ```ts function emitFile( name: string, content: string | Buffer, sourceMap?: string, assetInfo?: AssetInfo, ): void; ``` Emit a new file. This method allows you to create new files during the loader execution. * Basic example: ```js title="loader.js" module.exports = function loader(source) { // Emit a new file that will be output as `foo.js` in the output directory this.emitFile('foo.js', 'console.log("Hello, world!");'); return source; }; ``` * Example with asset info: ```js title="loader.js" module.exports = function loader(source) { this.emitFile( 'foo.js', 'console.log("Hello, world!");', undefined, // no sourcemap { sourceFilename: this.resourcePath, }, ); return source; }; ``` ## this.fs * **Type:** `InputFileSystem` Access to the `compilation` object's `inputFileSystem` property. ## this.getOptions() * **Type:** ```ts function getOptions(schema?: any): OptionsType; ``` Get the options passed in by the loader's user. For example: ```js title="rspack.config.mjs" export default { module: { rules: [ { test: /\.txt$/, use: { loader: './my-loader.js', options: { foo: 'bar', }, }, }, ], }, }; ``` In `my-loader.js` get the options passed in: ```js title="my-loader.js" module.exports = function myLoader(source) { const options = this.getOptions(); console.log(options); // { foo: 'bar' } return source; }; ``` In TypeScript, you can set the options type through the generic of `LoaderContext`. ```ts title="my-loader.ts" import type { LoaderContext } from '@rspack/core'; type MyLoaderOptions = { foo: string; }; export default function myLoader( this: LoaderContext, source: string, ) { const options = this.getOptions(); console.log(options); // { foo: 'bar' } return source; } ``` :::tip The parameter `schema` is optional and will not be used in Rspack. To provide the best performance, Rspack does not perform the schema validation. If your loader requires schema validation, please call [scheme-utils](https://github.com/webpack/scheme-utils) or other schema validation libraries. ::: ## this.getResolve() * **Type:** ```ts function getResolve(options: ResolveOptions): resolve; ``` Create a resolver like `this.resolve`. ## this.hot * **Type:** `boolean` Whether HMR is enabled. ```js title="loader.js" module.exports = function (source) { console.log(this.hot); // true if HMR is enabled return source; }; ``` ## this.importModule() * **Type:** ```ts interface ImportModuleOptions { /** * Specify a layer in which this module is placed/compiled */ layer?: string; /** * The public path used for the built modules */ publicPath?: PublicPath; /** * Target base uri */ baseUri?: string; } // with callback function importModule( request: string, options: ImportModuleOptions | undefined, callback: (err?: null | Error, exports?: T) => any, ): void; // without callback, return Promise function importModule( request: string, options?: ImportModuleOptions, ): Promise; ``` Compile and execute a module at the build time. This is an alternative lightweight solution for the child compiler. `importModule` will return a Promise if no callback is provided. ```js title="loader.js" const path = require('node:path'); module.exports = async function loader(source) { const modulePath = path.resolve(this.rootContext, 'some-module.ts'); const moduleExports = await this.importModule(modulePath, { // optional options }); const result = someProcessing(source, moduleExports); return result; }; ``` Or you can pass a callback to it. ```js title="loader.js" const path = require('node:path'); module.exports = function loader(source) { const callback = this.async(); const modulePath = path.resolve(this.rootContext, 'some-module.ts'); this.importModule( modulePath, // optional options undefined, (err, moduleExports) => { if (err) { return callback(err); } const result = someProcessing(source, moduleExports); callback(null, result); }, ); }; ``` ## this.query * **Type:** `string | OptionsType` The value depends on the loader configuration: * If the current loader was configured with an options object, `this.query` will point to that object. * If the current loader has no options, but was invoked with a query string, this will be a string starting with `?`. ## this.request * **Type:** `string` The module specifier string after being resolved. For example, if a `resource.js` is processed by `loader1.js` and `loader2.js`, the value of `this.request` will be `/path/to/loader1.js!/path/to/loader2.js!/path/to/resource.js`. ## this.resolve() * **Type:** ```ts function resolve( context: string, request: string, callback: (err: Error | null, result: string) => void, ): void; ``` Resolve a module specifier. * `context` must be the absolute path to a directory. This directory is used as the starting location for resolving. * `request` is the module specifier to be resolved. * `callback` is a callback function that gives the resolved path. ## this.mode * **Type:** `Mode` The value of [`mode`](/config/mode.md) is read when Rspack is run. The possible values are: `'production'`, `'development'`, `'none'` ```js title="loader.js" module.exports = function loader(source) { console.log(this.mode); // 'production' or other values return source; }; ``` ## this.target * **Type:** `Target` The current compilation target. Passed from [`target`](/config/target.md) configuration options. ```js title="loader.js" module.exports = function loader(source) { console.log(this.target); // 'web' or other values return source; }; ``` ## this.utils * **Type:** ```ts type Utils = { absolutify: (context: string, request: string) => string; contextify: (context: string, request: string) => string; createHash: (algorithm?: string) => Hash; }; ``` Access to the following utilities. * `absolutify`: Return a new request string using absolute paths when possible. * `contextify`: Return a new request string avoiding absolute paths when possible. * `createHash`: Return a new Hash object from provided hash function. ```js title="loader.js" module.exports = function (content) { this.utils.contextify( this.context, this.utils.absolutify(this.context, './index.js'), ); this.utils.absolutify(this.context, this.resourcePath); const mainHash = this.utils.createHash( this._compilation.outputOptions.hashFunction, ); mainHash.update(content); mainHash.digest('hex'); return content; }; ``` ## this.resource * **Type:** `string` The path string of the current module. For example `'/abc/resource.js?query#hash'`. ```js title="loader.js" module.exports = function loader(source) { console.log(this.resource); // '/abc/resource.js?query#hash' return source; }; ``` ## this.resourcePath * **Type:** `string` The path string of the current module, excluding the query and fragment parameters. For example `'/abc/resource.js?query#hash'` in `'/abc/resource.js'`. ```js title="loader.js" module.exports = function loader(source) { console.log(this.resourcePath); // '/abc/resource.js' return source; }; ``` ## this.resourceQuery * **Type:** `string` The query parameter for the path string of the current module. For example `'?query'` in `'/abc/resource.js?query#hash'`. ```js title="loader.js" module.exports = function loader(source) { console.log(this.resourceQuery); // '?query' return source; }; ``` ## this.resourceFragment * **Type:** `string` The fragment parameter of the current module's path string. For example `'#hash'` in `'/abc/resource.js?query#hash'`. ```js title="loader.js" module.exports = function loader(source) { console.log(this.resourceFragment); // '#hash' return source; }; ``` ## this.rootContext * **Type:** `string` The base path configured in Rspack config via [context](/config/context.md). ```js title="loader.js" module.exports = function loader(source) { console.log(this.rootContext); // /path/to/project return source; }; ``` ## this.sourceMap * **Type:** `boolean` Tells if source map should be generated. Since generating source maps can be an expensive task, you should check if source maps are actually requested. ## this.getLogger() * **Type:** ```ts function getLogger(name?: string): Logger; ``` Get the logger of this compilation, through which messages can be logged. ## this.version * **Type:** `number` The version number of the loader API. Currently 2. This is useful for providing backwards compatibility. Using the version you can specify custom logic or fallbacks for breaking changes. ## Internal properties :::warning Please note that using internal Rspack properties like `this._compiler` and `this._compilation` will cause your loader to lose its independence. Ideally, loaders should focus on file transformation logic, with deterministic output for given input, without depending on Rspack's internal state. Relying on these internal objects introduces unpredictable behavior, making testing and maintenance more difficult. Therefore, it's recommended to consider using these properties only when there are no other alternatives. ::: ### this.\_compiler * **Type:** `Compiler` Access to the current [Compiler](/api/javascript-api/compiler.md) object of Rspack. ### this.\_compilation * **Type:** `Compilation` Access to the current [Compilation](/api/javascript-api/compilation.md) object of Rspack. --- url: /api/loader-api/inline.md --- # Inline loaders It's possible to specify loaders in an `import` statement, or any equivalent "importing" method. Separate loaders from the resource with `!`. Each part is resolved relative to the current directory. ```js import Styles from 'style-loader!css-loader?modules!./styles.css'; ``` It's possible to override any loaders, preLoaders and postLoaders from the configuration by prefixing the inline `import` statement: * Prefixing with `!` will disable all configured normal loaders ```js import Styles from '!style-loader!css-loader?modules!./styles.css'; ``` * Prefixing with `!!` will disable all configured loaders (preLoaders, loaders, postLoaders) ```js import Styles from '!!style-loader!css-loader?modules!./styles.css'; ``` * Prefixing with `-!` will disable all configured preLoaders and loaders but not postLoaders ```js import Styles from '-!style-loader!css-loader?modules!./styles.css'; ``` Options can be passed with a query parameter, e.g. `?key=value&foo=bar`, or a JSON object, e.g. `?{"key":"value","foo":"bar"}`. --- url: /api/loader-api/inline-match-resource.md --- # Inline matchResource Inline matchResource allows you to dynamically change the matching rules when loading resources. You can set the `matchResource` for a module specifier by prefixing `!=!` to the module specifier. When a `matchResource` is set, it will be used to match with the `module.rules` instead of the original resource. This can be useful if further loaders should be applied to the resource, or if the module type needs to be changed. :::tip It is not recommended to use this syntax in source code. Inline request syntax is intended to only be used by loader generated code. Not following this recommendation will make your code Rspack-specific and non-standard. ::: ## Example ```js title="file.js" /* STYLE: body { background: red; } */ console.log('yep'); ``` A loader could transform the file into the following file and use the `matchResource` to apply the user-specified CSS processing rules: ```js title="file.js (transformed by loader)" import './file.js.css!=!extract-style-loader/getStyles!./file.js'; console.log('yep'); ``` This will add a dependency to `extract-style-loader/getStyles!./file.js` and treat the result as `file.js.css`. Because `module.rules` has a rule matching `/\.css$/` and it will apply to this dependency. The loader could look like this: ```js title="extract-style-loader/index.js" const getStylesLoader = require.resolve('./getStyles'); module.exports = function (source) { if (STYLES_REGEXP.test(source)) { source = source.replace(STYLES_REGEXP, ''); return `import ${JSON.stringify( this.utils.contextify( this.context || this.rootContext, `${this.resource}.css!=!${getStylesLoader}!${this.remainingRequest}`, ), )};${source}`; } return source; }; ``` ```js title="extract-style-loader/getStyles.js" module.exports = function (source) { const match = source.match(STYLES_REGEXP); return match[0]; }; ``` --- url: /api/plugin-api/compiler-hooks.md --- # Compiler hooks ## Overview {` flowchart TD CallRspack("rspack()") --> CreateCompiler("new Compiler()") CreateCompiler --> ApplyNodeEnvPlugin(Apply NodeEnvironmentPlugin) ApplyNodeEnvPlugin --> ApplyDefaultOptions(Apply default options) ApplyDefaultOptions --> ApplyCustomPlugins(Apply custom plugins) ApplyCustomPlugins --> HookEnvironment(hooks.environment) HookEnvironment --> HookAfterEnvironment(hooks.afterEnvironment) HookAfterEnvironment --> ApplyRspackPlugins(Apply internal plugins) ApplyRspackPlugins <--> HookEntryOptions(hooks.entryOption) ApplyRspackPlugins --> HookAfterPlugins(hooks.afterPlugins) HookAfterPlugins --> ResolveOptions(Generate resolve options) ResolveOptions --> HookAfterResolvers(hooks.afterResolvers) HookAfterResolvers --> HookInitialize(hooks.initialize) HookInitialize --> compiler("return compiler") class CallRspack flow-start class compiler flow-end class CreateCompiler,ApplyNodeEnvPlugin,ApplyDefaultOptions,ApplyCustomPlugins,ApplyRspackPlugins,ResolveOptions flow-process class HookEnvironment,HookAfterEnvironment,HookEntryOptions,HookAfterPlugins,HookAfterResolvers,HookInitialize flow-hook `} {` flowchart TD Compile("compiler.compile(callback)") --> CompilationParams("Create module factories") CompilationParams --> HookNormalModuleFactory(hooks.normalModuleFactory) CompilationParams --> HookContextModuleFactory(hooks.contextModuleFactory) CompilationParams --> HookBeforeCompile(hooks.beforeCompile) HookBeforeCompile --> HookCompile(hooks.compile) HookCompile --> Compilation("new Compilation()") Compilation --> HookThisCompilation(hooks.thisCompilation) HookThisCompilation --> HookCompilation(hooks.compilation) HookCompilation --> HookMake(hooks.make) HookMake --> CreateModuleGraph(Create module graph) CreateModuleGraph <--> RunLoaders(Run loaders on modules) CreateModuleGraph --> HookFinishMake(hooks.finishMake) HookFinishMake --> CompilationFinish("compilation.finish()") CompilationFinish --> CompilationSeal("compilation.seal()") CompilationSeal --> HookAfterCompile(hooks.afterCompile) HookAfterCompile --> Callback("callback()") class Compile flow-start class Callback,CloseCallback flow-end class CompilationParams,Compilation,CreateModuleGraph,RunLoaders,CompilationFinish,CompilationSeal flow-process class HookBeforeCompile,HookCompile,HookThisCompilation,HookCompilation,HookMake,HookFinishMake,HookAfterCompile flow-hook class HookNormalModuleFactory,HookContextModuleFactory flow-hook-non-support `} {` flowchart TD WatchCompiler("compiler.watch(options, callback)") --> CreateWatching("new Watching()") RunCompiler("compiler.run(callback)") --> HookBeforeRun(hooks.beforeRun) HookBeforeRun --> HookRun(hooks.run) HookRun --> HookReadRecords(hooks.readRecords) CreateWatching --> HookReadRecords HookReadRecords --> Compile("compiler.compile()") HookWatchRun --> Compile HookReadRecords --> HookWatchRun(hooks.watchRun) Compile --> HookShouldEmit{hooks.shouldEmit} HookShouldEmit --> |true| HookEmit(hooks.emit) HookShouldEmit --> |false| HookDone(hooks.done) HookEmit --> EmitAssets(Emit asset files) EmitAssets <--> HookAssetEmitted(hooks.assetEmitted) EmitAssets --> HookAfterEmit(hooks.afterEmit) HookAfterEmit --> HookNeedAdditionalPass{hooks.needAdditionalPass} HookNeedAdditionalPass --> |true| HookAdditionalDone(hooks.done) HookAdditionalDone --> HookAdditionPass(hooks.additionalPass) HookAdditionPass --> Compile HookNeedAdditionalPass --> |false| HookEmitRecords(hooks.emitRecords) HookEmitRecords --> HookDone HookDone --> HookFailed(hooks.failed) HookFailed --> Callback("callback(err, stats)") Callback --> WatchingWatch("watching.watch()") WatchingWatch --> HookAfterDone(hooks.afterDone) WatchingWatch --> CollectFileChanges("Collect file changes") CollectFileChanges --> HookReadRecords Callback --> HookAfterDone HookAfterDone -.-> CloseCompile("compiler.close(callback)") CloseCompile --> WatchingClose("watching.close()") WatchingClose --> HookWatchClose(hooks.watchClose) HookWatchClose --> CloseCallback("callback()") CloseCallback --> HookShutdown(hooks.shutdown) class RunCompiler,WatchCompiler flow-start class Callback flow-end class Compile,EmitAssets,CollectFileChanges,CreateWatching,WatchingWatch flow-process class HookBeforeRun,HookRun,HookShouldEmit,HookEmit,HookAfterEmit,HookDone,HookFailed,HookAfterDone,HookWatchRun flow-hook class HookReadRecords,HookAssetEmitted,HookNeedAdditionalPass,HookAdditionPass,HookAdditionalDone,HookEmitRecords flow-hook-non-support class CloseCompile flow-start class CloseCallback flow-end class WatchingClose flow-process class HookWatchClose,HookShutdown flow-hook `} ## `environment` Called while preparing the compiler environment, right after initializing the plugins in the configuration file. * **Type:** `SyncHook<[]>` ## `afterEnvironment` Called right after the `environment` hook, when the compiler environment setup is complete. * **Type:** `SyncHook<[]>` ## `entryOption` Called after the [`entry`](/config/entry.md) configuration from Rspack options has been processed. * **Type:** `SyncBailHook<[string, EntryNormalized]>` * **Arguments:** * `string`: same with [`context`](/config/context.md) * `EntryNormalized`: normalized [`entry`](/config/entry.md) ## `afterPlugins` Called after setting up initial set of internal plugins. * **Type:** `SyncHook<[Compiler]>` * **Arguments:** * `Compiler`: current compiler instance ```ts type Compiler = { hooks: CompilerHooks; inputFileSystem: InputFileSystem | null; outputFileSystem: OutputFileSystem | null; watchFileSystem: WatchFileSystem | null; options: RspackOptionsNormalized; watching: Watching; getInfrastructureLogger(name: string | (() => string)): Logger; getCache(name: string): CacheFacade; watch( watchOptions: Watchpack.WatchOptions, handler: liteTapable.Callback, ): Watching; run(callback: liteTapable.Callback): void; runAsChild( callback: ( err?: null | Error, entries?: Chunk[], compilation?: Compilation, ) => any, ): void; createChildCompiler( compilation: Compilation, compilerName: string, compilerIndex: number, outputOptions: OutputNormalized, plugins: RspackPluginInstance[], ): Compiler; compile(callback: liteTapable.Callback): void; close(callback: (error?: Error | null) => void): void; }; ``` ## `afterResolvers` Triggered after resolver setup is complete. * **Type:** `SyncHook<[Compiler]>` * **Arguments:** * `Compiler`: current compiler instance ```ts type Compiler = { hooks: CompilerHooks; inputFileSystem: InputFileSystem | null; outputFileSystem: OutputFileSystem | null; watchFileSystem: WatchFileSystem | null; options: RspackOptionsNormalized; watching: Watching; getInfrastructureLogger(name: string | (() => string)): Logger; getCache(name: string): CacheFacade; watch( watchOptions: Watchpack.WatchOptions, handler: liteTapable.Callback, ): Watching; run(callback: liteTapable.Callback): void; runAsChild( callback: ( err?: null | Error, entries?: Chunk[], compilation?: Compilation, ) => any, ): void; createChildCompiler( compilation: Compilation, compilerName: string, compilerIndex: number, outputOptions: OutputNormalized, plugins: RspackPluginInstance[], ): Compiler; compile(callback: liteTapable.Callback): void; close(callback: (error?: Error | null) => void): void; }; ``` ## `initialize` Called when a compiler object is initialized. * **Type:** `SyncHook<[]>` ## `beforeRun` Adds a hook right before running the compiler. :::note This hook is only triggered when calling [compiler.run()](/api/javascript-api/index.md#compilerrun) (which is used by the `rspack build` command), and will not be executed in watch mode. You can use the [watchRun](#watchrun) hook in watch mode. ::: * **Type:** `AsyncSeriesHook<[Compiler]>` * **Arguments:** * `Compiler`: current compiler instance ```ts type Compiler = { hooks: CompilerHooks; inputFileSystem: InputFileSystem | null; outputFileSystem: OutputFileSystem | null; watchFileSystem: WatchFileSystem | null; options: RspackOptionsNormalized; watching: Watching; getInfrastructureLogger(name: string | (() => string)): Logger; getCache(name: string): CacheFacade; watch( watchOptions: Watchpack.WatchOptions, handler: liteTapable.Callback, ): Watching; run(callback: liteTapable.Callback): void; runAsChild( callback: ( err?: null | Error, entries?: Chunk[], compilation?: Compilation, ) => any, ): void; createChildCompiler( compilation: Compilation, compilerName: string, compilerIndex: number, outputOptions: OutputNormalized, plugins: RspackPluginInstance[], ): Compiler; compile(callback: liteTapable.Callback): void; close(callback: (error?: Error | null) => void): void; }; ``` * **Example:** Sync operation ```js class ExamplePlugin { apply(compiler) { compiler.hooks.beforeRun.tap('ExamplePlugin', compiler => { console.log('Build is about to start...'); }); } } ``` * **Example:** Async operation ```js class ExamplePlugin { apply(compiler) { compiler.hooks.beforeRun.tapPromise( 'ExamplePlugin', (compiler) => { console.log('Build is about to start...'); await someAsyncOperation(); }, ); } } ``` ## `run` Called at the beginning of a build execution. :::note This hook is only triggered when calling [compiler.run()](/api/javascript-api/index.md#compilerrun) (which is used by the `rspack build` command), and will not be executed in watch mode. You can use the [watchRun](#watchrun) hook in watch mode. ::: * **Type:** `AsyncSeriesHook<[Compiler]>` * **Arguments:** * `Compiler`: current compiler instance ```ts type Compiler = { hooks: CompilerHooks; inputFileSystem: InputFileSystem | null; outputFileSystem: OutputFileSystem | null; watchFileSystem: WatchFileSystem | null; options: RspackOptionsNormalized; watching: Watching; getInfrastructureLogger(name: string | (() => string)): Logger; getCache(name: string): CacheFacade; watch( watchOptions: Watchpack.WatchOptions, handler: liteTapable.Callback, ): Watching; run(callback: liteTapable.Callback): void; runAsChild( callback: ( err?: null | Error, entries?: Chunk[], compilation?: Compilation, ) => any, ): void; createChildCompiler( compilation: Compilation, compilerName: string, compilerIndex: number, outputOptions: OutputNormalized, plugins: RspackPluginInstance[], ): Compiler; compile(callback: liteTapable.Callback): void; close(callback: (error?: Error | null) => void): void; }; ``` * **Example:** Sync operation ```js class ExamplePlugin { apply(compiler) { compiler.hooks.beforeRun.tap('ExamplePlugin', compiler => { console.log('Build start...'); }); } } ``` * **Example:** Async operation ```js class ExamplePlugin { apply(compiler) { compiler.hooks.beforeRun.tapPromise( 'ExamplePlugin', (compiler) => { console.log('Build start...'); await someAsyncOperation(); }, ); } } ``` ## `watchRun` Executes a plugin during watch mode after a new compilation is triggered but before the compilation is actually started. You can use `compiler.modifiedFiles` and `compiler.removedFiles` to get the changed file paths and removed file paths. :::note This hook is only triggered when calling [compiler.watch()](/api/javascript-api/index.md#compilerwatch), and will not be called in non-watch mode. You can use the [run](#run) or [beforeRun](#beforerun) hook in non-watch mode. ::: * **Type:** `AsyncSeriesHook<[Compiler]>` * **Arguments:** * `Compiler`: current compiler instance ```ts type Compiler = { hooks: CompilerHooks; inputFileSystem: InputFileSystem | null; outputFileSystem: OutputFileSystem | null; watchFileSystem: WatchFileSystem | null; options: RspackOptionsNormalized; watching: Watching; getInfrastructureLogger(name: string | (() => string)): Logger; getCache(name: string): CacheFacade; watch( watchOptions: Watchpack.WatchOptions, handler: liteTapable.Callback, ): Watching; run(callback: liteTapable.Callback): void; runAsChild( callback: ( err?: null | Error, entries?: Chunk[], compilation?: Compilation, ) => any, ): void; createChildCompiler( compilation: Compilation, compilerName: string, compilerIndex: number, outputOptions: OutputNormalized, plugins: RspackPluginInstance[], ): Compiler; compile(callback: liteTapable.Callback): void; close(callback: (error?: Error | null) => void): void; }; ``` * **Example:** Sync operation ```js class ExamplePlugin { apply(compiler) { compiler.hooks.watchRun.tap('ExamplePlugin', compiler => { const { modifiedFiles, removedFiles } = compiler; if (modifiedFiles) { console.log('Changed files:', Array.from(modifiedFiles)); } if (removedFiles) { console.log('Removed files:', Array.from(removedFiles)); } }); } } ``` * **Example:** Async operation ```js class ExamplePlugin { apply(compiler) { compiler.hooks.watchRun.tapPromise('ExamplePlugin', compiler => { await someAsyncOperation(); }); } } ``` ## `beforeCompile` Executes a plugin after compilation parameters are created. * **Type:** `AsyncSeriesHook<[]>` ## `compile` Called right after `beforeCompile`, before a new compilation is created. * **Type:** `SyncHook<[]>` ## `thisCompilation` Called while initializing the compilation, right before calling the `compilation` hook. * **Type:** `SyncHook<[Compilation]>` * **Arguments:** * `Compilation`: created [compilation](/api/javascript-api/compilation.md) object > See [compilation object](/api/javascript-api/compilation.md) for more details. ```ts type Compilation = { emitAsset(): void; // add a new asset updateAsset(): void; // update content of the asset renameAsset(): void; // rename the asset deleteAsset(): void; // delete an existing asset getAssets(): Asset[]; // get all assets getAsset(): Asset; // get asset from name getPath(): string; // generate path from template getPathWithInfo(): PathWithInfo; // generate path and asset info from template getStats(): Stats; // get stats object createChildCompiler(): Compiler; // create a child compiler rebuildModule(): void; // run module.build again getLogger(): Logger; // get compilation related logger object getCache(): CacheFacade; // get compilation related cache object options: RspackOptionsNormalized; // the compiler options compiler: Compiler; // current compiler hooks: CompilationHooks; // hooks of compilation hash: string | null; // hash of this compilation fullhash: string | null; // same as 'hash' assets: Record; // mapping from filename to asset content chunkGroups: ChunkGroup[]; // list of chunk groups entrypoints: Map; // mapping from name to entrypoint namedChunkGroups: Map; // mapping named chunk groups modules: Set; // set of all modules chunks: Set; // set of all chunks namedChunks: Map; // mapping of named chunks fileDependencies: CompilationDependencies; // dependent files contextDependencies: CompilationDependencies; // dependent directories missingDependencies: CompilationDependencies; // dependent missing files buildDependencies: CompilationDependencies; // dependent build files errors: RspackError[]; // errors during compilation warnings: RspackError[]; // warnings during compilation }; ``` ## `compilation` Runs a plugin after a compilation has been created. * **Type:** `SyncHook<[Compilation]>` * **Arguments:** * `Compilation`: created [compilation](/api/javascript-api/compilation.md) object > See [compilation object](/api/javascript-api/compilation.md) for more details. ```ts type Compilation = { emitAsset(): void; // add a new asset updateAsset(): void; // update content of the asset renameAsset(): void; // rename the asset deleteAsset(): void; // delete an existing asset getAssets(): Asset[]; // get all assets getAsset(): Asset; // get asset from name getPath(): string; // generate path from template getPathWithInfo(): PathWithInfo; // generate path and asset info from template getStats(): Stats; // get stats object createChildCompiler(): Compiler; // create a child compiler rebuildModule(): void; // run module.build again getLogger(): Logger; // get compilation related logger object getCache(): CacheFacade; // get compilation related cache object options: RspackOptionsNormalized; // the compiler options compiler: Compiler; // current compiler hooks: CompilationHooks; // hooks of compilation hash: string | null; // hash of this compilation fullhash: string | null; // same as 'hash' assets: Record; // mapping from filename to asset content chunkGroups: ChunkGroup[]; // list of chunk groups entrypoints: Map; // mapping from name to entrypoint namedChunkGroups: Map; // mapping named chunk groups modules: Set; // set of all modules chunks: Set; // set of all chunks namedChunks: Map; // mapping of named chunks fileDependencies: CompilationDependencies; // dependent files contextDependencies: CompilationDependencies; // dependent directories missingDependencies: CompilationDependencies; // dependent missing files buildDependencies: CompilationDependencies; // dependent build files errors: RspackError[]; // errors during compilation warnings: RspackError[]; // warnings during compilation }; ``` ## `make` Called before the make phase. In the make phase, Rspack will build the module graph starting from the entry, and use the loader to handle each module. * **Type:** `AsyncParallelHook<[Compilation]>` * **Arguments:** * `Compilation`: current [compilation](/api/javascript-api/compilation.md) object > See [compilation object](/api/javascript-api/compilation.md) for more details. ```ts type Compilation = { emitAsset(): void; // add a new asset updateAsset(): void; // update content of the asset renameAsset(): void; // rename the asset deleteAsset(): void; // delete an existing asset getAssets(): Asset[]; // get all assets getAsset(): Asset; // get asset from name getPath(): string; // generate path from template getPathWithInfo(): PathWithInfo; // generate path and asset info from template getStats(): Stats; // get stats object createChildCompiler(): Compiler; // create a child compiler rebuildModule(): void; // run module.build again getLogger(): Logger; // get compilation related logger object getCache(): CacheFacade; // get compilation related cache object options: RspackOptionsNormalized; // the compiler options compiler: Compiler; // current compiler hooks: CompilationHooks; // hooks of compilation hash: string | null; // hash of this compilation fullhash: string | null; // same as 'hash' assets: Record; // mapping from filename to asset content chunkGroups: ChunkGroup[]; // list of chunk groups entrypoints: Map; // mapping from name to entrypoint namedChunkGroups: Map; // mapping named chunk groups modules: Set; // set of all modules chunks: Set; // set of all chunks namedChunks: Map; // mapping of named chunks fileDependencies: CompilationDependencies; // dependent files contextDependencies: CompilationDependencies; // dependent directories missingDependencies: CompilationDependencies; // dependent missing files buildDependencies: CompilationDependencies; // dependent build files errors: RspackError[]; // errors during compilation warnings: RspackError[]; // warnings during compilation }; ``` ## `finishMake` Called after finishing the make phase. In the make phase, Rspack builds the module graph starting from the entry and uses loaders to handle each module. This hook is called when that process completes. * **Type:** `AsyncSeriesHook<[Compilation]>` * **Arguments:** * `Compilation`: current [compilation](/api/javascript-api/compilation.md) object > See [compilation object](/api/javascript-api/compilation.md) for more details. ```ts type Compilation = { emitAsset(): void; // add a new asset updateAsset(): void; // update content of the asset renameAsset(): void; // rename the asset deleteAsset(): void; // delete an existing asset getAssets(): Asset[]; // get all assets getAsset(): Asset; // get asset from name getPath(): string; // generate path from template getPathWithInfo(): PathWithInfo; // generate path and asset info from template getStats(): Stats; // get stats object createChildCompiler(): Compiler; // create a child compiler rebuildModule(): void; // run module.build again getLogger(): Logger; // get compilation related logger object getCache(): CacheFacade; // get compilation related cache object options: RspackOptionsNormalized; // the compiler options compiler: Compiler; // current compiler hooks: CompilationHooks; // hooks of compilation hash: string | null; // hash of this compilation fullhash: string | null; // same as 'hash' assets: Record; // mapping from filename to asset content chunkGroups: ChunkGroup[]; // list of chunk groups entrypoints: Map; // mapping from name to entrypoint namedChunkGroups: Map; // mapping named chunk groups modules: Set; // set of all modules chunks: Set; // set of all chunks namedChunks: Map; // mapping of named chunks fileDependencies: CompilationDependencies; // dependent files contextDependencies: CompilationDependencies; // dependent directories missingDependencies: CompilationDependencies; // dependent missing files buildDependencies: CompilationDependencies; // dependent build files errors: RspackError[]; // errors during compilation warnings: RspackError[]; // warnings during compilation }; ``` ## `afterCompile` Called after the make phase and before the seal phase. In the seal phase, Rspack will create chunk graph from the module graph and then generate the assets. * **Type:** `AsyncSeriesHook<[Compilation]>` * **Arguments:** * `Compilation`: current [compilation](/api/javascript-api/compilation.md) object > See [compilation object](/api/javascript-api/compilation.md) for more details. ```ts type Compilation = { emitAsset(): void; // add a new asset updateAsset(): void; // update content of the asset renameAsset(): void; // rename the asset deleteAsset(): void; // delete an existing asset getAssets(): Asset[]; // get all assets getAsset(): Asset; // get asset from name getPath(): string; // generate path from template getPathWithInfo(): PathWithInfo; // generate path and asset info from template getStats(): Stats; // get stats object createChildCompiler(): Compiler; // create a child compiler rebuildModule(): void; // run module.build again getLogger(): Logger; // get compilation related logger object getCache(): CacheFacade; // get compilation related cache object options: RspackOptionsNormalized; // the compiler options compiler: Compiler; // current compiler hooks: CompilationHooks; // hooks of compilation hash: string | null; // hash of this compilation fullhash: string | null; // same as 'hash' assets: Record; // mapping from filename to asset content chunkGroups: ChunkGroup[]; // list of chunk groups entrypoints: Map; // mapping from name to entrypoint namedChunkGroups: Map; // mapping named chunk groups modules: Set; // set of all modules chunks: Set; // set of all chunks namedChunks: Map; // mapping of named chunks fileDependencies: CompilationDependencies; // dependent files contextDependencies: CompilationDependencies; // dependent directories missingDependencies: CompilationDependencies; // dependent missing files buildDependencies: CompilationDependencies; // dependent build files errors: RspackError[]; // errors during compilation warnings: RspackError[]; // warnings during compilation }; ``` ## `shouldEmit` Called before emitting assets. Should return a boolean telling whether to emit. * **Type:** `SyncBailHook<[Compilation], boolean>` * **Arguments:** * `Compilation`: current [compilation](/api/javascript-api/compilation.md) object > See [compilation object](/api/javascript-api/compilation.md) for more details. ```ts type Compilation = { emitAsset(): void; // add a new asset updateAsset(): void; // update content of the asset renameAsset(): void; // rename the asset deleteAsset(): void; // delete an existing asset getAssets(): Asset[]; // get all assets getAsset(): Asset; // get asset from name getPath(): string; // generate path from template getPathWithInfo(): PathWithInfo; // generate path and asset info from template getStats(): Stats; // get stats object createChildCompiler(): Compiler; // create a child compiler rebuildModule(): void; // run module.build again getLogger(): Logger; // get compilation related logger object getCache(): CacheFacade; // get compilation related cache object options: RspackOptionsNormalized; // the compiler options compiler: Compiler; // current compiler hooks: CompilationHooks; // hooks of compilation hash: string | null; // hash of this compilation fullhash: string | null; // same as 'hash' assets: Record; // mapping from filename to asset content chunkGroups: ChunkGroup[]; // list of chunk groups entrypoints: Map; // mapping from name to entrypoint namedChunkGroups: Map; // mapping named chunk groups modules: Set; // set of all modules chunks: Set; // set of all chunks namedChunks: Map; // mapping of named chunks fileDependencies: CompilationDependencies; // dependent files contextDependencies: CompilationDependencies; // dependent directories missingDependencies: CompilationDependencies; // dependent missing files buildDependencies: CompilationDependencies; // dependent build files errors: RspackError[]; // errors during compilation warnings: RspackError[]; // warnings during compilation }; ``` * **Example:** ```js compiler.hooks.shouldEmit.tap('MyPlugin', compilation => { // return true to emit the output, otherwise false return true; }); ``` ## `emit` Called right before emitting assets to output dir. * **Type:** `AsyncSeriesHook<[Compilation]>` * **Arguments:** * `Compilation`: current [compilation](/api/javascript-api/compilation.md) object > See [compilation object](/api/javascript-api/compilation.md) for more details. ```ts type Compilation = { emitAsset(): void; // add a new asset updateAsset(): void; // update content of the asset renameAsset(): void; // rename the asset deleteAsset(): void; // delete an existing asset getAssets(): Asset[]; // get all assets getAsset(): Asset; // get asset from name getPath(): string; // generate path from template getPathWithInfo(): PathWithInfo; // generate path and asset info from template getStats(): Stats; // get stats object createChildCompiler(): Compiler; // create a child compiler rebuildModule(): void; // run module.build again getLogger(): Logger; // get compilation related logger object getCache(): CacheFacade; // get compilation related cache object options: RspackOptionsNormalized; // the compiler options compiler: Compiler; // current compiler hooks: CompilationHooks; // hooks of compilation hash: string | null; // hash of this compilation fullhash: string | null; // same as 'hash' assets: Record; // mapping from filename to asset content chunkGroups: ChunkGroup[]; // list of chunk groups entrypoints: Map; // mapping from name to entrypoint namedChunkGroups: Map; // mapping named chunk groups modules: Set; // set of all modules chunks: Set; // set of all chunks namedChunks: Map; // mapping of named chunks fileDependencies: CompilationDependencies; // dependent files contextDependencies: CompilationDependencies; // dependent directories missingDependencies: CompilationDependencies; // dependent missing files buildDependencies: CompilationDependencies; // dependent build files errors: RspackError[]; // errors during compilation warnings: RspackError[]; // warnings during compilation }; ``` ## `afterEmit` Called after emitting assets to output directory. * **Type:** `AsyncSeriesHook<[Compilation]>` * **Arguments:** * `Compilation`: current [compilation](/api/javascript-api/compilation.md) object > See [compilation object](/api/javascript-api/compilation.md) for more details. ```ts type Compilation = { emitAsset(): void; // add a new asset updateAsset(): void; // update content of the asset renameAsset(): void; // rename the asset deleteAsset(): void; // delete an existing asset getAssets(): Asset[]; // get all assets getAsset(): Asset; // get asset from name getPath(): string; // generate path from template getPathWithInfo(): PathWithInfo; // generate path and asset info from template getStats(): Stats; // get stats object createChildCompiler(): Compiler; // create a child compiler rebuildModule(): void; // run module.build again getLogger(): Logger; // get compilation related logger object getCache(): CacheFacade; // get compilation related cache object options: RspackOptionsNormalized; // the compiler options compiler: Compiler; // current compiler hooks: CompilationHooks; // hooks of compilation hash: string | null; // hash of this compilation fullhash: string | null; // same as 'hash' assets: Record; // mapping from filename to asset content chunkGroups: ChunkGroup[]; // list of chunk groups entrypoints: Map; // mapping from name to entrypoint namedChunkGroups: Map; // mapping named chunk groups modules: Set; // set of all modules chunks: Set; // set of all chunks namedChunks: Map; // mapping of named chunks fileDependencies: CompilationDependencies; // dependent files contextDependencies: CompilationDependencies; // dependent directories missingDependencies: CompilationDependencies; // dependent missing files buildDependencies: CompilationDependencies; // dependent build files errors: RspackError[]; // errors during compilation warnings: RspackError[]; // warnings during compilation }; ``` ## `done` Called when the compilation has completed. * **Type:** `AsyncSeriesHook` * **Arguments:** * `Stats`: generated stats object ```ts type Stats = { compilation: Compilation; hash: Readonly; startTime?: number; endTime?: number; hasErrors(): bool; hasWarnings(): bool; toJson(opts?: StatsValue): StatsCompilation; toString(opts?: StatsValue): string; }; ``` ## `afterDone` Called after `done` hook. * **Type:** `SyncHook` * **Arguments:** * `Stats`: generated stats object ```ts type Stats = { compilation: Compilation; hash: Readonly; startTime?: number; endTime?: number; hasErrors(): bool; hasWarnings(): bool; toJson(opts?: StatsValue): StatsCompilation; toString(opts?: StatsValue): string; }; ``` ## `failed` Called if the compilation fails. * **Type:** `SyncHook<[Error]>` ## `invalid` Executed when a watching compilation has been invalidated. This hook is not copied to child compilers. * **Type:** `SyncHook<[string | null, number]>` * **Arguments:** * `fileName`: the file path of the invalid file * `changeTime`: the change time of the invalid file When triggering a re-compilation, this hook can be used to get the changed file path and change time, for example: ```ts compiler.hooks.invalid.tap('MyPlugin', (fileName, changeTime) => { console.log(`Changed file: ${fileName}, change time: ${changeTime}`); }); ``` ## `watchClose` Called when a watching compilation has stopped. * **Type:** `SyncHook<[]>` ## `shutdown` Called when the compiler is closing. * **Type:** `AsyncSeriesHook<[]>` --- url: /api/plugin-api/compilation-hooks.md --- # Compilation hooks :::info The main compilation logic of Rspack runs on the Rust side. For factors such as stability, performance, and architecture, after the Rust side compilation objects are transferred to the JavaScript side when using hooks, the modifications on these objects will not be synchronized to the Rust side. Therefore, most of hooks are "read-only". ::: ## Overview {` flowchart TD EntryPlugin("EntryPlugin") --> AddEntry("compilation.addEntry(callback)") AddEntry --> HookAddEntry(hooks.addEntry) subgraph BuildModuleGraph["Create module graph"] HookAddEntry --> FactorizeModule("ModuleFactory.create()") FactorizeModule <--> SideEffectsResolve(Tree shaking module side effects) FactorizeModule <--> Resolve("Resolve module path") FactorizeModule --> BuildModule("compilation.buildModule()") BuildModule --> HookStillValidModule{hooks.stillValidModule} HookStillValidModule --> |true| ProcessDependencies("Process dependencies") HookStillValidModule --> |false| HookBuildModule(hooks.buildModule) HookBuildModule --> ModuleBuild("module.build()") ModuleBuild --> RunLoaders("Run the loaders") RunLoaders --> ParserParse("Parse dependencies") ParserParse --> ModuleBuild ParserParse <--> InnerGraph(Tree shaking inner graph parsing) ParserParse <--> SideEffectsCode(Tree shaking code side effects) ModuleBuild --> |success| HookSucceedModule(hooks.succeedModule) ModuleBuild --> |failed| HookFailedModule(hooks.failedModule) HookSucceedModule --> ProcessDependencies HookFailedModule --> ProcessDependencies ProcessDependencies --> FactorizeModule ProcessDependencies --> |failed| HookFailedEntry(hooks.failedEntry) ProcessDependencies --> |success| HookSucceedEntry(hooks.succeedEntry) HookFailedEntry --> Callback("callback()") HookSucceedEntry --> Callback end class AddEntry flow-start class Callback flow-end class FactorizeModule,Resolve,BuildModule,ProcessDependencies,RunLoaders,ParserParse,ModuleBuild flow-process class InnerGraph,SideEffectsResolve,SideEffectsCode flow-optimization class HookBuildModule,HookSucceedModule flow-hook class HookStillValidModule,HookAddEntry,HookFailedEntry,HookSucceedEntry,HookFailedModule flow-hook-non-support `} {` flowchart TD CompilerCompile("compiler.compile()") --> CompilationFinish("compilation.finish(callback)") CompilationFinish --> HookFinishModules(hooks.finishModules) HookFinishModules <--> FlagDependencyExports(Tree shaking flag module exports) HookFinishModules --> Callback("callback()") class CompilationFinish flow-start class Callback flow-end class FlagDependencyExports flow-optimization class HookFinishModules flow-hook `} {` flowchart TD StatsToString("stats.toString()") --> CreateStatsOptions("compilation.createStatsOptions") CreateStatsOptions --> HookStatsPreset(hooks.statsPreset) HookStatsPreset --> HookStatsNormalize(hooks.statsNormalize) HookStatsNormalize --> CreateStatsOptions CreateStatsOptions --> HookStatsFactory(hooks.statsFactory) HookStatsFactory --> HookStatsPrinter(hooks.statsPrinter) HookStatsPrinter --> StatsJSON("Generate stats JSON") StatsJSON --> StatsOutput("Output stats string") class StatsToString flow-start class StatsOutput flow-end class CreateStatsOptions,StatsJSON flow-process class HookStatsFactory,HookStatsPrinter,HookStatsPreset,HookStatsNormalize flow-hook `} {` flowchart TD subgraph Start direction LR CompilerCompile("compiler.compile()") --> Seal("compilation.seal(callback)") Seal --> HookSeal(hooks.seal) class HookSeal flow-hook end Start --> ChunkGraph subgraph ChunkGraph["Create chunk graph"] direction LR subgraph OptimizeDependencies["Optimize module graph"] direction TB HooksOptimizationDependencies(hooks.optimizeDependencies) <--> FlagUsedExports(Tree shaking flag used exports) HooksOptimizationDependencies --> HookAfterOptimizeDependencies(hooks.afterOptimizeDependencies) class HooksOptimizationDependencies,HookAfterOptimizeDependencies flow-hook-non-support class FlagUsedExports flow-optimization end OptimizeDependencies --> GenerateChunkGraph subgraph GenerateChunkGraph["Generate chunk graph"] direction TB HookBeforeChunks(hooks.beforeChunks) --> CreateEntryChunks("Create entry chunks") CreateEntryChunks --> BuildChunkGraph("Build chunk graph") BuildChunkGraph --> HookAfterChunks(hooks.afterChunks) class HookBeforeChunks,HookAfterChunks flow-hook-non-support class CreateEntryChunks,BuildChunkGraph flow-process class FlagUsedExports flow-optimization end end ChunkGraph --> Optimization subgraph Optimization["Optimize modules and chunks"] direction LR subgraph OptimizeModules["Optimize modules"] direction TB HookOptimize(hooks.optimize) --> HookOptimizeModules(hooks.optimizeModules) HookOptimizeModules --> HookAfterOptimizeModules(hooks.afterOptimizeModules) class HookOptimize flow-hook-non-support class HookOptimizeModules,HookAfterOptimizeModules flow-hook-partial-support end OptimizeModules --> OptimizeChunks["Optimize chunks"] subgraph OptimizeChunks HookOptimizeChunks(hooks.optimizeChunks) <--> SplitChunks(Split chunks) HookOptimizeChunks --> HookAfterOptimizeChunks(hooks.afterOptimizeChunks) class HookOptimizeChunks,HookAfterOptimizeChunks flow-hook-non-support class SplitChunks flow-optimization end OptimizeChunks --> OptimizeTree subgraph OptimizeTree["Optimize chunk groups"] HookOptimizeTree(hooks.optimizeTree) --> HookAfterOptimizeTree(hooks.afterOptimizeTree) class HookOptimizeTree flow-hook-partial-support class HookAfterOptimizeTree flow-hook-non-support end OptimizeTree --> OptimizeChunkModules subgraph OptimizeChunkModules["Optimize modules in chunks"] HookOptimizeChunkModules(hooks.optimizeChunkModules) <--> ModuleConcatenation(Module concatenation) HookOptimizeChunkModules --> HookAfterOptimizeChunkModules(hooks.afterOptimizeChunkModules) HookAfterOptimizeChunkModules --> HookShouldRecord(hooks.shouldRecord) class HookOptimizeChunkModules flow-hook-partial-support class HookShouldRecord,HookAfterOptimizeChunkModules flow-hook-non-support class ModuleConcatenation flow-optimization end end Optimization --> GenerateIds subgraph GenerateIds["Generate IDs of modules and chunks"] direction LR subgraph CreateModuleIds["Generate IDs of modules"] HookReviveModules(hooks.reviveModules) --> HookBeforeModuleIds(hooks.beforeModuleIds) HookBeforeModuleIds --> HookModuleIds(hooks.moduleIds) HookModuleIds --> HookOptimizeModuleIds(hooks.optimizeModuleIds) HookOptimizeModuleIds --> HookAfterOptimizeModuleIds(hooks.afterOptimizeModuleIds) class HookReviveModules,HookModuleIds,HookBeforeModuleIds,HookOptimizeModuleIds,HookAfterOptimizeModuleIds flow-hook-non-support end CreateModuleIds --> CreateChunkIds subgraph CreateChunkIds["Generate IDs of chunks"] HookReviveChunks(hooks.reviveChunks) --> HookBeforeChunkIds(hooks.beforeChunkIds) HookBeforeChunkIds --> HookChunkIds(hooks.moduleIds) HookChunkIds --> HookOptimizeChunkIds(hooks.optimizeChunkIds) HookOptimizeChunkIds --> HookAfterOptimizeChunkIds(hooks.afterOptimizeChunkIds) class HookReviveChunks,HookChunkIds,HookBeforeChunkIds,HookOptimizeChunkIds,HookAfterOptimizeChunkIds flow-hook-non-support end CreateChunkIds --> CreateRecords subgraph CreateRecords["Generate records"] ShouldRecord{"shouldRecord"} --> |true| HookRecordModules(hooks.recordModules) ShouldRecord{"shouldRecord"} --> |false| HookOptimizeCodeGeneration(hooks.optimizeCodeGeneration) HookRecordModules --> HookRecordChunks(hooks.recordChunks) HookRecordChunks --> HookOptimizeCodeGeneration(hooks.optimizeCodeOptions) class ShouldRecord,HookRecordModules,HookRecordChunks,HookOptimizeCodeGeneration flow-hook-non-support class SplitChunks flow-optimization end end GenerateIds --> CodeGeneration subgraph CodeGeneration["Generate code of modules"] direction LR subgraph CreateModuleHashes["Generate hashes of modules"] HookBeforeModuleHash(hooks.beforeModuleHash) --> GenerateModuleHashes("Create module hashes") GenerateModuleHashes --> HookAfterModuleHash(hooks.afterModuleHash) class HookBeforeModuleHash,HookAfterModuleHash flow-hook-non-support class GenerateModuleHashes flow-process end CreateModuleHashes --> ModuleGeneration subgraph ModuleGeneration["Generate code of modules"] HookBeforeModuleCodeGeneration(hooks.beforeModuleCodeGeneration) --> ModuleCodeGeneration("Generate module codes") ModuleCodeGeneration --> HookAfterModuleCodeGeneration(hooks.afterModuleCodeGeneration) class HookBeforeModuleCodeGeneration,HookAfterModuleCodeGeneration flow-hook-non-support class ModuleCodeGeneration flow-process end ModuleGeneration --> CollectRuntimeRequirements subgraph CollectRuntimeRequirements["Collect runtime modules"] HookBeforeRuntime(hooks.beforeRuntimeRequirements) --> HookModuleRuntime(hooks.runtimeRequirementInModule) HookModuleRuntime --> HookAdditionalChunkRuntime(hooks.additionalChunkRuntimeRequirements) HookAdditionalChunkRuntime --> HookChunkRuntime(hooks.runtimeRequirementInChunk) HookChunkRuntime --> HookAdditionalTreeRuntime(hooks.additionalTreeRuntimeRequirements) HookAdditionalTreeRuntime --> HookTreeRuntime(hooks.runtimeRequirementInTree) HookTreeRuntime --> HookAfterRuntimeRequirements(hooks.afterRuntimeRequirements) HookTreeRuntime <--> HookRuntimeModule(hooks.runtimeModule) class HookBeforeRuntime,HookModuleRuntime,HookAdditionalChunkRuntime,HookChunkRuntime,HookAfterRuntimeRequirements, flow-hook-non-support class HookAdditionalTreeRuntime,HookRuntimeModule,HookTreeRuntime flow-hook-partial-support class ModuleCodeGeneration flow-process end CollectRuntimeRequirements --> CompilationHash subgraph CompilationHash["Generate hash of compilation"] HookBeforeHash(hooks.beforeHash) --> CreateHash("Create compilation hash") CreateHash --> HookChunkHash(hooks.chunkHash) HookChunkHash --> HookFullHash(hooks.fullHash) HookFullHash --> CreateHash CreateHash --> HookAfterHash(hooks.afterHash) class HookBeforeHash,HookAfterHash,HookFullHash flow-hook-non-support class HookChunkHash flow-hook-partial-support class CreateHash flow-process end end CodeGeneration --> Assets subgraph Assets["Generate assets"] direction LR subgraph CreateModuleAssets["Generate assets of modules"] ShouldRecord2{"shouldRecord"} --> |true| HookRecordHash(hooks.recordHash) HookRecordHash --> HookBeforeModuleAssets(hooks.beforeModuleAssets) ShouldRecord2{"shouldRecord"} --> |false| HookBeforeModuleAssets HookBeforeModuleAssets --> GenerateModuleAssets("Generate module assets") GenerateModuleAssets <--> HookModuleAsset(hooks.moduleAsset) class ShouldRecord2,HookRecordHash,HookBeforeModuleAssets,HookModuleAsset flow-hook-non-support class GenerateModuleAssets flow-process end CreateModuleAssets --> CreateChunkAssets subgraph CreateChunkAssets["Generate assets of chunks"] HookShouldGenerateChunkAssets{hooks.shouldGenerateChunkAssets} --> |true| HookBeforeChunkAssets(hooks.beforeChunkAssets) HookBeforeChunkAssets --> GenerateChunkAssets("Generate chunk assets") GenerateChunkAssets --> HookRenderManifest(hooks.renderManifest) HookRenderManifest --> HookChunkAsset(hooks.chunkAsset) HookChunkAsset --> GenerateChunkAssets HookShouldGenerateChunkAssets --> |false| HookProcessAssets(hooks.processAssets) class HookBeforeChunkAssets,HookShouldGenerateChunkAssets,HookRenderManifest flow-hook-non-support class HookChunkAsset flow-hook-partial-support class HookProcessAssets flow-hook class GenerateChunkAssets flow-process end CreateChunkAssets --> ProcessAssets subgraph ProcessAssets["Process assets"] HookProcessAssets2(hooks.processAssets) --> HookAfterProcessAssets(hooks.afterProcessAssets) HookAfterProcessAssets --> |shouldRecord=true| HookRecord(hooks.record) class HookProcessAssets2,HookAfterProcessAssets flow-hook class HookRecord flow-hook-non-support end end Assets --> End subgraph End direction LR HookNeedAdditionalSeal --> |true| HookUnseal(hooks.unseal) HookNeedAdditionalSeal --> |false| HookAfterSeal HookUnseal --> Reseal("compilation.seal()") HookAfterSeal(hooks.afterSeal) --> Callback("callback()") class HookAfterSeal flow-hook class HookNeedAdditionalSeal,HookUnseal flow-hook-non-support class Reseal flow-start end End -. additional seal .-> Start class Seal flow-start class Callback flow-end `} ## `buildModule` Triggered before a module build has started. * **Type:** `SyncHook<[Module]>` * **Arguments:** * `Module`: module instance ```ts type Module = { context?: string; resource?: string; request?: string; userRequest?: string; rawRequest?: string; factoryMeta?: JsFactoryMeta; buildInfo: Record; buildMeta: Record; originalSource(): { isRaw: boolean; isBuffer: boolean; source: Buffer; map?: Buffer; } | null; identifier(): string; nameForCondition(): string | null; }; ``` ## `executeModule` If there exists compiled-time execution modules, this hook will be called when they are executed. * **Type:** `SyncHook<[ExecuteModuleArgument, ExecuteModuleContext]>` * **Arguments:** * `ExecuteModuleArgument`: arguments of compiled-time execution module * `ExecuteModuleContext`: context of compiled-time execution module ```ts type ExecuteModuleArgument = { codeGenerationResult: { get(sourceType: string): string; }; moduleObject: { id: string; exports: any; loaded: boolean; error?: Error; }; }; ``` ```ts type ExecuteModuleContext = { __webpack_require__: (id: string) => any; }; ``` ## `succeedModule` Executed when a module has been built successfully. * **Type:** `SyncHook<[Module]>` * **Arguments:** * `Module`: module instance ```ts type Module = { context?: string; resource?: string; request?: string; userRequest?: string; rawRequest?: string; factoryMeta?: JsFactoryMeta; buildInfo: Record; buildMeta: Record; originalSource(): { isRaw: boolean; isBuffer: boolean; source: Buffer; map?: Buffer; } | null; identifier(): string; nameForCondition(): string | null; }; ``` ## `finishModules` Called when all modules have been built without errors. * **Type:** `AsyncSeriesHook<[Module[]]>` * **Arguments:** * `Module[]`: List of module instances ```ts type Module = { context?: string; resource?: string; request?: string; userRequest?: string; rawRequest?: string; factoryMeta?: JsFactoryMeta; buildInfo: Record; buildMeta: Record; originalSource(): { isRaw: boolean; isBuffer: boolean; source: Buffer; map?: Buffer; } | null; identifier(): string; nameForCondition(): string | null; }; ``` ## `seal` Called when the compilation stops accepting new modules and starts to optimize modules. * **Type:** `SyncHook<[]>` ## `optimizeModules` Called at the beginning of the module optimization phase. * **Type:** `SyncBailHook<[Module[]]>` * **Arguments:** * `Module[]`: list of module instances ```ts type Module = { context?: string; resource?: string; request?: string; userRequest?: string; rawRequest?: string; factoryMeta?: JsFactoryMeta; buildInfo: Record; buildMeta: Record; originalSource(): { isRaw: boolean; isBuffer: boolean; source: Buffer; map?: Buffer; } | null; identifier(): string; nameForCondition(): string | null; }; ``` ## `afterOptimizeModules` Called after modules optimization has completed. * **Type:** `SyncBailHook<[Module[]]>` * **Arguments:** * `Module[]`: list of module instances ```ts type Module = { context?: string; resource?: string; request?: string; userRequest?: string; rawRequest?: string; factoryMeta?: JsFactoryMeta; buildInfo: Record; buildMeta: Record; originalSource(): { isRaw: boolean; isBuffer: boolean; source: Buffer; map?: Buffer; } | null; identifier(): string; nameForCondition(): string | null; }; ``` ## `optimizeTree` Called before optimizing the dependency tree. * **Type:** `AsyncSeriesHook<[Chunk[], Module[]]>` * **Arguments:** * `Chunk[]`: list of chunk instances * `Module[]`: list of module instances ```ts type Chunk = { auxiliaryFiles: ReadonlySet; canBeInitial(): boolean; chunkReason?: Readonly; contentHash: Readonly>; cssFilenameTemplate?: Readonly; filenameTemplate?: Readonly; files: ReadonlySet; getAllAsyncChunks(): Iterable; getAllInitialChunks(): Iterable; getAllReferencedChunks(): Iterable; getEntryOptions(): EntryOptions | undefined; get groupsIterable(): Iterable; hash?: Readonly; hasRuntime(): boolean; id?: Readonly; idNameHints: ReadonlyArray; ids: ReadonlyArray; isOnlyInitial(): boolean; name?: Readonly; renderedHash?: Readonly; runtime: ReadonlySet; }; ``` ```ts type Module = { context?: string; resource?: string; request?: string; userRequest?: string; rawRequest?: string; factoryMeta?: JsFactoryMeta; buildInfo: Record; buildMeta: Record; originalSource(): { isRaw: boolean; isBuffer: boolean; source: Buffer; map?: Buffer; } | null; identifier(): string; nameForCondition(): string | null; }; ``` ## `optimizeChunkModules` Called after the tree optimization, at the beginning of the chunk modules optimization. * **Type:** `AsyncSeriesBailHook<[Chunk[], Module[]]>` * **Arguments:** * `Chunk[]`: list of chunk instances * `Module[]`: list of module instances ```ts type Chunk = { auxiliaryFiles: ReadonlySet; canBeInitial(): boolean; chunkReason?: Readonly; contentHash: Readonly>; cssFilenameTemplate?: Readonly; filenameTemplate?: Readonly; files: ReadonlySet; getAllAsyncChunks(): Iterable; getAllInitialChunks(): Iterable; getAllReferencedChunks(): Iterable; getEntryOptions(): EntryOptions | undefined; get groupsIterable(): Iterable; hash?: Readonly; hasRuntime(): boolean; id?: Readonly; idNameHints: ReadonlyArray; ids: ReadonlyArray; isOnlyInitial(): boolean; name?: Readonly; renderedHash?: Readonly; runtime: ReadonlySet; }; ``` ```ts type Module = { context?: string; resource?: string; request?: string; userRequest?: string; rawRequest?: string; factoryMeta?: JsFactoryMeta; buildInfo: Record; buildMeta: Record; originalSource(): { isRaw: boolean; isBuffer: boolean; source: Buffer; map?: Buffer; } | null; identifier(): string; nameForCondition(): string | null; }; ``` ## `additionalTreeRuntimeRequirements` Called after the tree runtime requirements collection. * **Type:** `SyncHook<[Chunk, Set]>` * **Arguments:** * `Chunk`: chunk instance * `Set`: runtime requirements Additional builtin runtime modules can be added here by modifying the runtime requirements set. ```js title="rspack.config.mjs" export default { entry: './index.js', plugins: [ { apply(compiler) { const { RuntimeGlobals } = compiler.webpack; compiler.hooks.thisCompilation.tap('CustomPlugin', compilation => { compilation.hooks.additionalTreeRuntimeRequirements.tap( 'CustomPlugin', (_, set) => { // add a runtime module which define `__webpack_require__.h` set.add(RuntimeGlobals.getFullHash); }, ); }); }, }, ], }; ``` ```js title="index.js" // will print hash of this compilation console.log(__webpack_require__.h); ``` ## `runtimeRequirementInTree` Called during adding runtime modules to the compilation. * **Type:** `HookMap]>>` * **Arguments:** * `Chunk`: chunk instance * `Set`: runtime requirements Additional builtin runtime modules can be added here by modifying the runtime requirements set or calling [`compilation.addRuntimeModule`](/api/javascript-api/compilation.md#addruntimemodule) to add custom runtime modules. ```js title="rspack.config.mjs" export default { entry: './index.js', plugins: [ { apply(compiler) { const { RuntimeGlobals, RuntimeModule } = compiler.webpack; class CustomRuntimeModule extends RuntimeModule { constructor() { super('custom'); } generate() { const compilation = this.compilation; return ` __webpack_require__.mock = function(file) { return ${RuntimeGlobals.publicPath} + "/subpath/" + file; }; `; } } compiler.hooks.thisCompilation.tap('CustomPlugin', compilation => { compilation.hooks.runtimeRequirementInTree .for(RuntimeGlobals.ensureChunkHandlers) .tap('CustomPlugin', (chunk, set) => { // add a runtime module to access public path set.add(RuntimeGlobals.publicPath); compilation.addRuntimeModule(chunk, new CustomRuntimeModule()); }); }); }, }, ], }; ``` ```js title="index.js" // will print "/subpath/index.js" console.log(__webpack_require__.mock('index.js')); ``` ## `runtimeModule` Called after a runtime module is added into the compilation. * **Type:** `SyncHook<[RuntimeModule, Chunk]>` * **Arguments:** * `RuntimeModule`: runtime module instance * `Chunk`: chunk instance Generated code of this runtime module can be modified through its `source` property. ```js title="rspack.config.mjs" export default { plugins: [ { apply(compiler) { const { RuntimeGlobals } = compiler.webpack; compiler.hooks.compilation.tap('CustomPlugin', compilation => { compilation.hooks.runtimeModule.tap( 'CustomPlugin', (module, chunk) => { if (module.name === 'public_path' && chunk.name === 'main') { const originSource = module.source.source.toString('utf-8'); module.source.source = Buffer.from( `${RuntimeGlobals.publicPath} = "/override/public/path";\n`, 'utf-8', ); } }, ); }); }, }, ], }; ``` ```js title="index.js" // will print "/override/public/path" console.log(__webpack_require__.p); ``` ```ts type RuntimeModule = { source?: { isRaw: boolean; isBuffer: boolean; source: Buffer; map?: Buffer; }; moduleIdentifier: string; constructorName: string; name: string; }; ``` ## `processAssets` Process the assets before emit. * **Type:** `AsyncSeriesHook` * **Hook parameters:** * `name: string` — a name of the plugin * `stage: Stage` — a stage to tap into (see the [process assets stages](#process-assets-stages) below) * **Arguments:** * `Assets: Record`: a plain object, where key is the asset's pathname, and the value is data of the asset represented by the [Source](https://github.com/webpack/webpack-sources#source). ```ts type Source = { source(): string | ArrayBuffer; buffer(): Buffer; size(): number; map(options?: MapOptions): RawSourceMap | null; sourceAndMap(options?: MapOptions): SourceAndMapResult; }; ``` ### Process assets examples * Emit a new asset in the `PROCESS_ASSETS_STAGE_ADDITIONAL` stage: ```js compiler.hooks.thisCompilation.tap('MyPlugin', compilation => { const { Compilation } = compiler.webpack; compilation.hooks.processAssets.tap( { name: 'MyPlugin', stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL, }, assets => { const { RawSource } = compiler.webpack.sources; const source = new RawSource('This is a new asset!'); compilation.emitAsset('new-asset.txt', source); }, ); }); ``` * Updating an existing asset: ```js compiler.hooks.thisCompilation.tap('MyPlugin', compilation => { const { Compilation } = compiler.webpack; compilation.hooks.processAssets.tap( { name: 'MyPlugin', stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS, }, assets => { const asset = assets['foo.js']; if (!asset) { return; } const { RawSource } = compiler.webpack.sources; const oldContent = asset.source(); const newContent = oldContent + '\nconsole.log("hello world!")'; const source = new RawSource(newContent); compilation.updateAsset(assetName, source); }, ); }); ``` * Removing an asset: ```js compiler.hooks.thisCompilation.tap('MyPlugin', compilation => { const { Compilation } = compiler.webpack; compilation.hooks.processAssets.tap( { name: 'MyPlugin', stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE, }, assets => { const assetName = 'unwanted-script.js'; if (assets[assetName]) { compilation.deleteAsset(assetName); } }, ); }); ``` ### Process assets stages Here's the list of supported stages. Rspack will execute these stages sequentially from top to bottom. Please select the appropriate stage based on the operation you need to perform. * `PROCESS_ASSETS_STAGE_ADDITIONAL` — add additional assets to the compilation. * `PROCESS_ASSETS_STAGE_PRE_PROCESS` — basic preprocessing of the assets. * `PROCESS_ASSETS_STAGE_DERIVED` — derive new assets from the existing assets. * `PROCESS_ASSETS_STAGE_ADDITIONS` — add additional sections to the existing assets e.g. banner or initialization code. * `PROCESS_ASSETS_STAGE_OPTIMIZE` — optimize existing assets in a general way. * `PROCESS_ASSETS_STAGE_OPTIMIZE_COUNT` — optimize the count of existing assets, e.g. by merging them. * `PROCESS_ASSETS_STAGE_OPTIMIZE_COMPATIBILITY` — optimize the compatibility of existing assets, e.g. add polyfills or vendor prefixes. * `PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE` — optimize the size of existing assets, e.g. by minimizing or omitting whitespace. * `PROCESS_ASSETS_STAGE_DEV_TOOLING` — add development tooling to the assets, e.g. by extracting a source map. * `PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE` — optimize the numbers of existing assets by inlining assets into other assets. * `PROCESS_ASSETS_STAGE_SUMMARIZE` — summarize the list of existing assets. * `PROCESS_ASSETS_STAGE_OPTIMIZE_HASH` — optimize the hashes of the assets, e.g. by generating real hashes of the asset content. * `PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER` — optimize the transfer of existing assets, e.g. by preparing a compressed (gzip) file as separate asset. * `PROCESS_ASSETS_STAGE_ANALYSE` — analyze the existing assets. * `PROCESS_ASSETS_STAGE_REPORT` — creating assets for the reporting purposes. ## `afterProcessAssets` Called after the [processAssets](#processAssets) hook had finished without error. * **Type:** `SyncHook` * **Arguments:** * `Assets: Record`: list of asset instances ```ts type Source = { source(): string | ArrayBuffer; buffer(): Buffer; size(): number; map(options?: MapOptions): RawSourceMap | null; sourceAndMap(options?: MapOptions): SourceAndMapResult; }; ``` * **Example:** ```js compilation.hooks.afterProcessAssets.tap('MyPlugin', assets => { console.log('assets', Object.keys(assets)); }); ``` ## `afterSeal` Called after the seal phase. * **Type:** `AsyncSeriesHook<[]>` ## `chunkHash` Triggered to emit the hash for each chunk. * **Type:** `SyncHook<[Chunk, Hash]>` * **Arguments:** * `Chunk`: chunk instance * `Hash`: chunk hash instance ```ts type Chunk = { auxiliaryFiles: ReadonlySet; canBeInitial(): boolean; chunkReason?: Readonly; contentHash: Readonly>; cssFilenameTemplate?: Readonly; filenameTemplate?: Readonly; files: ReadonlySet; getAllAsyncChunks(): Iterable; getAllInitialChunks(): Iterable; getAllReferencedChunks(): Iterable; getEntryOptions(): EntryOptions | undefined; get groupsIterable(): Iterable; hash?: Readonly; hasRuntime(): boolean; id?: Readonly; idNameHints: ReadonlyArray; ids: ReadonlyArray; isOnlyInitial(): boolean; name?: Readonly; renderedHash?: Readonly; runtime: ReadonlySet; }; ``` ```ts type Hash = { update(data: string | Buffer, inputEncoding?: string): Hash; digest(encoding?: string): string | Buffer; }; ``` ## `chunkAsset` Triggered when an asset from a chunk was added to the compilation. * **Type:** `SyncHook<[Chunk, string]>` * **Arguments:** * `Chunk`: chunk instance * `string`: asset filename ```ts type Chunk = { auxiliaryFiles: ReadonlySet; canBeInitial(): boolean; chunkReason?: Readonly; contentHash: Readonly>; cssFilenameTemplate?: Readonly; filenameTemplate?: Readonly; files: ReadonlySet; getAllAsyncChunks(): Iterable; getAllInitialChunks(): Iterable; getAllReferencedChunks(): Iterable; getEntryOptions(): EntryOptions | undefined; get groupsIterable(): Iterable; hash?: Readonly; hasRuntime(): boolean; id?: Readonly; idNameHints: ReadonlyArray; ids: ReadonlyArray; isOnlyInitial(): boolean; name?: Readonly; renderedHash?: Readonly; runtime: ReadonlySet; }; ``` ## `childCompiler` Executed after setting up a child compiler. * **Type:** `SyncHook<[Compiler, string, number]>` * **Arguments:** * `Compiler`: child compiler instance * `string`: child compiler name * `number`: child compiler index ```ts type Compiler = { hooks: CompilerHooks; inputFileSystem: InputFileSystem | null; outputFileSystem: OutputFileSystem | null; watchFileSystem: WatchFileSystem | null; options: RspackOptionsNormalized; watching: Watching; getInfrastructureLogger(name: string | (() => string)): Logger; getCache(name: string): CacheFacade; watch( watchOptions: Watchpack.WatchOptions, handler: liteTapable.Callback, ): Watching; run(callback: liteTapable.Callback): void; runAsChild( callback: ( err?: null | Error, entries?: Chunk[], compilation?: Compilation, ) => any, ): void; createChildCompiler( compilation: Compilation, compilerName: string, compilerIndex: number, outputOptions: OutputNormalized, plugins: RspackPluginInstance[], ): Compiler; compile(callback: liteTapable.Callback): void; close(callback: (error?: Error | null) => void): void; }; ``` ## `statsPreset` This hook is like a list of actions that gets triggered when a preset is used. It takes in an options object. When a plugin manages a preset, it should change settings in this object carefully without replacing existing ones. * **Type:** `SyncHook<[Partial, CreateStatsOptionsContext]>` * **Arguments:** * `Partial`: stats options * `CreateStatsOptionsContext`: stats context Here's an illustrative plugin example: ```js compilation.hooks.statsPreset.for('my-preset').tap('MyPlugin', options => { if (options.all === undefined) options.all = true; }); ``` This plugin ensures that for the preset `"my-preset"`, if the `all` option is undefined, it defaults to `true`. See [stats configuration](/config/stats.md) for details. ```ts type CreateStatsOptionsContext = { forToString?: boolean; [key: string]: any; }; ``` ## `statsNormalize` This hook is used to transform an options object into a consistent format that can be easily used by subsequent hooks. It also ensures that missing options are set to their default values. * **Type:** `SyncHook<[Partial, CreateStatsOptionsContext]>` * **Arguments:** * `Partial`: stats options * `CreateStatsOptionsContext`: stats context Here's an illustrative plugin example: ```js compilation.hooks.statsNormalize.tap('MyPlugin', options => { if (options.myOption === undefined) options.myOption = []; if (!Array.isArray(options.myOption)) options.myOptions = [options.myOptions]; }); ``` In this plugin, if the `myOption` is missing, it sets it to `[]`. Additionally, it ensures that `myOption` is always an array even if it was originally defined as a single value. See [stats configuration](/config/stats.md) for details. ```ts type CreateStatsOptionsContext = { forToString?: boolean; [key: string]: any; }; ``` ## `statsFactory` This hook provides access to the StatsFactory class for specific options. * **Type:** `SyncHook<[StatsFactory, StatsOptions]>` * **Arguments:** * `StatsFactory`: stats factory instance, see [Stats Factory Hooks](/api/plugin-api/stats-hooks.md#statsfactory) for more details * `StatsOptions`: stats options ```ts type StatsFactory = { hooks: StatsFactoryHooks; create( type: string, data: any, baseContext: Omit, ): void; }; ``` See [stats configuration](/config/stats.md) for details. ## `statsPrinter` This hook provides access to the StatsPrinter class for specific options. * **Type:** `SyncHook<[StatsPrinter, StatsOptions]>` * **Arguments:** * `StatsPrinter`: stats printer instance, see [Stats Printer Hooks](/api/plugin-api/stats-hooks.md#statsprinter) for more details. * `StatsOptions`: stats options ```ts type StatsPrinter = { hooks: StatsPrinterHooks; print( type: string, object: { [key: string]: any; }, baseContext?: { [key: string]: any; }, ): string; }; ``` See [stats configuration](/config/stats.md) for details. --- url: /api/plugin-api/normal-module-factory-hooks.md --- # NormalModuleFactory `NormalModuleFactory` is used by the [Compiler](/api/javascript-api/compiler.md) to generate modules (`NormalModule`). Starting from each entry module (`entry`), it resolves the dependency requests of the modules to obtain the final paths of the dependencies. Based on these final paths, it creates `NormalModule` instances. It then further resolves the dependency requests of the newly created modules. This process is recursive, creating each module as a `NormalModule` through `NormalModuleFactory`. `NormalModuleFactory` provides the following lifecycle hooks. These can be used just like `Compiler` hooks: ```js NormalModuleFactory.hooks.someHook.tap(/* ... */); ``` All hooks inherit from `Tapable`. In addition to `tap()`, you can also use `tapAsync()` and `tapPromise()`, depending on the type of the hook. ## `beforeResolve` `AsyncSeriesBailHook<[ResolveData]>` Called when a new dependency request is encountered. A dependency can be ignored by returning `false`. Otherwise, it should return `undefined` to proceed. The `beforeResolve` hook is called at the very beginning of the module resolution process, allowing the module's request information to be intercepted and modified before the resolution takes place. This hook can be used to pre-process, filter or block the resolution of certain modules. ```js compiler.hooks.compilation.tap( 'MyPlugin', (compilation, { normalModuleFactory }) => { normalModuleFactory.hooks.beforeResolve.tap('MyPlugin', resolveData => { // access and modify module request information console.log(JSON.stringify(resolveData, null, 2)); }); }, ); ``` ```ts export type ResolveData = { contextInfo: { issuer: string; }; context: string; request: string; fileDependencies: string[]; missingDependencies: string[]; contextDependencies: string[]; createData?: { request?: string; userRequest?: string; resource?: string; }; }; ``` ## `factorize` `AsyncSeriesBailHook<[ResolveData]>` Called before initiating resolve. It should return undefined to proceed. The `factorize` hook is used to add custom logic before a module is instantiated, modifying the module creation process. ```js compiler.hooks.compilation.tap( 'MyPlugin', (compilation, { normalModuleFactory }) => { normalModuleFactory.hooks.factorize.tap('MyPlugin', resolveData => { // access and modify module request information console.log(JSON.stringify(resolveData, null, 2)); }); }, ); ``` ```ts export type ResolveData = { contextInfo: { issuer: string; }; context: string; request: string; fileDependencies: string[]; missingDependencies: string[]; contextDependencies: string[]; createData?: { request?: string; userRequest?: string; resource?: string; }; }; ``` :::warning Returning module instance is not supported for now. This hook will affect the module creation process, so use it with caution. ::: ## `resolve` `AsyncSeriesBailHook<[ResolveData]>` Called before the request is resolved, it should return `undefined` to continue. The `resolve` hook can be used to intercept and modify module request information before module resolution begins. This hook allows for preprocessing of module requests. ```js compiler.hooks.compilation.tap( 'MyPlugin', (compilation, { normalModuleFactory }) => { normalModuleFactory.hooks.resolve.tap('MyPlugin', resolveData => { // access and modify module request information console.log(JSON.stringify(resolveData, null, 2)); }); }, ); ``` ```ts export type ResolveData = { contextInfo: { issuer: string; }; context: string; request: string; fileDependencies: string[]; missingDependencies: string[]; contextDependencies: string[]; createData?: { request?: string; userRequest?: string; resource?: string; }; }; ``` :::warning Returning module instance or `false` is not supported for now. ::: ## `afterResolve` `AsyncSeriesBailHook<[ResolveData]>` Called after the module specifier is resolved. The `afterResolve` hook is used to further process or modify the results after the module has been resolved. It is called at the end of the module resolution process, which means that at this stage, the module's path, request information, etc., have already been determined. ```js compiler.hooks.compilation.tap( 'MyPlugin', (compilation, { normalModuleFactory }) => { normalModuleFactory.hooks.afterResolve.tap('MyPlugin', resolveData => { // access and modify the resolved module information console.log(JSON.stringify(resolveData, null, 2)); }); }, ); ``` ```ts export type ResolveData = { contextInfo: { issuer: string; }; context: string; request: string; fileDependencies: string[]; missingDependencies: string[]; contextDependencies: string[]; createData?: { request?: string; userRequest?: string; resource?: string; }; }; ``` ## `resolveForScheme` `AsyncSeriesBailHook<[ResourceDataWithData]>` Called before a module specifier with scheme (URI) is resolved. The `resolveForScheme` is typically used to handle module specifiers that have a specific protocol, such as `file://`, `https://`, etc. ```js compiler.hooks.compilation.tap( 'MyPlugin', (compilation, { normalModuleFactory }) => { normalModuleFactory.hooks.resolveForScheme .for('https') .tap('MyPlugin', resourceData => { console.log(JSON.stringify(resourceData, null, 2)); }); }, ); ``` ```ts type ResourceDataWithData = { resource: string; path: string; query?: string; fragment?: string; data?: Record; }; ``` --- url: /api/plugin-api/context-module-factory-hooks.md --- # ContextModuleFactory The `ContextModuleFactory` module is used by the `Compiler` to generate dependencies from [require.context](/api/runtime-api/module-methods.md#requirecontext) API. It resolves the requested directory, generates requests for each file and filters against passed regExp. Matching dependencies then passes through [NormalModuleFactory](/api/plugin-api/normal-module-factory-hooks.md). ## `beforeResolve` `AsyncSeriesBailHook<[BeforeResolveResult]>` Called before resolving the requested directory. The request can be ignored by returning `false`. ```ts type BeforeResolveData = { context: string; request: string; regExp: RegExp | undefined; recursive: boolean; } export type BeforeResolveResult = | false | BeforeResolveData; ``` ## `afterResolve` `AsyncSeriesBailHook<[AfterResolveResult]>` Called after the requested directory resolved. ```ts type AfterResolveData = { resource: number; context: string; request: string; regExp: RegExp | undefined; recursive: boolean; dependencies: Dependency[]; } export type AfterResolveResult = | false | AfterResolveData; ``` --- url: /api/plugin-api/javascript-modules-plugin-hooks.md --- # JavascriptModulesPlugin ## `chunkHash` `SyncHook<[Chunk, Hash]>` Called when computing the chunk hash for JavaScript chunks. ```ts type Chunk = { auxiliaryFiles: ReadonlySet; canBeInitial(): boolean; chunkReason?: Readonly; contentHash: Readonly>; cssFilenameTemplate?: Readonly; filenameTemplate?: Readonly; files: ReadonlySet; getAllAsyncChunks(): Iterable; getAllInitialChunks(): Iterable; getAllReferencedChunks(): Iterable; getEntryOptions(): EntryOptions | undefined; get groupsIterable(): Iterable; hash?: Readonly; hasRuntime(): boolean; id?: Readonly; idNameHints: ReadonlyArray; ids: ReadonlyArray; isOnlyInitial(): boolean; name?: Readonly; renderedHash?: Readonly; runtime: ReadonlySet; }; ``` ```ts type Hash = { update(data: string | Buffer, inputEncoding?: string): Hash; digest(encoding?: string): string | Buffer; }; ``` --- url: /api/plugin-api/stats-hooks.md --- # Stats hooks ## StatsFactory ### StatsFactory.hooks.extract A HookMap, called when generating the specified stats item. * **Type:** `HookMap>` * **Arguments:** * `Object`: result stats item object which properties should be added. * `Class`: the original data of the stats item * `StatsFactoryContext`: generating context ```ts type StatsFactoryContext = { type: string; makePathsRelative?: ((arg0: string) => string) | undefined; compilation?: Compilation | undefined; cachedGetErrors?: ((arg0: Compilation) => JsStatsError[]) | undefined; cachedGetWarnings?: ((arg0: Compilation) => JsStatsWarning[]) | undefined; }; ``` For the following example, the `customProperty` attribute is added in the finally generated `stats.compilation` through `MyPlugin`: ```js compilation.hooks.statsFactory.tap('MyPlugin', (statsFactory, options) => { statsFactory.hooks.extract .for('compilation') .tap('MyPlugin', (object, compilation) => { object.customProperty = MyPlugin.getCustomValue(compilation); }); }); ``` ### StatsFactory.hooks.result A HookMap, called after generating the specified stats item. * **Type:** `HookMap>` * **Arguments:** * `any[]`: generated stats item result * `StatsFactoryContext`: generating context ## StatsPrinter ### StatsPrinter.hooks.print A HookMap, called 为一个 HookMap, called when generating the printed string of the specified stats item. * **Type:** `HookMap>` * **Arguments:** * `Object`: stats item object * `StatsPrinterContext`: printing context ```ts type StatsPrinterContext = { type?: string; compilation?: StatsCompilation; chunkGroup?: StatsChunkGroup; asset?: StatsAsset; module?: StatsModule; chunk?: StatsChunk; moduleReason?: StatsModuleReason; bold?: (str: string) => string; yellow?: (str: string) => string; red?: (str: string) => string; green?: (str: string) => string; magenta?: (str: string) => string; cyan?: (str: string) => string; formatFilename?: (file: string, oversize?: boolean) => string; formatModuleId?: (id: string) => string; formatChunkId?: | ((id: string, direction?: 'parent' | 'child' | 'sibling') => string) | undefined; formatSize?: (size: number) => string; formatDateTime?: (dateTime: number) => string; formatFlag?: (flag: string) => string; formatTime?: (time: number, boldQuantity?: boolean) => string; chunkGroupKind?: string; }; ``` ### StatsPrinter.hooks.result A HookMap, called after generating the printed string of the specified stats item. * **Type:** `HookMap>` * **Arguments:** * `String`: printed string of the stats item * `StatsPrinterContext`: printing context --- url: /api/plugin-api/runtime-plugin-hooks.md --- # RuntimePlugin hooks `RuntimePlugin` is used to generate the code for the Rspack startup. It provides the following hooks that can be used to modify these runtime codes. You can obtain these hooks like below: ```js title="rspack.config.mjs" export default { //... plugins: [ { apply: compiler => { const { RuntimePlugin } = compiler.webpack; compiler.hooks.compilation.tap('MyPlugin', compilation => { const hooks = RuntimePlugin.getCompilationHooks(compilation); //... }); }, }, ], }; ``` ## `createScript` `SyncWaterallHook<[string, chunk]>` Can modify the code executed when creating the `