---
url: /guide/introduction.md
---
# Introduction
## What is a Bundler
In JavaScript development, a bundler is responsible for compiling small pieces of code (ESM or CommonJS modules) into something larger and more complex, such as a library or application.
For web applications, this makes your application load and run significantly faster (even with HTTP/2). For libraries, this can avoid your consuming application having to bundle the source again, and can also improve runtime execution performance.
For those interested in the details, we have written a deeper analysis on [why bundlers are still needed](/in-depth/why-bundlers).
## Why Rolldown
Rolldown is primarily designed to serve as the underlying bundler in [Vite](https://vite.dev/), with the goal to replace [esbuild](https://esbuild.github.io/) and [Rollup](https://rollupjs.org/) (which are currently used in Vite as dependencies) with one unified build tool. Here's why we are implementing a new bundler from the ground up:
* **Performance**: Rolldown is written in Rust. It is on the same performance level with esbuild and [10~30 times faster than Rollup](https://github.com/rolldown/benchmarks). Its WASM build is also [significantly faster than esbuild's](https://x.com/youyuxi/status/1869608132386922720) (due to Go's sub-optimal WASM compilation).
* **Ecosystem Compatibility**: Rolldown supports the same plugin API with Rollup / Vite, ensuring compatibility with Vite's existing ecosystem.
* **Additional Features**: Rolldown provides some important features needed in Vite but unlikely to be implemented by esbuild and Rollup (details below).
Although designed for Vite, Rolldown is also fully capable of being used as a standalone, general-purpose bundler. It can serve as a drop-in replacement for Rollup in most cases, and can also be used as an esbuild alternative when better chunking control is needed.
## Rolldown's Feature Scope
Rolldown provides largely compatible APIs (especially the plugin interface) with Rollup, and has similar treeshaking capabilities for bundle size optimization.
However, Rolldown's feature scope is more similar to esbuild, offering these [additional features](./notable-features) as built-in:
* Platform presets
* TypeScript / JSX / syntax lowering transforms
* Node.js compatible module resolution
* ESM / CJS module interop
* `define`
* `inject`
* Minification (WIP)
Rolldown also has a few concepts that have close equivalents in esbuild, but do not exist in Rollup:
* [Module Types](./notable-features#module-types) (Experimental)
* [Plugin hook filters](/apis/plugin-api/hook-filters)
Finally, Rolldown provides some features that esbuild and Rollup do not (and may not intend to) implement:
* [Manual code splitting](./notable-features#manual-code-splitting)
* HMR support (WIP)
## Credits
Rolldown wouldn't exist without all the lessons we learned from other bundlers like [esbuild](https://esbuild.github.io/), [Rollup](https://rollupjs.org/), [webpack](https://webpack.js.org/), and [Parcel](https://parceljs.org/). We have the utmost respect and appreciation towards the authors and maintainers of these important projects.
---
---
url: /guide/getting-started.md
---
# Getting Started
:::tip Looking for specific use cases?
For most applications, using [Rolldown through Vite](https://vite.dev/guide/rolldown.html#how-to-try-rolldown) is the recommended approach, as it provides a complete development experience with dev server, HMR, and optimized production builds.
For library bundling, check out [tsdown](https://tsdown.dev/).
:::
## Installation
::: code-group
```sh [vp]
$ vp add -D rolldown
```
```sh [npm]
$ npm install -D rolldown
```
```sh [pnpm]
$ pnpm add -D rolldown
```
```sh [yarn]
$ yarn add -D rolldown
```
```sh [bun]
$ bun add -D rolldown
```
:::
::: details Using a minor platform (CPU architecture, OS) ?
Prebuilt binaries are distributed for the following platforms (grouped by [Node.js v24 platform support tier](https://github.com/nodejs/node/blob/v24.x/BUILDING.md#platform-list)):
* Tier 1
* Linux x64 glibc (`x86_64-unknown-linux-gnu`)
* Linux arm64 glibc (`aarch64-unknown-linux-gnu`)
* Windows x64 (`x86_64-pc-windows-msvc`)
* Apple x64 (`x86_64-apple-darwin`)
* Apple arm64 (`aarch64-apple-darwin`)
* Tier 2
* Windows arm64 (`aarch64-pc-windows-msvc`)
* Linux s390x glibc (`s390x-unknown-linux-gnu`)
* Linux ppc64le glibc (`powerpc64le-unknown-linux-gnu`)
* Experimental
* Linux x64 musl (`x86_64-unknown-linux-musl`)
* Linux armv7 (`armv7-unknown-linux-gnueabihf`)
* FreeBSD x64 (`x86_64-unknown-freebsd`)
* OpenHarmony arm64 (`aarch64-unknown-linux-ohos`)
* Other
* Linux arm64 musl (`aarch64-unknown-linux-musl`)
* Android arm64 (`aarch64-linux-android`)
* Wasm + Wasi (`wasm32-wasip1-threads`)
If you are using a platform that a prebuilt binary is not distributed, you have the following options:
* Use the Wasm build
1. Download the Wasm build.
* For npm, you can run `npm install --cpu wasm32 --os wasip1-threads`.
* For yarn or pnpm, you need to add the following content to your `.yarnrc.yaml` or `pnpm-workspace.yaml`:
```yaml
supportedArchitectures:
os:
- wasip1-threads
cpu:
- wasm32
```
2. Make Rolldown load the Wasm build.
* If the prebuilt binary is not available, Rolldown will fallback to the Wasm binary automatically.
* In case you need to force Rolldown to use the Wasm build, you can set `NAPI_RS_FORCE_WASI=error` environment variable.
* Build from source
1. Clone the repository.
2. Setup the project by following [the setup instructions](/development-guide/setup-the-project).
3. Build the project by following [the build instructions](/development-guide/building-and-running).
4. Set the `NAPI_RS_NATIVE_LIBRARY_PATH` environment variable to the path of `packages/rolldown` in the cloned repository.
:::
### Release Channels
* [latest](https://npmx.dev/package/rolldown#versions): currently `1.x.x`.
* [pkg.pr.new](https://pkg.pr.new/~/rolldown/rolldown): continuously released from the `main` branch. Install with `npm i https://pkg.pr.new/rolldown@sha` where `sha` is a successful build listed on [pkg.pr.new](https://pkg.pr.new/~/rolldown/rolldown).
## Using the CLI
To verify Rolldown is installed correctly, run the following in the directory where you installed it:
```sh
$ ./node_modules/.bin/rolldown --version
```
You can also check out the CLI options and examples with:
```sh
$ ./node_modules/.bin/rolldown --help
```
### Your first bundle
Let's create two source JavaScript files:
```js [src/main.js]
import { hello } from './hello.js';
hello();
```
```js [src/hello.js]
export function hello() {
console.log('Hello Rolldown!');
}
```
Then run the following in the command line:
```sh
$ ./node_modules/.bin/rolldown src/main.js --file bundle.js
```
You should see the content written to `bundle.js` in your current directory. Let's run it to verify it's working:
```sh
$ node bundle.js
```
You should see `Hello Rolldown!` printed.
### Adding a package.json build script
To avoid typing the long command, we can move it inside a `package.json` script:
```json{5} [package.json]
{
"name": "my-rolldown-project",
"type": "module",
"scripts": {
"build": "rolldown src/main.js --file bundle.js"
},
"devDependencies": {
"rolldown": "^1.0.0"
}
}
```
Now we can run the build with just:
::: code-group
```sh [vp]
$ vp run build
```
```sh [npm]
$ npm run build
```
```sh [pnpm]
$ pnpm run build
```
```sh [yarn]
$ yarn build
```
```sh [bun]
$ bun run build
```
:::
## Using the Config File
When more options are needed, it is recommended to use a config file for more flexibility. A config file can be written in `.js`, `.cjs`, `.mjs`, `.ts`, `.mts`, or `.cts` formats. Let's create the following config file:
```js [rolldown.config.js]
import { defineConfig } from 'rolldown';
export default defineConfig({
input: 'src/main.js',
output: {
file: 'bundle.js',
},
});
```
Rolldown supports most of the [Rollup config options](https://rollupjs.org/configuration-options), with some [notable additional features](./notable-features). See the [reference](/reference/) for the full list of options.
While exporting a plain object also works, it is recommended to utilize the [`defineConfig`](/reference/Function.defineConfig) helper method to get options intellisense and auto-completion. This helper is provided purely for the types and returns the options as-is.
Next, in the npm script, we can instruct Rolldown to use the config file with the `--config` CLI option (`-c` for short):
```json{5} [package.json]
{
"name": "my-rolldown-project",
"type": "module",
"scripts": {
"build": "rolldown -c"
},
"devDependencies": {
"rolldown": "^1.0.0"
}
}
```
### Multiple builds in the same config
You can also specify multiple configurations as an array, and Rolldown will bundle them in parallel.
```js [rolldown.config.js]
import { defineConfig } from 'rolldown';
export default defineConfig([
{
input: 'src/main.js',
output: {
format: 'esm',
},
},
{
input: 'src/worker.js',
output: {
format: 'iife',
dir: 'dist/worker',
},
},
]);
```
## Using Plugins
Rolldown's plugin API is identical to that of Rollup's, so you can reuse most of the existing Rollup plugins when using Rolldown. That said, Rolldown provides many [built-in features](./notable-features) that make it unnecessary to use plugins.
Also Rolldown provides some builtin plugins that can be used for some use cases. See [Builtin Plugins](/builtin-plugins/) for more information.
Community plugins that are published to npm are listed in [Vite Plugin Registry](https://registry.vite.dev/plugins).
## Using the API
Rolldown provides a JavaScript API that is compatible with [Rollup's](https://rollupjs.org/javascript-api/), which separates `input` and `output` options:
```js
import { rolldown } from 'rolldown';
const bundle = await rolldown({
// input options
input: 'src/main.js',
});
// generate bundles in memory with different output options
await bundle.generate({
// output options
format: 'esm',
});
await bundle.generate({
// output options
format: 'cjs',
});
// or directly write to disk
await bundle.write({
file: 'bundle.js',
});
```
Alternatively, you can also use the more concise `build` API, which accepts the exact same options as the config file export:
```js
import { build } from 'rolldown';
// build writes to disk by default
await build({
input: 'src/main.js',
output: {
file: 'bundle.js',
},
});
```
## Using the Watcher
The rolldown watcher api is compatible with rollup [watch](https://rollupjs.org/javascript-api/#rollup-watch).
```js
import { watch } from 'rolldown';
const watcher = watch({/* option */}); // or watch([/* multiple option */] )
watcher.on('event', () => {});
await watcher.close(); // This is different than rollup: rolldown returns a promise here.
```
---
---
url: /guide/notable-features.md
---
# Notable Features
This page documents some notable features in Rolldown that do not have built-in equivalents in Rollup.
## Platform presets
* Configurable via the [`platform`](/reference/InputOptions.platform) option.
* Default: `'node'` for `cjs` output, `'browser'` otherwise
* Possible values: `browser | node | neutral`
Similar to [esbuild's `platform` option](https://esbuild.github.io/api/#platform), this option provides some sensible defaults regarding module resolution and how to handle `process.env.NODE_ENV`.
**Notable differences from esbuild:**
* The default output format is always `esm` regardless of platform.
:::tip
Rolldown does not polyfill Node built-ins when targeting the browser. You can opt-in to it with [rolldown-plugin-node-polyfills](https://github.com/rolldown/rolldown-plugin-node-polyfills).
:::
## Built-in transforms
Rolldown supports the following transforms out of the box, powered by [Oxc](https://oxc.rs/docs/guide/usage/transformer).
The transform is configurable via the [`transform`](/reference/InputOptions.transform) option.
The following transforms are supported:
* TypeScript
* Sets configurations based on the `tsconfig.json` when the [`tsconfig`](/reference/InputOptions.tsconfig) option is provided.
* Supported legacy decorators and decorator metadata.
* JSX
* Syntax lowering
* Automatically transforms modern syntax to be compatible with your defined target.
* Supports [down to ES2015](https://oxc.rs/docs/guide/usage/transformer/lowering#transformations).
## CJS support
Rolldown supports mixed ESM / CJS module graphs out of the box, without the need for `@rollup/plugin-commonjs`. It largely follows esbuild's semantics and [passes all esbuild ESM / CJS interop tests](https://github.com/evanw/bundler-esm-cjs-tests).
See [Bundling CJS](/in-depth/bundling-cjs) for more details.
## Module resolution
* Configurable via the [`resolve`](/reference/InputOptions.resolve) option
* Powered by [oxc-resolver](https://github.com/oxc-project/oxc-resolver), aligned with webpack's [enhanced-resolve](https://github.com/webpack/enhanced-resolve)
Rolldown resolves modules based on TypeScript and Node.js' behavior by default, without the need for `@rollup/plugin-node-resolve`.
When top-level [`tsconfig`](/reference/InputOptions.tsconfig) option is provided, Rolldown will respect `compilerOptions.paths` in the specified `tsconfig.json`.
## Define
* Configurable via the [`transform.define`](/reference/InputOptions.transform#define) option.
This feature provides a way to replace global identifiers with constant expressions. Aligns with the respective options in [Vite](https://vite.dev/config/shared-options.html#define) and [esbuild](https://esbuild.github.io/api/#define).
::: tip `@rollup/plugin-replace` behaves differently
Note it behaves differently from [`@rollup/plugin-replace`](https://github.com/rollup/plugins/tree/master/packages/replace) as the replacement is AST-based, so the value to be replaced must be a valid identifier or member expression. Use the built-in [`replacePlugin`](/builtin-plugins/replace) for that purpose.
:::
## Inject
* Configurable via the [`transform.inject`](/reference/InputOptions.transform#inject) option.
This feature provides a way to shim global variables with a specific value exported from a module. This feature is equivalent of [`@rollup/plugin-inject`](https://github.com/rollup/plugins/tree/master/packages/inject) and conceptually similar to [esbuild's `inject` option](https://esbuild.github.io/api/#inject).
## Manual Code Splitting
* Configurable via [`output.codeSplitting`](/reference/OutputOptions.codeSplitting) option.
Rolldown allows controlling the chunking behavior granularly, similar to webpack's [`optimization.splitChunks`](https://webpack.js.org/plugins/split-chunks-plugin/#optimizationsplitchunks) feature.
See [Manual Code Splitting](/in-depth/manual-code-splitting) for more details.
## Module types
* ⚠️ Experimental
This is conceptually similar to [esbuild's `loader` option](https://esbuild.github.io/api/#loader), allowing users to globally associate file extensions to built-in module types via the [`moduleTypes`](/reference/InputOptions.moduleTypes) option, or specify module type of a specific module in plugin hooks. It is discussed in more details [here](/in-depth/module-types).
## Minification
* Configurable via the [`output.minify`](/reference/OutputOptions.minify) option.
The minification is powered by [Oxc Minifier](https://oxc.rs/docs/guide/usage/minifier). See its documentation for more details.
---
---
url: /guide/troubleshooting.md
---
# Troubleshooting
## Performance
Performance is a primary goal for Rolldown. However, build performance isn't solely determined by Rolldown itself. It's also significantly affected by the environment it runs in and the plugins used.
While we continuously strive to improve Rolldown to minimize these external factors, there are inherent limitations and areas where optimizations are still ongoing. This guide provides insights into potential bottlenecks and how you can mitigate them.
### Environment
The operating system and its configuration can impact build times, particularly file system operations.
#### Windows
File system access on Windows is generally slower compared to other operating systems like macOS or Linux. Especially, antivirus software can make this much worse. But even without interference from antivirus programs, baseline file system performance tends to be slower. It is 3 times slower than macOS and 10 times slower than Linux. This becomes a bottleneck when most of the transforms are done without a plugin.
To improve performance on Windows, consider using alternative file system environments:
1. [**Dev Drive**](https://learn.microsoft.com/en-us/windows/dev-drive/): A newer Windows feature designed for developer workloads, using the Resilient File System (ReFS). Using a Dev Drive can lead to a **2x to 3x speedup** compared to the standard Windows NTFS file system for file system operations.
2. [**Windows Subsystem for Linux (WSL)**](https://learn.microsoft.com/en-us/windows/wsl/): WSL lets Linux environment to run on Windows easily, which offers significantly better file system performance. Placing your project files and running the build process within WSL can result in speedups of around **10x** compared to the standard Windows NTFS file system for file system operations.
:::details Benchmark Reference
The benchmark script used is described in this blog post ([How fast can you open 1000 files?](https://lemire.me/blog/2025/03/01/how-fast-can-you-open-1000-files/)).
The results were:
| File System / Threads | 1 | 2 | 4 | 8 | 16 |
| -----------------------: | ----: | ----: | ----: | ----: | ----: |
| Windows NTFS | 286ms | 153ms | 85ms | 106ms | 110ms |
| Windows Dev Drive (ReFS) | 124ms | 67ms | 35ms | 48ms | 55ms |
| WSL (ext4) | 24ms | 13ms | 7.8ms | 9.0ms | 13ms |
The benchmark was ran on the following environment:
* OS: Windows 11 Pro 23H2 22631.5189
* CPU: AMD Ryzen 9 5900X
* Memory: DDR4-3600 32GB
* SSD: Western Digital Black SN850X 1TB
:::
### Plugins
Plugins extend Rolldown's functionality, but can also introduce performance overhead.
#### Plugin Hook Filters
Rolldown provides a feature called **Plugin Hook Filters**. This allows you to specify precisely which modules a plugin hook should process, reducing the communication overhead between JavaScript and Rust. For detailed information on how filters work internally, refer to the [Hook Filters](/apis/plugin-api/hook-filters) page.
If you are a plugin user and the plugin you use does not have hook filters specified, you can apply them by using the `withFilter` utility function exported by Rolldown.
```js
import yaml from '@rollup/plugin-yaml';
import { defineConfig } from 'rolldown';
import { withFilter } from 'rolldown/filter';
export default defineConfig({
plugins: [
// Run the transform hook of the `yaml` plugin only for modules which end in `.yaml`
withFilter(yaml({/*...*/}), { transform: { id: /\.yaml$/ } }),
],
});
```
#### Leverage Built-in Features
Rolldown includes several built-in features designed for efficiency. Where possible, prefer using these native capabilities over external Rollup plugins that perform similar tasks. Relying on built-in functionality often means the processing happens entirely within Rust, allowing to process in parallel.
Check the [Rolldown Features](/guide/notable-features) page for capabilities that does not exist in Rollup.
For example, the following common Rollup plugins may be replaced with Rolldown's built-in features:
* `@rollup/plugin-alias`: [`resolve.alias`](/reference/InputOptions.resolve#alias) option
* `@rollup/plugin-commonjs`: supported out of the box
* `@rollup/plugin-inject`: [`inject`](/guide/notable-features#inject) option
* `@rollup/plugin-replace`: [`replacePlugin`](/builtin-plugins/replace)
* `@rollup/plugin-node-resolve`: supported out of the box
* `@rollup/plugin-json`: supported out of the box
* `@rollup/plugin-swc`, `@rollup/plugin-babel`, `@rollup/plugin-sucrase`: supported out of the box via Oxc (complex configurations might still require the plugin)
* `@rollup/plugin-terser`: `output.minify` option
## Avoiding Direct `eval`
The `eval()` function evaluates a string of JavaScript code. `eval()` calls have two modes: direct eval and indirect eval. Direct eval refers to the case where the global `eval` function is called directly. Differently from indirect eval, direct eval allows the passed string to access the local scope variables of the caller.
Direct eval is problematic when bundling the code for many reasons:
* Rolldown applies an optimization called "scope hoisting" that puts multiple files into a single scope. However, this means code evaluated by direct `eval` can read and write variables in a different file in the bundle! This is a correctness issue because the evaluated code may try to access a global variable but may accidentally access a private variable with the same name from another file instead. **It can potentially even be a security issue** if a private variable in another file has sensitive data.
* Rolldown may rename some variables in the bundle to avoid name collisions. While this is not a problem when not using direct eval, it is a problem for direct eval because the code evaluated by direct eval may try to reference the renamed variables by the original name.
* Minifiers avoid mangling variable names that may be referenced from the direct eval code for correctness. There are also other optimizations prevented by direct eval. This means the output code would not be reduced efficiently.
Luckily, it is usually easy to avoid using direct eval. There are two commonly-used alternatives that avoid all of the drawbacks mentioned above:
* `(0, eval)('x')`
This is most common way to use indirect eval. There are also other ways to trigger indirect eval. For example, `var eval2 = eval; eval2('x')` and `[eval][0]('x')` and `window.eval('x')` are all indirect eval calls. When you use indirect eval, the code is evaluated in the global scope instead of in the inline scope of the caller.
* `new Function('x')`
This constructs a new function object at run-time. It is as if you wrote `function() { x }` in the global scope except that `x` can be an arbitrary string of code. This form is sometimes convenient because you can add arguments to the function, and use those arguments to expose variables to the evaluated code. For example, `(new Function('env', 'x'))(someEnv)` is as if you wrote `(function(env) { x })(someEnv)`. This is often a sufficient alternative for direct `eval` when the evaluated code needs to access local variables because you can pass the local variables in as arguments.
## Avoid relying on `this` in exported functions
In JavaScript, `this` is a special variable that is bound to a different value normally depending on how the function is called. For example, when the function is called as a method on an object, the `this` variable is bound to the object.
```js
const obj = {
method() {
console.log(this); // `this` is `obj` here
},
};
obj.method();
```
Similar to this, when a function is exported from a module and is called via a module namespace object, based on the ECMAScript spec, the `this` variable is bound to the module namespace object.
```js
// imported.js
export function method() {
console.log(this); // `this` is the module namespace object of `imported.js` here
}
// main.js
import * as namespace from './imported.js';
namespace.method();
```
However, **Rolldown does not necessarily preserve the value of `this`** for this case. For this reason, it is recommended to avoid relying on `this` in exported functions. That said, this behavior is common across most bundlers and would not be a problem in practice.
The reason for this behavior is because preserving the value of `this` limits the possibilities of tree-shaking. For example, if the `this` variable needs to be bound to the module namespace object, all the exports in that module cannot be tree-shaken even if they are not used through the `import`s.
::: tip A similar issue when outputting your code as CJS
Similar to the issue described above, Rolldown does not necessarily preserve the value of `this` of exported functions when outputting your code as CJS. In this case, `this` that should be `undefined` may be bound to the `module.exports` object instead.
:::
## Avoid relying on Temporal Dead Zone (TDZ) errors
In ECMAScript, `let`, `const`, and `class` declarations create a binding that exists from the start of its scope but is uninitialized until the declaration itself is evaluated. Reading the binding during this window, even via `typeof`, throws a `ReferenceError`. This window is known as the "Temporal Dead Zone (TDZ)".
```js
typeof x; // ReferenceError: Cannot access 'x' before initialization
let x = 1;
```
However, **Rolldown does not necessarily preserve TDZ semantics**, for a mix of correctness and performance reasons. Code that relies on a TDZ access throwing may behave differently in the bundled output, and should be avoided.
For example, Rolldown always rewrites a module top-level `class X {}` to `var X = class {}` so that the binding can be hoisted alongside other top-level declarations. As a result, the binding is observable as `undefined` (rather than throwing) before the declaration is reached. Setting [`output.topLevelVar`](/reference/OutputOptions.topLevelVar) to `true` extends the same rewriting to top-level `let` and `const`.
```js
// In ESM, this throws ReferenceError.
// In Rolldown's bundled output, `typeof X` evaluates to `"undefined"`.
console.log(typeof X);
class X {}
```
As another example, Rolldown may inline exported `const` values at their use sites, even across an import cycle. When the cycle causes the constant to be read before its declaration runs, ESM would throw, but Rolldown returns the inlined value instead.
::: code-group
```js [entry.js]
import './constants.js';
```
```js [constants.js]
export const foo = 123;
export function bar() {
return foo;
}
import './cycle.js';
```
```js [cycle.js]
import { bar } from './constants.js';
// In ESM, `bar()` throws ReferenceError because `foo` is in TDZ.
// In Rolldown's bundled output, `bar()` returns `123`.
console.log(bar());
```
:::
## Warning: "Sourcemap is likely to be incorrect"
You'll see this warning if you generate a sourcemap with your bundle ([`sourcemap: true`](/reference/OutputOptions.sourcemap) or `sourcemap: 'inline'`) but you're using one or more plugins that transformed code without generating a sourcemap for the transformation.
Usually, a plugin will only omit the sourcemap if it (the plugin, not the bundle) was configured with `sourcemap: false` - so all you need to do is change that. If the plugin doesn't generate a sourcemap, consider raising an issue with the plugin author.
## Error: "Cannot find module '@rolldown/binding-...'"
This error means Node.js found the `rolldown` package but not the platform-specific native package. It is usually caused by a known npm bug with optional dependencies ([npm/cli#4828](https://github.com/npm/cli/issues/4828)); if you installed with npm, removing `node_modules` and `package-lock.json` and reinstalling fixes it.
It can also happen when the config file lives in a symlinked directory that points into another project, for example one shared between Windows and WSL ([#9854](https://github.com/rolldown/rolldown/issues/9854)). Node.js resolves the config to its real path before resolving its imports, so `import ... from 'rolldown'` can pick up a `node_modules` installed for a different platform. Keep the config outside the symlinked directory, or run with the `NODE_OPTIONS=--preserve-symlinks` environment variable set (not compatible with pnpm, whose `node_modules` layout relies on symlinks).
---
---
url: /in-depth/why-bundlers.md
---
# Why do we still need bundlers?
## Skipping the build step is impractical
With the general availability of native ES modules and HTTP/2 in modern browsers, some developers are advocating for an unbundled approach for shipping web applications, even in production. While this approach works for smaller applications, in our opinion bundling is still very much necessary if you are shipping anything non-trivial and care about performance (which translates to better user experience).
Even in a polished unbundled deployment model, a build step is still often unavoidable. Take Rails 8's default import-map-based approach for example: all JavaScript assets still go through a build step in order to fingerprint the assets and generate the import map and modulepreload directives. It's just handled via `importmap-rails` and Propshaft instead of a JavaScript bundler.
Moreover, the unbundled approach will hit its limits if you have any of the following requirements:
* Require modern JavaScript features like ES6+, TypeScript, or JSX.
* Need to leverage bundler-specific optimizations like tree-shaking, code splitting, or minification.
* Utilize libraries or frameworks that depend on a build step.
* Utilize NPM dependencies that ship unbundled source code (results in too many requests).
Going with unbundled means locking yourself out of a big part of the JS ecosystem and giving up on many possible performance optimizations that could benefit your end users.
The main argument of avoiding JavaScript bundlers is added complexity and slowing down the dev feedback loop. However, modern JS tooling has improved a lot on this front over the past few years. Our goal with Vite / Rolldown is to improve these aspects further and make the build step feel invisible.
## The case for bundlers
Fundamentally, bundlers exist because of the unique constraints of web applications: they need to be delivered over the network on-demand. Bundlers can make web applications more performant in three ways:
1. Reduce the amount of network requests and waterfalls.
2. Reduce total bytes sent over the network.
3. Improve JavaScript execution performance.
## Reduce network requests and waterfalls
The first important thing we need to acknowledge is that **HTTP/2 does not mean you can stop caring about number of HTTP requests**.
Although HTTP/2 theoretically supports unlimited multiplexing, most browsers / servers have a default limit of around 100 on the maximum number of concurrent streams per connection. Every network request also comes with fixed overhead (header processing, TLS encryption, multiplexing, etc.) on both the server and the client. More requests means more server load, and the actual concurrency is limited by how fast your server can serve the module files. Applications that contain thousands of unbundled modules will still create serious network bottlenecks even under HTTP/2.
Deep import chains also result in network waterfalls - i.e. the browser needs to make multiple network roundtrips to fetch the entire module graph. This can be mitigated to some extent with `modulepreload` directives, but generating these requires tooling support, and bloating the HTML with thousands of `modulepreload` directives in `
` is also a performance issue in itself.
Bundling can drastically reduce such overhead by combining thousands of modules into an optimal number of chunks that both the server and the browser can handle with ease. Bundling also flattens the import chain depth to reduce waterfalls, and can provide the data needed to generate `modulepreload` directives. In its essence, bundling moves the work of combining the module graph to the build phase, instead of incurring it as a runtime cost for every visitor. This makes large applications load significantly faster on initial visit, especially in poor network conditions.
### Trade-offs in caching strategy
One argument supporting the unbundled approach is that it allows each module to be cached individually, reducing the amount of cache invalidation when the application is updated. However, this comes with the trade-off of a much slower initial load as explained above.
Sub-optimal bundling configurations can cause cascading chunk hash validations, causing users to have to re-download a large part of the app when the app is updated. But this is a solvable problem: bundlers can also leverage import maps and advanced chunking control to limit hash invalidation and improve cache hit rate. We do intend to provide an improved, more caching-friendly default chunking strategy in Vite / Rolldown in the future.
## Reduce total bytes sent over the network
Bundling can also greatly reduce overall size of JavaScript sent over the wire.
First, bundles can hoist multiple modules into the same scope, removing all the import / export statements between them.
Second, treeshaking / dead code elimination is an optimization that can only be performed by statically analyzing the source code at build time. Native ESM loads and evaluates everything eagerly, so even if you only use a single export from a big module, the entire module has to be downloaded and evaluated. With a smart bundler, exports that are not used can be completely removed from the final bundle, saving lots of bytes.
Finally, minification and gzip / brotli compression are considerably more efficient when performed on bundled code compared to individual modules.
With these factors combined, users download less code, and your servers use less outbound bandwidth.
## Improve JavaScript execution performance
JavaScript is an interpreted language, and modern JavaScript engines often employ advanced JIT compilation to make it run faster. However, there is also non-trivial cost involved in parsing and compiling JavaScript.
Sending less JavaScript code not only saves bandwidth - it also means less JavaScript needs to be compiled and evaluated in the browser, leading to faster application startup time.
Some bundlers / minifiers also can perform optimizations like constant folding / ahead-of-time evaluation to varying extent, making the bundled code more efficient than their hand-written source.
***
In conclusion, bundling is still a beneficial, and in many cases necessary step in web development, and will continue to be so in the foreseeable future.
---
---
url: /in-depth/why-plugin-hook-filter.md
---
# Why Plugin Hook Filters?
## The Problem
Even though Rolldown's core is written in Rust with parallel processing capabilities, **adding JavaScript plugins can significantly slow down your builds**. Why? Because each plugin hook gets called for *every* module, even when the plugin doesn't care about most of them.
For example, if you have a CSS plugin that only transforms `.css` files, it still gets called for every `.js`, `.ts`, `.jsx`, and other file in your project. With 10 plugins, this overhead multiplies, causing build times to increase by **3-4x**.
Plugin hook filters solve this by letting Rolldown skip unnecessary plugin calls at the Rust level, keeping your builds fast even with many plugins.
## Real-World Impact
Let's see the actual performance difference with a benchmark using [apps/10000](https://github.com/rolldown/benchmarks/tree/main/apps/10000):
branch: https://github.com/rolldown/benchmarks/pull/3
```diff
diff --git a/apps/10000/rolldown.config.mjs b/apps/10000/rolldown.config.mjs
--- a/apps/10000/rolldown.config.mjs
+++ b/apps/10000/rolldown.config.mjs
@@ -1,8 +1,25 @@
import { defineConfig } from "rolldown";
-import { minify } from "rollup-plugin-esbuild";
+// import { minify } from "rollup-plugin-esbuild";
const sourceMap = !!process.env.SOURCE_MAP;
const m = !!process.env.MINIFY;
+const transformPluginCount = process.env.PLUGIN_COUNT || 0;
+let transformCssPlugin = Array.from({ length: transformPluginCount }, (_, i) => {
+ let index = i + 1;
+ return {
+ name: `transform-css-${index}`,
+ transform(code, id) {
+ if (id.endsWith(`foo${index}.css`)) {
+ return {
+ code: `.index-${index} {
+ color: red;
+}`,
+ map: null,
+ };
+ }
+ }
+ }
+})
export default defineConfig({
input: {
main: "./src/index.jsx",
@@ -11,13 +28,7 @@ export default defineConfig({
"process.env.NODE_ENV": JSON.stringify("production"),
},
plugins: [
- m
- ? minify({
- minify: true,
- legalComments: "none",
- target: "es2022",
- })
- : null,
+ ...transformCssPlugin,
].filter(Boolean),
profilerNames: !m,
output: {
diff --git a/apps/10000/src/index.css b/apps/10000/src/index.css
deleted file mode 100644
diff --git a/apps/10000/src/index.jsx b/apps/10000/src/index.jsx
--- a/apps/10000/src/index.jsx
+++ b/apps/10000/src/index.jsx
@@ -1,7 +1,16 @@
import React from "react";
import ReactDom from "react-dom/client";
import App1 from "./f0";
-import './index.css'
+import './foo1.css'
+import './foo2.css'
+import './foo3.css'
+import './foo4.css'
+import './foo5.css'
+import './foo6.css'
+import './foo7.css'
+import './foo8.css'
+import './foo9.css'
+import './foo10.css'
ReactDom.createRoot(document.getElementById("root")).render(
```
**Setup:**
* 10 CSS files (`foo1.css` to `foo10.css`)
* Each plugin transforms only one specific CSS file (e.g., plugin 1 only cares about `foo1.css`)
* Variable number of plugins controlled via `PLUGIN_COUNT`
* Plugins use standard pattern: check if file matches, return early if not
### Without Filter (Traditional Approach)
```bash
Benchmark 1: PLUGIN_COUNT=0 node --run build:rolldown
Time (mean ± σ): 745.6 ms ± 11.8 ms [User: 2298.0 ms, System: 1161.3 ms]
Range (min … max): 732.1 ms … 753.6 ms 3 runs
Benchmark 2: PLUGIN_COUNT=1 node --run build:rolldown
Time (mean ± σ): 862.6 ms ± 61.3 ms [User: 2714.1 ms, System: 1192.6 ms]
Range (min … max): 808.3 ms … 929.2 ms 3 runs
Benchmark 3: PLUGIN_COUNT=2 node --run build:rolldown
Time (mean ± σ): 1.106 s ± 0.020 s [User: 3.287 s, System: 1.382 s]
Range (min … max): 1.091 s … 1.130 s 3 runs
Benchmark 4: PLUGIN_COUNT=5 node --run build:rolldown
Time (mean ± σ): 1.848 s ± 0.022 s [User: 4.398 s, System: 1.728 s]
Range (min … max): 1.825 s … 1.869 s 3 runs
Benchmark 5: PLUGIN_COUNT=10 node --run build:rolldown
Time (mean ± σ): 2.792 s ± 0.065 s [User: 6.013 s, System: 2.198 s]
Range (min … max): 2.722 s … 2.850 s 3 runs
Summary
'PLUGIN_COUNT=0 node --run build:rolldown' ran
1.16 ± 0.08 times faster than 'PLUGIN_COUNT=1 node --run build:rolldown'
1.48 ± 0.04 times faster than 'PLUGIN_COUNT=2 node --run build:rolldown'
2.48 ± 0.05 times faster than 'PLUGIN_COUNT=5 node --run build:rolldown'
3.74 ± 0.10 times faster than 'PLUGIN_COUNT=10 node --run build:rolldown'
```
**Key Takeaway:** Build time scales linearly with plugin count - 10 plugins = **3.74x slower** (2.8s vs 745ms).
## The Solution: Plugin Hook Filters
Instead of calling every plugin for every module, use `filter` to tell Rolldown which files each plugin cares about. Here's how:
```diff
diff --git a/apps/10000/rolldown.config.mjs b/apps/10000/rolldown.config.mjs
index 822af995..dee07e68 100644
--- a/apps/10000/rolldown.config.mjs
+++ b/apps/10000/rolldown.config.mjs
@@ -8,14 +8,21 @@ let transformCssPlugin = Array.from({ length: transformPluginCount }, (_, i) =>
let index = i + 1;
return {
name: `transform-css-${index}`,
- transform(code, id) {
- if (id.endsWith(`foo${index}.css`)) {
- return {
- code: `.index-${index} {
+ transform: {
+ filter: {
+ id: {
+ include: new RegExp(`foo${index}.css$`),
+ }
+ },
+ handler(code, id) {
+ if (id.endsWith(`foo${index}.css`)) {
+ return {
+ code: `.index-${index} {
color: red;
}`,
- map: null,
- };
+ map: null,
+ };
+ }
}
}
}
```
**What changed:**
* Wrapped the `transform` function in an object with `handler` and `filter` properties
* Added `filter.id.include` with a regex pattern matching only the files this plugin cares about
* Rolldown now checks the filter in Rust *before* calling into JavaScript
### With Filter (Optimized)
```bash
Benchmark 1: PLUGIN_COUNT=0 node --run build:rolldown
Time (mean ± σ): 739.1 ms ± 6.8 ms [User: 2312.5 ms, System: 1153.0 ms]
Range (min … max): 733.0 ms … 746.5 ms 3 runs
Benchmark 2: PLUGIN_COUNT=1 node --run build:rolldown
Time (mean ± σ): 760.6 ms ± 18.3 ms [User: 2422.1 ms, System: 1107.4 ms]
Range (min … max): 739.7 ms … 773.6 ms 3 runs
Benchmark 3: PLUGIN_COUNT=2 node --run build:rolldown
Time (mean ± σ): 731.2 ms ± 11.1 ms [User: 2461.3 ms, System: 1141.4 ms]
Range (min … max): 723.9 ms … 744.0 ms 3 runs
Benchmark 4: PLUGIN_COUNT=5 node --run build:rolldown
Time (mean ± σ): 741.5 ms ± 9.3 ms [User: 2621.6 ms, System: 1111.3 ms]
Range (min … max): 734.0 ms … 751.9 ms 3 runs
Benchmark 5: PLUGIN_COUNT=10 node --run build:rolldown
Time (mean ± σ): 747.3 ms ± 2.1 ms [User: 2900.9 ms, System: 1120.0 ms]
Range (min … max): 745.0 ms … 749.2 ms 3 runs
Summary
'PLUGIN_COUNT=2 node --run build:rolldown' ran
1.01 ± 0.02 times faster than 'PLUGIN_COUNT=0 node --run build:rolldown'
1.01 ± 0.02 times faster than 'PLUGIN_COUNT=5 node --run build:rolldown'
1.02 ± 0.02 times faster than 'PLUGIN_COUNT=10 node --run build:rolldown'
1.04 ± 0.03 times faster than 'PLUGIN_COUNT=1 node --run build:rolldown'
```
**Key Takeaway:** With filters, all plugin counts perform nearly identically (~740ms). The overhead has been **eliminated**.
### Performance Comparison
| Plugin Count | Without Filter | With Filter | Speedup |
| ------------ | -------------- | ----------- | --------- |
| 0 plugins | 745ms | 739ms | 1.0x |
| 1 plugin | 863ms | 761ms | 1.13x |
| 2 plugins | 1,106ms | 731ms | 1.51x |
| 5 plugins | 1,848ms | 742ms | 2.49x |
| 10 plugins | 2,792ms | 747ms | **3.74x** |
**Bottom line:** When you have plugins that only care about specific files, use filters to maintain fast build times regardless of how many plugins you add.
## How It Works Under the Hood
To understand why filters are so effective, you need to understand how Rolldown processes modules with JavaScript plugins.
Rolldown uses parallel processing (like the [producer-consumer problem](https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem)) to build the module graph efficiently. Here's a simple dependency graph to illustrate:
**Dependency Graph**
```dot [Dependency Graph]
digraph {
bgcolor="transparent";
rankdir=TB;
node [shape=box, style="filled,rounded", fontname="Arial", fontsize=12, margin="0.2,0.1", color="${#3c3c43|#dfdfd6}", fontcolor="${#3c3c43|#dfdfd6}"];
edge [fontname="Arial", fontsize=10, color="${#3c3c43|#dfdfd6}", fontcolor="${#3c3c43|#dfdfd6}"];
a [label="a.js", fillcolor="${#fff0e0|#4a2a0a}"];
b [label="b.js", fillcolor="${#dbeafe|#1e3a5f}"];
c [label="c.js", fillcolor="${#dbeafe|#1e3a5f}"];
d [label="d.js", fillcolor="${#dbeafe|#1e3a5f}"];
e [label="e.js", fillcolor="${#dbeafe|#1e3a5f}"];
f [label="f.js", fillcolor="${#dbeafe|#1e3a5f}"];
a -> b;
a -> c;
b -> d;
b -> e;
c -> f;
}
```
### Without JavaScript Plugins

Everything runs in parallel in Rust. Multiple CPU cores process modules simultaneously, maximizing throughput.
> \[!NOTE]
> These diagrams show the conceptual algorithm, not exact implementation details. Some time slices are exaggerated for clarity—`fetch_module` actually runs at macrosecond speeds.
### With JavaScript Plugins (No Filter)

Here's the bottleneck: **JavaScript plugins run in a single thread**. Even though Rolldown's Rust core is parallel, every module must:
1. Stop at the "diamond" (hook call phase)
2. Cross the FFI boundary from Rust → JavaScript
3. Wait for *all* plugins to run serially
4. Cross back from JavaScript → Rust
This serialization point becomes a major bottleneck. Notice how the diamond section grows wider as more plugins are added, while CPU cores sit idle waiting for JavaScript.
### With Filters (Optimized)
When you add filters, Rolldown evaluates them **in Rust** before crossing into JavaScript:
```
For each module:
For each plugin:
✓ Check filter in Rust (macrosecond)
✗ Skip if no match
→ Only call JavaScript for matching plugins
```
This eliminates the majority of FFI overhead and JavaScript execution time. In the benchmark, most plugins don't match most files, so nearly all calls are skipped. The diamond shrinks back down, CPU utilization stays high, and build times remain fast.
## When to Use Filters
**Use filters when:**
* ✅ Your plugin only processes specific file types (e.g., `.css`, `.svg`, `.md`)
* ✅ Your plugin targets specific directories (e.g., `src/**`, `node_modules/**`)
* ✅ You have multiple plugins in your build
* ✅ You care about build performance
## Quick Reference
```js
// ❌ Without filter - called for every module
export default {
name: 'my-plugin',
transform(code, id) {
if (!id.endsWith('.css')) return;
// ... transform CSS
},
};
// ✅ With filter - only called for CSS files
export default {
name: 'my-plugin',
transform: {
filter: {
id: { include: /\.css$/ },
},
handler(code, id) {
// ... transform CSS
},
},
};
```
See the [plugin hook filter usage](/apis/plugin-api/hook-filters) for complete filter api and options.
---
---
url: /in-depth/module-types.md
---
# Module Types
As a web bundler, JavaScript is not the only file type with built-in support in Rolldown. For example, Rolldown can handle TypeScript and JSX files directly, parsing and transforming them to JavaScript before bundling them. We refer to these file types with first-class support in Rolldown as **Module Types**.
## How module types affect users
End users usually do not need to concern themselves with Module Types, since Rolldown automatically recognizes and handles known Module Types.
By default, Rolldown determines the module type of a module based on its file extension. However, in some cases this may not be sufficient. For example, imagine a file containing JSON data, but its extension is `.data`. Rolldown can't recognize it as a JSON file because the extension is not `.json`.
In this case, users need to explicitly tell Rolldown that files with the `.data` extension should be treated as the JSON module type. This can be done via the `moduleTypes` option in the config:
```js [rolldown.config.js]
export default {
moduleTypes: {
'.data': 'json',
},
};
```
## Module types and plugins
Plugins can specify the module type of a specific file via the `load` hook and the `transform` hook:
```js
const myPlugin = {
load(id) {
if (id.endsWith('.data')) {
return {
code: '...',
moduleType: 'json',
};
}
},
};
```
The main significance of module types is that it provides a central convention for supported types, making it easier to chain multiple plugins that need to operate on the same module type.
For example, `@vitejs/plugin-vue` currently creates virtual css modules for the style blocks in `.vue` files and append `?lang=css` to the id of a virtual module, allowing these modules to be recognized as css by the vue plugin. However, this is only a convention of the vue plugin - other plugins may ignore the query string and thus not recognize the convention.
With module types, `@vitejs/plugin-vue` can explicitly specify the module type of virtual css modules as `css`, and other plugins like the postcss plugin can process these css modules without being aware of the vue plugin.
Another example: to add support for `.jsonc` files, a plugin could simply strip comments of `.jsonc` files in the `load` hook and return `moduleType: 'json'`. Rolldown will handle the rest.
---
---
url: /in-depth/external-modules.md
---
# External Modules
When a module is marked as external, Rolldown will not bundle it. Instead, the `import` or `require` statement is preserved in the output, and the module is expected to be available at runtime.
```js
// input
import lodash from 'lodash';
console.log(lodash);
// output (lodash is external)
import lodash from 'lodash';
console.log(lodash);
```
This page explains how externals work end-to-end: how a module becomes external, how its import path is determined in the output, and how the relevant options and plugin hooks interact.
## How a Module Becomes External
There are three ways a module can be marked as external:
1. **The [`external`](/reference/InputOptions.external) option** — a config-level pattern (string, regex, array, or function) that tests each import specifier. See the [option reference](/reference/InputOptions.external) for pattern syntax, examples, and caveats.
2. **A plugin's `resolveId` hook** — a plugin can return `{ id, external: true }` (or `"relative"` / `"absolute"`) to explicitly mark a module as external. A plugin can also `return false` to mark the raw specifier as external with the same normalization as the `external` option.
3. **Unresolved modules** — if no plugin or the internal resolver can find a module and the `external` option matches the specifier, Rolldown treats it as external rather than throwing an error.
## The Full Resolution Flow
Here is the step-by-step process Rolldown follows when it encounters an import:
### 1. First `external` check
The raw import specifier (e.g. `'./utils'`, `'lodash'`) is tested against the [`external`](/reference/InputOptions.external) option with `isResolved: false`. If it matches, the module is marked as external immediately — **plugins and the internal resolver are skipped entirely**.
### 2. Plugin `resolveId`
If the first check did not match, plugins get a chance to resolve the import:
| Plugin return value | Effect |
| ------------------------------------- | --------------------------------------------------------------------------------- |
| `return false` | External. Uses the raw specifier as the module ID (same normalization as step 1). |
| `return { id, external: true }` | External. Uses `id` as the module ID. |
| `return { id, external: "relative" }` | External. Path is **always** relativized (overrides config). |
| `return { id, external: "absolute" }` | External. Path is **always** kept verbatim (overrides config). |
| `return { id }` (no `external`) | Resolved, continue to step 3 with the resolved ID. |
| `return null` | No plugin handled it, fall through to step 3. |
### 3. Internal resolver
Rolldown's built-in resolver tries to find the module on disk.
### 4. Second `external` check
The resolved ID (e.g. `'/project/node_modules/vue/dist/vue.runtime.esm-bundler.js'`) is tested against the [`external`](/reference/InputOptions.external) option with `isResolved: true`. If it matches, the specifier is marked as external.
### 5. Output path determination
Regardless of which step marked the module as external (first check, plugin, or second check), [`makeAbsoluteExternalsRelative`](/reference/InputOptions.makeAbsoluteExternalsRelative) applies uniformly to determine the import path in the output:
* **Bare specifiers** (e.g. `'lodash'`, `'node:fs'`) — appear as-is when matched on the first check. If matched on the second check (resolved path), the full resolved path appears instead (see the [caveat about `/node_modules/`](/reference/InputOptions.external#avoid-node-modules-for-npm-packages)).
* **Relative and absolute specifiers** — two things happen:
1. **Resolve-time normalization** — for the first check and `return false`, when `makeAbsoluteExternalsRelative` is enabled (which it is by default), relative specifiers (the **original import specifier**) are normalized to absolute paths by resolving against the importer's directory. This ensures that `'./utils'` imported from different directories correctly maps to different external modules. For the second check and `return { id, external: true }`, the **resolved module ID** is already absolute.
2. **Render-time output** — absolute resolved module IDs may be converted back to relative paths from the output chunk's location (e.g. `'/project/src/utils.js'` → `'./utils.js'`). Whether this happens depends on the `makeAbsoluteExternalsRelative` value and whether the original import specifier was relative.
Plugin overrides (`external: "relative"` / `"absolute"`) bypass this logic entirely. See the [`makeAbsoluteExternalsRelative` reference](/reference/InputOptions.makeAbsoluteExternalsRelative) for how each value controls this behavior, with examples.
## Special Cases
### Data URLs
Specifiers with a valid `data:` URL (e.g. `data:text/javascript,export default 42`) with a supported file format are handled by Rolldown's internal dataurl plugin which **bundles the inline content**. They are not automatically treated as external.
However, other `data:` URLs are treated as external automatically unless it's handled by a custom plugin.
### HTTP URLs
Specifiers starting with `http://`, `https://`, or `//` are **automatically treated as external** regardless of the `external` option, unless it's handled by a custom plugin. These IDs are emitted as-is and not affected by `makeAbsoluteExternalsRelative`.
```js
import lib from 'https://cdn.example.com/lib.js';
// Always external, emitted as-is
```
## Unused Imports Are Removed
If nothing uses an import from an external module, Rolldown removes it.
```js
// input
import { used, unused } from 'ext-pkg';
console.log(used);
// output
import { used } from 'ext-pkg';
console.log(used);
```
Note that even if every import is removed, the statement itself usually stays. External modules are assumed to have side effects, so it becomes a bare `import 'ext-pkg';`. The statement goes away completely only when the external module is also marked side-effect-free.
::: warning Difference from bundled modules
If a bundled module does not actually export `unused`, Rolldown emits a `MISSING_EXPORT` error at build time, whether or not the import is used.
For external modules, Rolldown does not know what exports exist, so it cannot check. If `unused` does not exist, importing it would throw at runtime, and removing the import removes that error along with it. Causing a semantic change without any message is normally a bad idea, but Rolldown makes an exception here. An unused import usually comes from dead code elimination, either Rolldown's own or a plugin's, rather than being written by hand, so the error is rarely the one you intended to see.
:::
---
---
url: /in-depth/directives.md
---
# Directive
JavaScript has a feature called directive, which is used to annotate a part of the code.
Rolldown may not be able to preserve the semantics related to directives, here are the strategies when handling directives.
## `"use strict"`
The `"use strict"` directive is a directive that tells the JavaScript engine to enforce strict mode. Because keeping the top-level `"use strict"` directive semantics is complicated and requires a bigger output size, Rolldown may not keep them.
Since ES modules are always in strict mode, Rolldown does not output any `"use strict"` directive for `output.format: 'es'`. As a side note, this means code that is not in strict mode are forced to be in strict mode for ES module format output.
You can control the `"use strict"` directive emission with the [`output.strict`](/reference/OutputOptions.strict) option:
* `true` - Always emit `"use strict"` at the top of the output (not applicable for ESM format since ESM is always strict).
* `false` - Never emit `"use strict"` in the output.
* `'auto'` (default) - Respect the `"use strict"` directive from the source code.
```ts
import { defineConfig } from 'rolldown';
export default defineConfig({
output: {
format: 'cjs',
strict: true,
},
});
```
When `output.format` is not `'es'` and `output.strict` is `'auto'`, Rolldown will output the `"use strict"` directive for any of the following cases:
* The directive is not in the top-level scope and not inside strict mode scope ([REPL](https://repl.rolldown.rs/#eNptjk0KAyEMha8SsrGF4gGE3mQ24mhxsMmgsR0YvHu1pT+LbpJ8L+G97BjQ7Bhp9pteypgJzZdP6Dr6beUsRQdmOEOo5CQygT0cYZ8IQNXioUiOTtTg7KVmAtXvO7eJuo9HI7n6dsLMKc18J+2YQrxo+cT+2fw+ALMPtibpoXnEcJW1inkjQOB8tV1QbinqJbbRngVbz751s2TFF8H2AIc5VRY=))
* The directive is in the top-level scope and the module is an entry module ([REPL](https://repl.rolldown.rs/#eNptUEtuhDAMvYqVDVCN6Kobuuw12FBwpqmCQx2nTYVy9zGD5qPRbJK8Z7+PshprutU4mjC333F7k+lu+GBGhVWKCFHYjVK99+TmJbDA1/+C/JE+ESyHGar2Nf6kgVF121ZPY6AYPLY+HOvrcv3WNDpVZzSdcMJyMFfdJf9GPC3QE+ZzhQntkLyATTSKCwS7sM4NrD0BMEpiggwvkFVXNFfjOHg/hT9qtaB1x7vcJ5O9wEPe2vNmH5IsSboLBLCB50GJatQ/2MmyXefDFM3+VTM/CEYx5QSMo4I7))
* The directive is in the top-level scope and `output.preserveModules` is enabled ([REPL](https://repl.rolldown.rs/#eNptkE1uhDAMha9iZQNUiK66ocuuewM2FJwpVYip40ypUO5eZxAz1Wg2Sfzz/L14M9a0m5n8iGvzFfLbm/YW12bQsIgBIQhPgxSvnZ/mhVjg83dBfosfCJZphqJ5Dt+xZ1Rd7ur8QD6Qw8bRqbw2ly9VpVWdjKYVjphqc9Ud/FvioQFcLwZGtH10Ajb6QSbysMvKtYKt8wCMEtnDCk+wqiopVWFMzo304xu1Z6fTP+qDyo6/420d5/EUZYnSHiGAJZ57TRSDbqA+sgtjQD7jO43RYWghf3ovpnxdDpPU2VlRrhcMYtIfQpqMFA==))
## Other directives
The ECMAScript specification allows implementations to define additional directives. Since those additional directives are not part of the specification, Rolldown does not know the semantics of them. Rolldown assumes that they follow the similar semantics as `"use strict"`. But for the same reason as above, Rolldown may not preserve the top-level directives.
Rolldown will output the directive for any of the following cases:
* The directive is not in the top-level scope ([REPL](https://repl.rolldown.rs/#eNptjt0KwyAMhV8l5MYNig8g7E16I1ZHi02Kxq1QfPfpxn4udpPkOwnn5MCA5sCZJr/rJfeZ0Hx5QNfQ7xsnyTowwwVCISczE9jTGY6RAFTJHlzJwqvqnLyURKDafeM6UvPxaCQVXwdMHOPEd9KOKcxXLZ/YP5vfB2DywZYoLTT1GC6yFTFvBAicVtsE5ZasXmLt7VmwtuxbM4tWfBasD4hqVRg=))
* The directive is in the top-level scope and the module is a entry module ([REPL](https://repl.rolldown.rs/#eNptUM1OwzAMfhUrl7ZolBOXcuQ1eimtM4pSuzgOdKr67riLtiHYJYn9/Sqr865Z3UgDLvVH3N/kmtt8cL2NRYoIfYrK0yOSyql4aWmcZhaF99OM8preELzwBEX9FD9TJ2jqndVSzxQ5YB34WF7J5XNVGWr+6BqVhNvBXXWXFrfF/xoZywm4nJsM6LsUFHyiXkcmyJxyqWBtCUBQkxAs8ACL6TaLt1ThEAb+ptp6+vH4K/4Oknv8yVtb2e056Zy0uYwAnmXqbFH09hV5ue3X+XCbZX+ZWegUo7rtB/Gqh1w=))
* The directive is in the top-level scope and `output.preserveModules` is enabled ([REPL](https://repl.rolldown.rs/#eNptkM9ShDAMxl8l0wvgIJ684NGzb8AFIV1xSoNps7LD8O6mMOw6upe2+fPl+zWLsaZezOB7nKvPkN7e1Le4NJ2GmQSETkKk8RF95Ev20vhhnIgjfFwm5Fd5R7BMI2TVU/iSllHVqavxHflADitHp/zanD8XhVZ1Ppo6suBamqvuoLgl/mOM1IvD5IDzxtGjbcVFsOK7OJCHXZ3PBSyNB2CMwh5meIBZVauaqyeTcz19+0op7XD6ZX6nslP88VsaTuNJ4iSxPkIASzy2msg6XUR5ZCfGgHzGtw0/1JD+vhfXdG2HWZXsrFaujRiiWX8ALR2RKg==))
If you want to append custom directive to all files, you can use the `output.banner` option:
```ts
import { defineConfig } from 'rolldown';
export default defineConfig({
output: {
banner: "'use client';",
},
});
```
---
---
url: /in-depth/automatic-code-splitting.md
---
# Automatic Code Splitting
Automatic code splitting is the process of creating chunks from modules. This chapter describes its behavior and the principles behind it.
Automatic code splitting is not controllable. It runs following certain rules. Thus, we will also refer to it as automatic code splitting against manual code splitting done by [manual code splitting](./manual-code-splitting.md).
Two types of chunks are generated by automatic code splitting.
## **Entry chunks**
**Entry chunks** are generated by combining modules connected statically into a chunk. "statically" means static `import ... from '...'` or `require(...)`.
There are two types of **entry chunks**.
The first one is **initial chunks**. **Initial chunks** are generated due to users' configuration. For example, `input: ['./a.js', './b.js']` defines two **initial chunks**.
The second one is **dynamic chunks**. **Dynamic chunks** are generated due to dynamic imports. Dynamic imports are used to load code on demand, so we don't put imported code together with the importers.
For the following code, two chunks will be generated:
```js
// entry.js (included in `input` option)
import foo from './foo.js';
import('./dyn-entry.js');
// dyn-entry.js
require('./bar.js');
// foo.js
export default 'foo';
// bar.js
module.exports = 'bar';
```
In this case, there are two groups of statically connected modules.
```dot
digraph {
bgcolor="transparent";
rankdir=LR;
node [shape=box, style="filled,rounded", fontname="Arial", fontsize=12, margin="0.2,0.1", color="${#3c3c43|#dfdfd6}", fontcolor="${#3c3c43|#dfdfd6}"];
edge [fontname="Arial", fontsize=10, color="${#3c3c43|#dfdfd6}", fontcolor="${#3c3c43|#dfdfd6}"];
subgraph cluster_group1 {
label="Group 1 (initial chunk)";
labeljust="l";
fontname="Arial";
fontsize=11;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#d44803|#ff712a}";
entry [label="entry.js", fillcolor="${#fff0e0|#4a2a0a}"];
foo [label="foo.js", fillcolor="${#fff0e0|#4a2a0a}"];
entry -> foo [label="static import"];
}
subgraph cluster_group2 {
label="Group 2 (dynamic chunk)";
labeljust="l";
fontname="Arial";
fontsize=11;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#0366d6|#58a6ff}";
dyn [label="dyn-entry.js", fillcolor="${#dbeafe|#1e3a5f}"];
bar [label="bar.js", fillcolor="${#dbeafe|#1e3a5f}"];
dyn -> bar [label="require()"];
}
entry -> dyn [label="import()", style=dashed];
}
```
Since there are two groups, in the end, automatic code splitting will generate two chunks.
## **Common chunks**
**Common chunks** are generated when a module gets statically imported by at least two different entries. Those modules are put into a separate chunk.
The purpose of this behavior is:
* Ensure every JavaScript module is singleton in the final bundle output.
* When a entry gets executed, only imported modules should get executed.
It is important to note that whether a module could be put into the same common chunk is determined by if it is imported by the same entries.
For the following code, six chunks will be generated:
```js
// entry-a.js (included in `input` option)
import 'shared-by-ab.js';
import 'shared-by-abc.js';
console.log(globalThis.value);
// entry-b.js (included in `input` option)
import 'shared-by-ab.js';
import 'shared-by-bc.js';
import 'shared-by-abc.js';
console.log(globalThis.value);
// entry-c.js (included in `input` option)
import 'shared-by-bc.js';
import 'shared-by-abc.js';
console.log(globalThis.value);
// shared-by-ab.js
globalThis.value = globalThis.value || [];
globalThis.value.push('ab');
// shared-by-bc.js
globalThis.value = globalThis.value || [];
globalThis.value.push('bc');
// shared-by-abc.js
globalThis.value = globalThis.value || [];
globalThis.value.push('abc');
```
The chunks will be generated as follows:
::: code-group
```js [entry-a.js]
import './common-ab.js';
import './common-abc.js';
```
```js [entry-b.js]
import './common-ab.js';
import './common-bc.js';
import './common-abc.js';
```
```js [entry-c.js]
import './common-bc.js';
import './common-abc.js';
```
```js [common-ab.js]
globalThis.value = globalThis.value || [];
globalThis.value.push('ab');
```
```js [common-bc.js]
globalThis.value = globalThis.value || [];
globalThis.value.push('bc');
```
```js [common-abc.js]
globalThis.value = globalThis.value || [];
globalThis.value.push('abc');
```
:::
The following diagram shows how entries share dependencies and how modules are grouped into chunks:
```dot
digraph {
bgcolor="transparent";
rankdir=TB;
node [shape=box, style="filled,rounded", fontname="Arial", fontsize=12, margin="0.2,0.1", color="${#3c3c43|#dfdfd6}", fontcolor="${#3c3c43|#dfdfd6}"];
edge [fontname="Arial", fontsize=10, color="${#3c3c43|#dfdfd6}", fontcolor="${#3c3c43|#dfdfd6}"];
newrank=true;
// Entry nodes
entry_a [label="entry-a.js", fillcolor="${#fff0e0|#4a2a0a}"];
entry_b [label="entry-b.js", fillcolor="${#fff0e0|#4a2a0a}"];
entry_c [label="entry-c.js", fillcolor="${#fff0e0|#4a2a0a}"];
// Shared module nodes
shared_ab [label="shared-by-ab.js", fillcolor="${#dbeafe|#1e3a5f}"];
shared_bc [label="shared-by-bc.js", fillcolor="${#dbeafe|#1e3a5f}"];
shared_abc [label="shared-by-abc.js", fillcolor="${#e0e7ff|#2e1065}"];
// Edges
entry_a -> shared_ab;
entry_a -> shared_abc;
entry_b -> shared_ab;
entry_b -> shared_bc;
entry_b -> shared_abc;
entry_c -> shared_bc;
entry_c -> shared_abc;
// Chunk grouping
subgraph cluster_chunk_a {
label="entry-a.js chunk";
labeljust="l";
fontname="Arial";
fontsize=11;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#d44803|#ff712a}";
entry_a;
}
subgraph cluster_chunk_b {
label="entry-b.js chunk";
labeljust="l";
fontname="Arial";
fontsize=11;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#d44803|#ff712a}";
entry_b;
}
subgraph cluster_chunk_c {
label="entry-c.js chunk";
labeljust="l";
fontname="Arial";
fontsize=11;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#d44803|#ff712a}";
entry_c;
}
subgraph cluster_common_ab {
label="common-ab.js chunk";
labeljust="l";
fontname="Arial";
fontsize=11;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#0366d6|#58a6ff}";
shared_ab;
}
subgraph cluster_common_bc {
label="common-bc.js chunk";
labeljust="l";
fontname="Arial";
fontsize=11;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#0366d6|#58a6ff}";
shared_bc;
}
subgraph cluster_common_abc {
label="common-abc.js chunk";
labeljust="l";
fontname="Arial";
fontsize=11;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#0366d6|#58a6ff}";
shared_abc;
}
}
```
`entry-*.js` chunks are generated by the reason discussed above. `common-*.js` chunks are the **common chunks**. These are created because:
* `common-ab.js`: `shared-by-ab.js` is imported by both `entry-a.js` and `entry-b.js`.
* `common-bc.js`: `shared-by-bc.js` is imported by both `entry-b.js` and `entry-c.js`.
* `common-abc.js`: `shared-by-abc.js` is imported by all 3 entries.
You may ask why automatic code splitting doesn't place `shared-by-*.js` files into a single common chunk. The reason is that doing so would violate the original code's intention.
For the example above, if a single common chunk were created, it will be like:
```js [common-all.js]
globalThis.value = globalThis.value || [];
globalThis.value.push('ab');
globalThis.value = globalThis.value || [];
globalThis.value.push('bc');
globalThis.value = globalThis.value || [];
globalThis.value.push('abc');
```
For this output, executing each entry will output `['ab', 'bc', 'abc']`. However, the original code outputs a different result for each entry:
* `entry-a.js`: `['ab', 'abc']`
* `entry-b.js`: `['ab', 'bc', 'abc']`
* `entry-c.js`: `['bc', 'abc']`
## Module Placing Order
Rolldown tries to place your modules in the order declared in the original code.
For the following code:
```js
// entry.js
import { foo } from './foo.js';
console.log(foo);
// foo.js
export var foo = 'foo';
```
Rolldown will try to calculate the order by emulating the execution, starting from entries.
In this case, the execution order is `[foo.js, entry.js]`. So the bundle output will be like:
```js [output.js]
// foo.js
var foo = 'foo';
// entry.js
console.log(foo);
```
### Respecting Execution Order doesn't take precedence
However, Rolldown sometimes places modules without respecting their original order. This is because ensuring that modules are singletons takes precedence over placing them in the declared order.
For the following code:
```js
// entry.js (included in `input` option)
import './setup.js';
import './execution.js';
import('./dyn-entry.js');
// setup.js
globalThis.value = 'hello, world';
// execution.js
console.log(globalThis.value);
// dyn-entry.js
import './execution.js';
```
The bundle output will be:
::: code-group
```js [entry.js]
import './common-execution.js';
// setup.js
globalThis.value = 'hello, world';
```
```js [dyn-entry.js]
import './common-execution.js';
```
```js [common-execution.js]
console.log(globalThis.value);
```
:::
`common-execution.js` is a common chunk. It is generated because `execution.js` is imported by both `entry.js` and `dyn-entry.js`.
```dot
digraph {
bgcolor="transparent";
rankdir=TB;
node [shape=box, style="filled,rounded", fontname="Arial", fontsize=12, margin="0.2,0.1", color="${#3c3c43|#dfdfd6}", fontcolor="${#3c3c43|#dfdfd6}"];
edge [fontname="Arial", fontsize=10, color="${#3c3c43|#dfdfd6}", fontcolor="${#3c3c43|#dfdfd6}"];
compound=true;
subgraph cluster_entry {
label="entry.js chunk";
labeljust="l";
fontname="Arial";
fontsize=11;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#d44803|#ff712a}";
entry [label="entry.js", fillcolor="${#fff0e0|#4a2a0a}"];
setup [label="setup.js", fillcolor="${#fff0e0|#4a2a0a}"];
}
subgraph cluster_dyn {
label="dyn-entry.js chunk";
labeljust="l";
fontname="Arial";
fontsize=11;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#d44803|#ff712a}";
dyn [label="dyn-entry.js", fillcolor="${#fff0e0|#4a2a0a}"];
}
subgraph cluster_common {
label="common-execution.js chunk";
labeljust="l";
fontname="Arial";
fontsize=11;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#0366d6|#58a6ff}";
execution [label="execution.js", fillcolor="${#dbeafe|#1e3a5f}"];
}
entry -> setup [label="import"];
entry -> execution [label="import"];
entry -> dyn [label="import()", style=dashed];
dyn -> execution [label="import"];
}
```
This example shows the problem, before bundling, the code outputs `hello, world`, but after bundling, it outputs `undefined`. Currently, there's no easy way to solve this problem, as well for other bundlers that output ESM.
::: info Related issues for other bundlers
* [evanw/esbuild#399](https://github.com/evanw/esbuild/issues/399)
* [rollup/rollup#4539](https://github.com/rollup/rollup/issues/4539)
:::
There are some discussions on how to solve this problem. One way is to move modules into additional common chunks whenever their original order would be violated, but that can fragment the output. Rolldown instead offers [`strictExecutionOrder`](/reference/OutputOptions.strictExecutionOrder), which wraps ESM module bodies so they can run in source order while keeping ESM output. When a wrapped dynamic entry ends up sharing its implementation chunk with other code, the rewritten `import()` triggers the implementation itself. Strict mode emits a small entry facade only where a real file is still needed — for example when another chunk statically loads the entry's chunk, or for chunks a plugin emits — so the output chunk shape can still change. By default strict mode wraps every eligible module; the experimental `onDemandWrapping` mode derives a conservative subset from predicted chunk execution hazards.
---
---
url: /in-depth/manual-code-splitting.md
---
# Manual Code Splitting
Manual code splitting is a powerful feature that allows you to do manual code splitting to complement the [automatic code splitting](./automatic-code-splitting.md). This is useful when you want to optimize the loading performance of your application by splitting it into smaller, more manageable pieces.
Before reading this guide, you should first understand the [automatic code splitting](./automatic-code-splitting.md) feature of Rolldown. This guide will explain how manual code splitting works and how to use it effectively.
Before we dive into the details, let's clarify some things first.
* Automatic code splitting and manual code splitting are not contradictory. Using manual code splitting does not mean disabling automatic code splitting.
A module will be either captured by automatic code splitting or manual code splitting depending on your configuration, but not both. If a module is not captured by manual code splitting, it will still be put into a chunk which is created by automatic code splitting while respecting the rules we explained in the [automatic code splitting](./automatic-code-splitting.md) guide.
## Why use manual code splitting?
The automatic code splitting doesn't take loading performance or cache invalidation into account. It simply groups modules based on their static imports. This can lead to suboptimal chunking, where large chunks are created that may not be performant for loading or cause cache invalidation for every deployment.
## How to use manual code splitting?
Let's take a look at the following example:
```jsx
// index.jsx
import * as ReactDom from 'react-dom';
import App from './App.jsx';
ReactDom.createRoot(document.getElementById('root')).render( );
// App.jsx
import * as React from 'react';
import { Button } from 'ui-lib';
export default function App() {
return alert('Button clicked!')} />;
}
```
and you get the following output:
```js [output-hash0.js]
// node_modules/react/index.js
'React library code';
// node_modules/ui-lib/index.js
'UI library code';
// node_modules/react-dom/index.js
'ReactDOM library code';
// App.js
function App() {
return alert('Button clicked!')} />;
}
// index.js
ReactDom.createRoot(document.getElementById('root')).render( );
```
In this example,
* We used 3 libraries: `react`, `react-dom`, and `ui-lib`.
* `output-hash0.js` is the output file generated by Rolldown.
* `hash0` is the hash of the output file, it changes if the content of the file changes.
### Reduce cache invalidation
Let's talk about cache invalidation first. Cache invalidation here means that when you deploy a new version of your application, the browser will need to download the new version of the file. If the file is large, this can lead to a poor user experience.
For example, if you change the `app.jsx` file:
```jsx [app.jsx]
function App() {
return alert('Button clicked!')} />; // [!code --]
return alert('Button clicked!!!')} />; // [!code ++]
}
```
then naturally, you get a `output-hash1.js` file with the same content as `output-hash0.js`, except for the change in the `App` function.
Now, if you deploy this new version of your application, the browser will need to download the entire `output-hash1.js` file, even though only a small part of it has changed. This is because the hash of the file has changed, and the browser will treat it as a new file.
To solve this problem, we can use the codeSplitting option to split output libraries into separate chunks, because they don't change frequently compared to application code.
```js [rolldown.config.js]
export default {
// ... other configurations
output: {
codeSplitting: {
groups: [
{
test: /node_modules/,
name: 'libs',
},
],
},
},
};
```
By using the above codeSplitting option, the output will look like this:
:::code-group
```js [output-hash0.js]
import ... from './libs-hash0.js';
// App.js
function App() {
return alert("Button clicked!")} />;
}
// index.js
ReactDom.createRoot(document.getElementById("root")).render( );
```
```js [libs-hash0.js]
// node_modules/react/index.js
"React library code";
// node_modules/ui-lib/index.js
"UI library code";
// node_modules/react-dom/index.js
"ReactDOM library code";
export { ... };
```
:::
For example, after you change the `app.jsx` file
```jsx [app.jsx]
function App() {
return alert('Button clicked!')} />; // [!code --]
return alert('Button clicked!!!')} />; // [!code ++]
}
```
you will get output like this:
:::code-group
```js [output-hash1.js]
import ... from './libs-hash0.js';
// App.js
function App() {
return alert("Button clicked!!!")} />;
}
// index.js
ReactDom.createRoot(document.getElementById("root")).render( );
```
```js [libs-hash0.js]
// node_modules/react/index.js
"React library code";
// node_modules/ui-lib/index.js
"UI library code";
// node_modules/react-dom/index.js
"ReactDOM library code";
export { ... };
```
:::
* The `libs-hash0.js` file is not changed, so the browser can use the cached version of the file.
* The `output-hash1.js` file is changed, so the browser will download the new version of the file.
### Improve loading performance
Manual code splitting can also be used to improve the loading performance of your application by splitting it into a practical number of chunks and taking advantage of browser's parallel loading capabilities.
In the previous example, we put all the libraries into a single chunk, which is not optimal for loading performance. If the libraries are too large, the browser will spend a long time downloading the chunk, which can lead to a poor user experience.
To solve this problem, we can use the codeSplitting option to split the libraries into separate chunks, so that the browser can download them in parallel.
```js [rolldown.config.js]
export default {
// ... other configurations
output: {
codeSplitting: {
groups: [
{
test: /node_modules\/react/,
name: 'react',
},
{
test: /node_modules\/react-dom/,
name: 'react-dom',
},
{
test: /node_modules\/ui-lib/,
name: 'ui-lib',
},
],
},
},
};
```
By using the above codeSplitting option, the output will look like this:
:::code-group
```js [output-hash0.js]
import ... from './react-hash0.js';
import ... from './react-dom-hash0.js';
import ... from './ui-lib-hash0.js';
// App.js
function App() {
return alert("Button clicked!")} />;
}
// index.js
ReactDom.createRoot(document.getElementById("root")).render( );
```
```js [react-hash0.js]
"React library code";
export { ... };
```
```js [react-dom-hash0.js]
"ReactDOM library code";
export { ... };
```
```js [ui-lib-hash0.js]
"UI library code";
export { ... };
```
:::
Now, the libraries are split into separate chunks, and the browser can download them in parallel. This can significantly improve the loading performance of your application, especially if the libraries are large.
## Limitations
### Why there's always a `runtime.js` chunk?
```dot
digraph {
bgcolor="transparent";
rankdir=TB;
node [shape=box, style="filled,rounded", fontname="Arial", fontsize=12, margin="0.2,0.1", color="${#3c3c43|#dfdfd6}", fontcolor="${#3c3c43|#dfdfd6}"];
edge [fontname="Arial", fontsize=10, color="${#3c3c43|#dfdfd6}", fontcolor="${#3c3c43|#dfdfd6}"];
compound=true;
subgraph cluster_problem {
label="Without runtime.js";
labeljust="l";
fontname="Arial";
fontsize=12;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#cb2431|#f85149}";
p_main [label="main.js", fillcolor="${#fff0e0|#4a2a0a}"];
p_first [label="first.js", fillcolor="${#dbeafe|#1e3a5f}"];
p_second [label="second.js\n(__esm, __export defined here)", fillcolor="${#dbeafe|#1e3a5f}"];
p_main -> p_first [label="imports"];
p_main -> p_second [label="imports __esm"];
p_first -> p_second [label="imports"];
p_second -> p_first [label="imports", color="${#cb2431|#f85149}", fontcolor="${#cb2431|#f85149}", style=dashed];
}
subgraph cluster_solution {
label="With runtime.js";
labeljust="l";
fontname="Arial";
fontsize=12;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#22863a|#3fb950}";
s_runtime [label="runtime.js\n(__esm, __export)", fillcolor="${#dcfce7|#14532d}"];
s_main [label="main.js", fillcolor="${#fff0e0|#4a2a0a}"];
s_first [label="first.js", fillcolor="${#dbeafe|#1e3a5f}"];
s_second [label="second.js", fillcolor="${#dbeafe|#1e3a5f}"];
s_main -> s_runtime [label="imports"];
s_main -> s_first [label="imports"];
s_first -> s_runtime [label="imports"];
s_first -> s_second [label="imports"];
s_second -> s_runtime [label="imports"];
s_second -> s_first [label="imports"];
}
}
```
tl;dr: If you used manual code splitting with groups, rolldown will forcefully generate a `runtime.js` chunk to ensure that the runtime code is always executed before any other chunks.
The `runtime.js` chunk is a special chunk that **only** contains the runtime code necessary for loading and executing your application. It is generated forcefully by the bundler to ensure that the runtime code is always executed before any other chunks.
Since manual code splitting allows you to move modules between chunks, it's easily to create a circular import in the output code. This can lead to a situation where the runtime code is not executed before the other chunks, causing errors in your application.
A example output code with circular import:
```js
// first.js
import { __esm, __export, init_second, value$1 as value } from './second.js';
var first_exports = {};
__export(first_exports, { value: () => value$1 });
var value$1;
var init_first = __esm({
'first.js'() {
init_second();
// ...
},
});
export { first_exports, init_first, value$1 as value };
// main.js
import { first_exports, init_first } from './first.js';
import { __esm, init_second, second_exports } from './second.js';
var init_main = __esm({
'main.js'() {
init_first();
init_second();
// ...
},
});
init_main();
// second.js
import { init_first, value } from './first.js';
var __esm = '...';
var __export = '...';
var second_exports = {};
__export(second_exports, { value: () => value$1 });
var value$1;
var init_second = __esm({
'second.js'() {
init_first();
// ...
},
});
export { __esm, __export, init_second, second_exports, value$1 };
```
When we run `node ./main.js`, the traversal order of the modules would be `main.js` -> `first.js` -> `second.js`. The module execution order would be `second.js` -> `first.js` -> `main.js`.
`second.js` tries to call `__esm` function before it gets initialized. This will lead to a runtime error which is trying to call `undefined` as a function.
With forcefully generated `runtime.js`, the bundler ensures any chunk that depends on runtime code would first load `runtime.js` before executing itself. This guarantees that the runtime code is always executed before any other chunks, preventing circular import issues.
### Why does the group contain modules that don't satisfy the constraints?
When a module is captured by a group, Rolldown will try to capture its dependencies recursively without considering constraints. This is because Rolldown is only allowed to mangle the exports of non-entry chunks by default.
For example, if you have the following code:
```js
// entry.js
import { value } from './a.js';
console.log(value);
export const foo = 'foo';
// a.js
import { value as valueB } from './b.js';
export const value = 'a' + valueB;
// b.js
export const value = 'b';
```
Let's say we want to move the `a.js` module into a separate chunk while keeping the `b.js` module in the same chunk as `entry.js`. We get
:::code-group
```js [entry.js]
import { value } from './a.js';
// b.js
const value = 'b';
// entry.js
const foo = 'foo';
console.log(value);
export { foo, value };
```
```js [a.js]
import { value } from './entry.js';
// a.js
export const value = 'a' + value;
```
:::
You could see, to make `a.js` work, we have to change the export signature of the entry chunk `entry.js` and add an additional export `value`. This totally violates the original intention of the code, which is to only export `foo` from `entry.js`.
If you don't want this behavior, you could use [`codeSplitting.includeDependenciesRecursively: false`](/reference/OutputOptions.codeSplitting#includedependenciesrecursively) to disable it.
:::warning Caveats
With `includeDependenciesRecursively: false`, depended modules of a group might be left in the entry chunks. It's invalid to export non-entry module from an entry chunk. To avoid this, Rolldown will implicitly set `preserveEntrySignatures: 'allow-extension'` if you didn't set it explicitly.
* [`InputOptions.preserveEntrySignatures: false | 'allow-extension'`](/reference/InputOptions.preserveEntrySignatures)
`includeDependenciesRecursively: false` increases the chance of generating invalid output code. If you encounter issues due to execution order or circular dependencies, consider enabling:
* [`strictExecutionOrder: true`](/reference/OutputOptions.strictExecutionOrder)
:::
### Why is the chunk bigger than `maxSize`?
`maxSize` acts as a target rather than a strict limit. A chunk may exceed this value in the following scenarios:
* If a single module is larger than `maxSize`, the resulting chunk will exceed the limit. Rolldown does not currently support splitting a single module into multiple chunks.
* Rolldown prioritizes the `minSize` configuration. If splitting a large chunk would result in new chunks that fall below the `minSize` threshold, Rolldown will keep the original chunk undivided to avoid generating excessively small files.
---
---
url: /in-depth/bundling-cjs.md
---
# Bundling CJS
Rolldown provides first-class support for CommonJS modules. This document explains how Rolldown handles CJS modules and their interoperability with ES modules.
## Key Features
### Native CJS Support
Rolldown automatically recognizes and processes CommonJS modules without requiring any additional plugins or packages. This native support means:
* No need to install extra dependencies
* Better performance compared to plugin-based solutions
### On-demand Execution
Rolldown preserves the on-demand execution semantics of CommonJS modules, which is a key feature of the CommonJS module system. This means modules are only executed when they are actually required.
Here's an example:
```js
// index.js
import { value } from './foo.js';
const getFooExports = () => require('./foo.js');
// foo.js
module.exports = { value: 'foo' };
```
When bundled, it produces:
```js
// #region \0rolldown/runtime.js
// ...runtime code
// #endregion
// #region foo.js
var require_foo = __commonJS({
'foo.js'(exports, module) {
module.exports = { value: 'foo' };
},
});
// #endregion
// #region index.js
const getFooExports = () => require_foo();
// #endregion
```
In this example, the `foo.js` module won't be executed until `getFooExports()` is called, maintaining the lazy-loading behavior of CommonJS.
### ESM/CJS Interoperability
Rolldown provides seamless interoperability between ES modules and CommonJS modules.
Example of ESM importing from CJS:
```js
// index.js
import { value } from './foo.js';
console.log(value);
// foo.js
module.exports = { value: 'foo' };
```
Bundled output:
```js
// #region \0rolldown/runtime.js
// ...runtime code
// #endregion
// #region foo.js
var require_foo = __commonJS({
'foo.js'(exports, module) {
module.exports = { value: 'foo' };
},
});
// #endregion
// #region index.js
var import_foo = __toESM(require_foo());
console.log(import_foo.value);
// #endregion
```
The `__toESM` helper ensures that CommonJS exports are properly converted to ES module format, allowing seamless access to the exported values.
## Caveats
### `require` external modules
By default, Rolldown tries to keep the semantics of `require` and does not convert `require` against external modules to `import`. This is because the semantics of `require` are different from `import` in ES modules. For example, `require` are evaluated lazily, while `import` are evaluated before the code is executed.
::: tip Still want to convert `require` to `import`?
If you want to convert `require` calls to `import` statements, you can use [the built-in `esmExternalRequirePlugin`](/builtin-plugins/esm-external-require). Note that the plugin must own the externals it converts: list them in the plugin's `external` option, not in the top-level `external` option.
:::
For [`platform: 'node'`](../guide/notable-features.md#platform-presets), Rolldown will generate a `require` function from [`module.createRequire`](https://nodejs.org/docs/latest/api/module.html#modulecreaterequirefilename). This keeps the semantics of `require` completely intact. Note that compared to converting to `import`, there's two downsides to this approach:
1. Requires the `module.createRequire` function support in the runtime, which may not be available in partially Node compatible environments
2. Unsuitable for libraries that expects to be bundled as the `require` function will be a local variable and that makes it harder for bundlers to statically analyze the code
For other platforms, Rolldown will leave it as-is, allowing the running environment to provide a `require` function or inject one manually. For example, you can inject the `require` function that returns the value obtained by `import` by using [`inject` feature](../guide/notable-features.md#inject).
::: code-group
```js [rolldown.config.js]
import path from 'node:path';
export default {
inject: {
require: path.resolve('./require.js'),
},
};
```
```js [require.js]
import fs from 'node:fs';
export default (id) => {
if (id === 'node:fs') {
return fs;
}
throw new Error(`Requiring ${JSON.stringify(id)} is not allowed.`);
};
```
:::
### Ambiguous `default` import from CJS modules
In the ecosystem, there's two common ways to handle imports from CJS modules. While Rolldown tries to support both interpretations automatically, they are **incompatible for `default` imports**. In that case, Rolldown uses a similar heuristic to [Webpack](https://webpack.js.org/) and [esbuild](https://esbuild.github.io/) to determine the value of `default` imports.
If it matches one of the conditions below, the `default` import is the `module.exports` value of the importee CJS module. Otherwise, the `default` import is the `module.exports.default` value of the importee CJS module.
* The importer is `.mjs` or `.mts`
* (When it's a dynamic import) The importer is `.cjs` or `.cts`
* The closest `package.json` for the importer has a `type` field set to `module`
* (When it's a dynamic import) The closest `package.json` for the importer has a `type` field set to `commonjs`
* The `module.exports.__esModule` value of the importee CJS module is not set to `true`
* The `module.exports` value of the importee CJS module has no own `default` property
The last condition handles CJS modules that set `__esModule` without actually shipping a `default` export (for example tslib's UMD build). Without it, the `default` import would be `undefined`. `@rollup/plugin-commonjs` handles this case with the same fallback.
:::: details Behavior in details
Let's assume the following ESM importer module and CJS importee module:
::: code-group
```js [index.js]
import foo from './importee.cjs';
console.log(foo);
```
```js [importee.cjs]
Object.defineProperty(module.exports, '__esModule', {
value: true,
});
module.exports.default = 'foo';
```
:::
In the first interpretation, the way [Babel](https://babel.dev/) interprets, this code will print `foo`. In this interpretation, the behavior is changed based on the `__esModule` flag. `__esModule` is commonly set by transformers to indicate that the module was written in ESM syntax (e.g. `export default 'foo'` in this case) and was transformed to CJS syntax. The rationale for this behavior is that the transformed module should behave the same as the original module did without the transformation. [`@rollup/plugin-commonjs`](https://github.com/rollup/plugins/tree/master/packages/commonjs) uses this interpretation by default.
In the second interpretation, the way Node.js interprets, this code will print `{ default: 'foo' }`. The rationale for this behavior is that CJS modules sets the export keys dynamically while ESM requires the export keys to be statically known, so to allow accessing all the exports, the entire `module.exports` is exposed as the default export. `@rollup/plugin-commonjs` uses this interpretation when `defaultIsModuleExports: false` is set.
These two interpretations expects different values for `default` imports and Rolldown has to decide which one to use.
::::
::: details What is the rationale for this heuristic?
Rolldown's heuristic is based on the assumption that the files affected by Node.js's module determination concept are expected to be runnable in Node.js. For ESM files to be runnable in Node.js, they need to have `.mjs` or the closest `package.json` to have a `type` field set to `module` ([so that the ESM loader is used](https://nodejs.org/api/packages.html#determining-module-system)), and the code should be written in a way that expects the Node.js interpretation. On the otherhand, for files written in ESM syntax but not marked as ESM in the Node.js's module determination concept, the code is highly likely to be transformed by other tools, which commonly follows the Babel's interpretation.
:::
#### Recommendations for Library Authors
If you are writing a new code, we strongly recommend you to **publish your code as ESM syntax**. With [the `require(ESM)` feature](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require) shipped in Node.js, there's no major blocker to do so.
If you still need to publish your code as CJS syntax, we strongly recommend to **avoid using the `default` export**.
When importing a default export from a CJS module, we recommend to write a code that handles both interpretations. For example, you can use the following code to handle both interpretations:
```js
import rawFoo from './importee.cjs';
const foo =
typeof rawFoo === 'object' && rawFoo !== null && rawFoo.__esModule ? rawFoo.default : rawFoo;
console.log(foo);
```
This code will print `foo` in both interpretations. Note that TypeScript may show a type error when using this code; this is because [TypeScript does not support this behavior](https://github.com/microsoft/TypeScript/issues/54102), but it is safe to ignore the error.
#### Recommendations for Library Users
If you find an issue that seems to be caused by this incompatibility, try using [publint](https://publint.dev/) to check the package. It has [a rule that detects the incompatibility](https://publint.dev/rules#cjs_with_esmodule_default_export) (note that it only checks some of the files in the package, not all of them).
If the heuristic is not working for you, you can use the code in the section above that handles both interpretations. If the import is in a dependency, we recommend to raise an issue to the dependency. In the meantime, you can use [`patch-package`](https://github.com/ds300/patch-package) or [`pnpm patch`](https://pnpm.io/cli/patch) or alternatives as an escape hatch.
### Strict Mode Applied to `.js` files
For files ending with `.js`, Rolldown parses the file as ESM ([#7009](https://github.com/rolldown/rolldown/issues/7009)) without falling back to CJS. This means that syntaxes only allowed in non-strict mode (sloppy mode) will be rejected.
For now, you can change the file extension to `.cjs` as a workaround.
## Future Plans
Rolldown's first-class support for CommonJS modules enables several potential optimizations:
* Advanced tree-shaking capabilities for CommonJS modules
* Better dead code elimination
---
---
url: /in-depth/non-esm-output-formats.md
---
# Non ESM Output Formats
Rolldown supports non-ESM output formats. Some features in ESM are not supported in non-ESM formats and Rolldown will emit messages or provide polyfills for them.
## Top Level Await
Top level await is not supported in non-ESM formats. Rolldown outputs an error if it encounters top level await when the output format is not ESM.
## `import.meta`
`import.meta` is a syntax error in non-ESM formats. To avoid that from happening, Rolldown replaces `import.meta` with other values.
### Well-known `import.meta` properties
Rolldown supports the following well-known `import.meta` properties:
* `import.meta.url`
* `import.meta.dirname`
* `import.meta.filename`
These properties are polyfilled when the output format is CJS. In other formats, it will be handled as same as the other properties.
:::: tip Polyfilling `import.meta.url` in IIFE and UMD
Rollup supports polyfilling `import.meta.url` in IIFE and UMD formats. However, Rolldown does not support this feature. If you need to polyfill it, you can use the following config:
::: code-group
```ts [rolldown.config.ts (IIFE)]
import { defineConfig } from 'rolldown';
const importMetaUrlPolyfillVariableName = '__import_meta_url__';
export default defineConfig({
transform: {
define: {
'import.meta.url': importMetaUrlPolyfillVariableName,
},
},
output: {
format: 'iife',
intro:
"var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;" +
`var ${importMetaUrlPolyfillVariableName} = (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('main.js', document.baseURI).href)`,
},
});
```
```ts [rolldown.config.ts (UMD)]
import { defineConfig } from 'rolldown';
const importMetaUrlPolyfillVariableName = '__import_meta_url__';
export default defineConfig({
transform: {
define: {
'import.meta.url': importMetaUrlPolyfillVariableName,
},
},
output: {
format: 'umd',
intro:
"var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;" +
`var ${importMetaUrlPolyfillVariableName} = (typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('main.js', document.baseURI).href))`,
},
});
```
:::
::::
### Other properties and `import.meta` object itself
Other properties and `import.meta` object itself are replaced with `{}`. Since this does not keep the original value, Rolldown emits a warning in this case.
---
---
url: /in-depth/tla-in-rolldown.md
---
# Top Level Await(TLA) in Rolldown
Background knowledge:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#top\_level\_await
* https://github.com/tc39/proposal-top-level-await
## How rolldown handles TLA
At this point, the principle of supporting TLA in rolldown is: we will make it work after bundling without preserving 100% semantic as the original code.
Current rules are:
* If your input contains TLA, it could only be bundled and emitted with `esm` format.
* `require` TLA module is forbidden.
## Concurrent to sequential
One downside of TLA in rolldown is that it will change the original code's behavior from concurrent to sequential. It still ensures the relative order, but indeed slows down the execution and may break the execution if the original code relies on concurrency.
```dot
digraph {
bgcolor="transparent";
rankdir=LR;
node [shape=box, style="filled,rounded", fontname="Arial", fontsize=12, margin="0.2,0.1", color="${#3c3c43|#dfdfd6}", fontcolor="${#3c3c43|#dfdfd6}"];
edge [fontname="Arial", fontsize=10, color="${#3c3c43|#dfdfd6}", fontcolor="${#3c3c43|#dfdfd6}"];
compound=true;
subgraph cluster_before {
label="Before bundling (concurrent)";
labeljust="l";
fontname="Arial";
fontsize=12;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#22863a|#3fb950}";
b_main [label="main.js\nimport tla1, tla2", fillcolor="${#fff0e0|#4a2a0a}"];
b_all [label="Promise.all([\n tla1,\n tla2\n])", fillcolor="${#dcfce7|#14532d}"];
b_tla1 [label="tla1.js\nawait ...", fillcolor="${#dbeafe|#1e3a5f}"];
b_tla2 [label="tla2.js\nawait ...", fillcolor="${#dbeafe|#1e3a5f}"];
b_done [label="both resolved", fillcolor="${#dcfce7|#14532d}"];
b_main -> b_all;
b_all -> b_tla1;
b_all -> b_tla2;
b_tla1 -> b_done;
b_tla2 -> b_done;
}
subgraph cluster_after {
label="After bundling (sequential)";
labeljust="l";
fontname="Arial";
fontsize=12;
fontcolor="${#3c3c43|#dfdfd6}";
style="dashed,rounded";
color="${#d44803|#ff712a}";
a_tla1 [label="await tla1", fillcolor="${#dbeafe|#1e3a5f}"];
a_tla2 [label="await tla2", fillcolor="${#dbeafe|#1e3a5f}"];
a_main [label="console.log(\n foo1, foo2\n)", fillcolor="${#fff0e0|#4a2a0a}"];
a_tla1 -> a_tla2 [label="then"];
a_tla2 -> a_main [label="then"];
}
}
```
A real-world example would looks like
```js
// main.js
import { bar } from './sync.js';
import { foo1 } from './tla1.js';
import { foo2 } from './tla2.js';
console.log(foo1, foo2, bar);
// tla1.js
export const foo1 = await Promise.resolve('foo1');
// tla2.js
export const foo2 = await Promise.resolve('foo2');
// sync.js
export const bar = 'bar';
```
After bundling, it will be
```js
// tla1.js
const foo1 = await Promise.resolve('foo1');
// tla2.js
const foo2 = await Promise.resolve('foo2');
// sync.js
const bar = 'bar';
// main.js
console.log(foo1, foo2, bar);
```
You can see that, in bundled code, promise `foo1` and `foo2` are resolved sequentially, but in the original code, they are resolved concurrently.
There's a very [good example](https://github.com/tc39/proposal-top-level-await?tab=readme-ov-file#semantics-as-desugaring) of TLA spec repo, which explains the mental model of how the TLA works
```js
import { a } from './a.mjs';
import { b } from './b.mjs';
import { c } from './c.mjs';
console.log(a, b, c);
```
could be considered as the following code after desugaring:
```js
import { a, promise as aPromise } from './a.mjs';
import { b, promise as bPromise } from './b.mjs';
import { c, promise as cPromise } from './c.mjs';
export const promise = Promise.all([aPromise, bPromise, cPromise]).then(() => {
console.log(a, b, c);
});
```
However, in rolldown, it will looks like this after bundling:
```js
import { a, promise as aPromise } from './a.mjs';
import { b, promise as bPromise } from './b.mjs';
import { c, promise as cPromise } from './c.mjs';
await aPromise;
await bPromise;
await cPromise;
console.log(a, b, c);
```
---
---
url: /in-depth/dead-code-elimination.md
---
# Dead Code Elimination
Dead code elimination (DCE) is an optimization technique that removes unused code from your bundle, making it smaller and faster to load.
Rolldown removes code that meets **both** of these conditions:
1. **Not used** - The value is never used
2. **Has no side effects** - Removing the code won't change the program's behavior
Here's a simple example:
```js
// math.js
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
// main.js
import { add } from './math.js';
console.log(add(2, 3));
```
In this example, `multiply` is never imported and has no side effects, so Rolldown removes it from the final bundle.
::: tip Tree-Shaking
Tree-shaking is a related term [popularized by Rollup](https://rollupjs.org/faqs/#what-is-tree-shaking). It refers to a specific technique for dead code elimination that works by "shaking" the syntax tree to remove unused code.
:::
## What Are Side Effects?
A side effect is any operation that affects something outside its own scope. Common side effects include:
* Modifying global variables or the DOM
* Importing CSS files (which apply styles to the page)
* Polyfills that modify prototypes or global objects
```js
// side effect: applies styles
import './styles.css';
// side effect: modifies global
window.API_URL = '/api';
// side effect: modifies prototype
Array.prototype.first = function () {
return this[0];
};
```
## How Rolldown Detects Side Effects
Rolldown automatically analyzes your code to detect side effects by examining:
* Whether the module has top-level code that runs on import
* Whether function calls might modify external state
* Whether property accesses might trigger getters with side effects
However, static analysis has limitations. Some patterns are too dynamic to analyze, so Rolldown may conservatively keep code when it's uncertain. You can tune this behavior with [`treeshake.unknownGlobalSideEffects`](/reference/InputOptions.treeshake#unknownglobalsideeffects) and [`treeshake.propertyReadSideEffects`](/reference/InputOptions.treeshake#propertyreadsideeffects).
You can also help Rolldown perform more aggressive dead code elimination by explicitly marking code as side-effect-free.
## Marking Code as Side-Effect-Free
You can use annotation comments to tell Rolldown that a piece of code is side-effect-free. They are enabled by default and can be disabled with [`treeshake.annotations`](/reference/InputOptions.treeshake#annotations).
### `@__PURE__`
The `@__PURE__` annotation tells the bundler that a function call or `new` expression has no side effects. If the result is unused, the entire call can be removed.
```js
const button = /* @__PURE__ */ createButton();
const widget = /* @__PURE__ */ new Widget();
```
If `button` and `widget` are never used, Rolldown removes both calls entirely. Without the annotations, Rolldown would keep them because it can't be certain `createButton()` and `new Widget()` have no side effects.
The annotation must appear **immediately before** the call or `new` expression for it to apply. If it is placed elsewhere, Rolldown emits an `INVALID_ANNOTATION` warning.
::: warning Common invalid positions
```js
// Before a non-call expression
/* @__PURE__ */ globalThis.createElement;
// Before a declaration
/* @__PURE__ */ function foo() {}
// Between an identifier and `=` in a variable declarator
const foo /* @__PURE__ */ = bar();
```
:::
::: tip
The annotation can also be written as `/* #__PURE__ */` (with `#` instead of `@`) for compatibility with other tools.
:::
### `@__NO_SIDE_EFFECTS__`
The `@__NO_SIDE_EFFECTS__` annotation tells the bundler that any call of this function declaration has no side effects.
```js
/* @__NO_SIDE_EFFECTS__ */
function createComponent(name) {
return {
name,
render() {
return `<${name}>${name}>`;
},
};
}
// This call will be removed if `button` is unused
const button = createComponent('button');
// This call will also be removed if `input` is unused
const input = createComponent('input');
```
This can be more convenient than adding `@__PURE__` to every call site when you know the function itself is always pure.
## Marking Entire Modules as Side-Effect-Free
While you can mark individual expressions or functions, you can also mark entire modules as side-effect-free. If you mark a module as side-effect-free, Rolldown will treat every statement in that module as side-effect-free when none of its exports are used.
::: details What does "none of its exports are used" mean?
This refers to the exports that are **defined in the module itself**, not re-exports from other modules.
```js [utils.js]
// assume that this file is marked as side-effect-free
window.loaded = true; // side effect
// Defined in this file - counts as "its exports"
export function add(a, b) {
return a + b;
}
// Re-exported from another file - these does NOT count
export { multiply } from './math.js';
export * from './math2.js';
import { divide } from './math3.js';
export { divide };
```
In this example:
* If you `import { add } from './utils.js'`, the module is considered "used" because `add` is defined in `utils.js`
* If you only `import { multiply } from './utils.js'`, the module is considered "unused" because `multiply` is just re-exported, not defined here
:::
For example, consider this case:
```js
// math.js
window.myGlobal = 'hello'; // side effect: modifies global
export function add(a, b) {
return a + b;
}
// main.js
import './math.js';
console.log('main');
```
If `math.js` is marked as side-effect-free, the output will be:
```js
console.log('main');
```
:::: warning This is conditional
The statements are only treated as side-effect-free when none of the module's exports are used. If any export is used, side effects are preserved.
::: details Example
For example, consider this case:
```js
// math.js (marked as side-effect-free)
window.myGlobal = 'hello'; // side effect: modifies global
export function add(a, b) {
return a + b;
}
// main.js
import { add } from './math.js';
console.log('main', add(2, 3));
```
The output will be:
```js
window.myGlobal = 'hello';
function add(a, b) {
return a + b;
}
console.log('main', add(2, 3));
```
On the other hand, if you mark every statement in `math.js` as side-effect-free, the output will be:
```js
function add(a, b) {
return a + b;
}
console.log('main', add(2, 3));
```
:::
::::
#### `sideEffects` in package.json
The `sideEffects` field in `package.json` tells bundlers which files in your package have side effects:
```json [package.json]
{
"name": "my-library",
"sideEffects": false
}
```
Setting `sideEffects: false` marks all files in the package as side-effect-free, which is common for utility libraries.
You can also specify an array of files that have side effects:
```json [package.json]
{
"name": "my-library",
"sideEffects": ["./src/polyfill.js", "**/*.css"]
}
```
This tells Rolldown that most files have no side effects and can be removed if unused, except for `polyfill.js` and CSS files which must be preserved.
The array accepts glob patterns (supports `*`, `**`, `{a,b}`, `[a-z]`). Patterns like `*.css` that do not include a `/` will be treated as `**/*.css`.
::: warning CSS Files
If your library imports CSS files, make sure to include them in the `sideEffects` array. Otherwise, the CSS imports may be removed:
```json [package.json]
{
"name": "my-component-library",
"sideEffects": ["**/*.css", "**/*.scss"]
}
```
:::
#### Plugin Hook: `moduleSideEffects`
Plugins can return [`moduleSideEffects`](/reference/Interface.SourceDescription#modulesideeffects) from the `resolveId`, `load`, or `transform` hooks to override side effect detection for specific modules:
```js [rolldown.config.js]
export default {
plugins: [
{
name: 'my-plugin',
resolveId(source) {
if (source === 'my-pure-module') {
return {
id: source,
moduleSideEffects: false,
};
}
return null;
},
},
],
};
```
The priority order for determining a module's side effects is:
1. `transform` hook's returned `moduleSideEffects`
2. `load` hook's returned `moduleSideEffects`
3. `resolveId` hook's returned `moduleSideEffects`
4. [`treeshake.moduleSideEffects`](/reference/InputOptions.treeshake#modulesideeffects) option
5. `sideEffects` field in `package.json`
## Example: Optimizing a Component Library
Consider a component library with this structure:
```
my-component-lib/
├── package.json
└── src/
├── index.js
└── components/
├── Button.js
├── Button.css
├── Modal.js
└── Modal.css
```
::: code-group
```js [src/index.js]
export { Button } from './components/Button.js';
export { Modal } from './components/Modal.js';
```
```js [src/components/Button.js]
import './Button.css';
export function Button(props) {
/* ... */
}
```
:::
To ensure unused components can be removed, mark only the CSS files as having side effects:
```json [package.json]
{
"name": "my-component-lib",
"sideEffects": ["**/*.css"]
}
```
Now when a consumer imports only `Button`:
```js
import { Button } from 'my-component-lib';
render( );
```
Rolldown will:
1. Include `components/Button.js` (because `Button` is used)
2. Include `components/Button.css` (because it's imported by `components/Button.js` and marked as having side effects)
3. Exclude `components/Modal.js` (because `Modal` is not used)
4. Exclude `components/Modal.css` (because `components/Modal.js` is excluded)
---
---
url: /in-depth/lazy-barrel-optimization.md
---
# Lazy Barrel Optimization
Lazy barrel is an optimization feature that enhances build performance by avoiding compilation of unused re-export modules in side-effect-free [barrel modules](/glossary/barrel-module).
## Why use Lazy Barrel
Large component libraries like [Ant Design](https://ant.design/) use barrel modules extensively. When you import just one component, the bundler traditionally compiles thousands of modules, most of which are unused.
Here's a real-world example importing only `Button` from antd:
```js
import { Button } from 'antd';
Button;
```
| Metric | Without lazy barrel | With lazy barrel |
| -------------------- | ------------------- | ---------------- |
| Modules compiled | 2986 | 250 |
| Build time (macOS) | ~65ms | ~28ms |
| Build time (Windows) | ~210ms | ~50ms |
By enabling lazy barrel, Rolldown reduces the number of compiled modules by **92%** and speeds up the build by **2-4x**.
::: tip
You can reproduce this benchmark using the [lazy-barrel example](https://github.com/rolldown/benchmarks/tree/main/examples/lazy-barrel).
:::
## How Lazy Barrel works
When enabled, Rolldown analyzes which exports are actually used and only compiles those modules. The unused re-export modules are skipped, significantly improving build performance for large codebases with many barrel modules.
### Basic example
```js
// barrel/index.js
export { a } from './a';
export { b } from './b';
// main.js
import { a } from './barrel';
console.log(a);
```
With lazy barrel optimization:
* `barrel/index.js` is loaded and analyzed
* Only `a.js` is compiled since `a` is imported
* `b.js` is **not** compiled since `b` is not used
## Supported export patterns
Lazy barrel optimization works with various export patterns:
### Star re-exports
```js
export * from './components';
```
### Named re-exports
```js
export { Component } from './Component';
export { helper as utils } from './helper';
export { default as Button } from './Button';
export { Button as default } from './Button';
```
### Namespace re-exports
```js
export * as ns from './module';
```
### Import-then-export patterns
```js
// Equivalent to `export { a } from './a'`
import { a } from './a';
export { a };
// Equivalent to `export { a as default } from './a'`
import { a } from './a';
export { a as default };
// Equivalent to `export * as ns from './module'`
import * as ns from './module';
export { ns };
// Equivalent to `export { default as b } from './b'`
import b from './b';
export { b };
```
### Mixed exports
```js
export { a } from './a';
export * as ns from './b';
export * from './others';
export * from './more';
```
When an import can be found in named exports, star exports are not searched, avoiding unnecessary module loading.
However, if the import is not found in named exports, all star re-exports will be loaded to resolve it. If those star re-exported modules are also barrel modules, only the specific import specifier will be loaded from them.
:::: warning Re-export vs Own export for default
`export { Button as default } from './Button.js'` and `import { Button } from './Button.js'; export default Button` are **not equivalent**.
In the former case, the value exported is synced with the value in `Button.js`. This is because it points to the same variable.
In the latter case, the value exported is not synced with the value in `Button.js`. This is because `export default ...` creates a new variable.
This example shows the difference:
::: code-group
```js [main.js]
import { Button, increment } from './Button.js';
import ExportDefaultButton, { ReExportedButton } from './re-exporter.js';
console.log(Button); // 1
console.log(ReExportedButton); // 1
console.log(ExportDefaultButton); // 1
increment();
console.log(Button); // 2
console.log(ReExportedButton); // 2
console.log(ExportDefaultButton); // 1
```
```js [re-exporter.js]
import { Button } from './Button.js';
export default Button;
export { Button as ReExportedButton } from './Button.js';
```
```js [Button.js]
export let Button = 1;
export const increment = () => {
Button++;
};
```
:::
For this reason, `export default ...` is considered an own export and may prevent the optimization (see [Own exports](#own-exports-non-pure-re-export-barrels)).
::::
## Advanced scenarios
### Self re-export
Lazy barrel correctly handles barrel modules that re-export from themselves:
```js
// barrel/index.js
export { a } from './a';
export { a as b } from './index'; // self re-export
```
### Circular exports
Lazy barrel correctly handles circular export relationships between barrel modules:
```js
// barrel-a/index.js
export { a } from './a';
export * from '../barrel-b';
// barrel-b/index.js
export { b } from './b';
export { a as c } from '../barrel-a'; // circular reference
```
### Dynamic import entry
When a barrel module is dynamically imported, it becomes an entry point and all its exports must be available:
```js
// barrel/a.js
export const a = 'a';
import('./index.js'); // makes barrel an entry point
// barrel/index.js
export { a } from './a';
export { b } from './b'; // b.js will be loaded
```
However, if `b.js` is also a barrel module, its unused exports will still be optimized.
### Unused import specifiers
By default, even if an imported specifier is not used, its corresponding module will still be loaded:
```js
// barrel/index.js
export { a } from './a';
export { b } from './b';
// main.js
import { a } from './barrel'; // a.js is loaded even if `a` is never used
```
### Own exports (non-pure re-export barrels)
When a barrel module has its own exports (not just re-exports), all its import records must be loaded when any own export is used:
```js
// barrel/index.js
import './a';
import { b } from './b';
import { e } from './e';
export { c } from './c';
export { d } from './d';
export { e };
console.log(b);
export const index = 'index'; // own export
export default b; // `default` is an own export
// main.js
import { index, c } from './barrel';
// or import b, { c } from './barrel';
```
In this case, when `index` is imported: `a.js`, `b.js`, `c.js`, `d.js`, and `e.js` are all loaded:
* `import './a'` - `a.js` is loaded with no specifier requested
* `import { b } from './b'` - `b.js` is loaded with `b` requested (used by the barrel's own code)
* `import { e } from './e'; export { e }` (import-then-export) - `e.js` is loaded with `e` requested, because Rolldown cannot statically determine whether the barrel's own code also uses `e`
* `export { c } from './c'` (dedicated re-export) - `c.js` is loaded with `c` requested (because main.js imports `c`)
* `export { d } from './d'` (dedicated re-export) - `d.js` is loaded with no specifier requested (like `import './d'`, since `d` is not imported in main.js)
Note the distinction between a dedicated re-export record (`export { .. } from '..'`, `export * as ns from '..'`) and a shared import record produced by the import-then-export pattern. When the barrel's own exports are loaded by main.js and the barrel must execute, dedicated re-export records can still fall back to an empty specifier set if their binding is not requested by main.js. Shared import records, by contrast, always keep their full specifiers, since their bindings may be referenced by the barrel's own code.
This happens because `moduleSideEffects` can only be determined after the transform hook, but lazy barrel decisions are made at the load stage. When the barrel must execute (due to own exports being used), all its imports must be loaded to ensure correct behavior.
If the loaded modules (`a.js`, `b.js`, etc.) are also barrel modules, lazy barrel optimization still applies to them recursively based on whether specifiers are requested.
## Configuration
Lazy barrel optimization is currently disabled by default. You can enable it in your Rolldown configuration:
```js
// rolldown.config.js
export default {
experimental: {
lazyBarrel: true,
},
};
```
::: warning
This option is planned to be removed in the future. If you need to opt out, please [open an issue](https://github.com/rolldown/rolldown/issues) describing your use case so we can address it before the option is gone.
:::
## Requirements
For lazy barrel optimization to work, barrel modules need to be marked as side-effect-free explicitly:
1. **Package declaration**: Adding `"sideEffects": false` to `package.json`
2. **Rolldown plugin hooks**: Returning `moduleSideEffects: false` from `resolveId`, `load`, or `transform` hooks
```js
// rolldown.config.js
export default {
plugins: [
{
name: 'mark-barrel-side-effect-free',
transform(code, id) {
if (id.includes('/barrel/')) {
return { moduleSideEffects: false };
}
},
},
],
};
```
3. **Rolldown configuration**: Using the `treeshake.moduleSideEffects` option
```js
// rolldown.config.js
export default {
treeshake: {
moduleSideEffects: [
// Mark barrel modules as side-effect-free using regex
{ test: /\/barrel\//, sideEffects: false },
// Or mark specific paths
{ test: /\/components\/index\.js$/, sideEffects: false },
],
},
};
```
You can also use a function for more complex logic:
```js
// rolldown.config.js
export default {
treeshake: {
moduleSideEffects: (id) => {
// Mark all index.js files as side-effect-free
if (id.endsWith('/index.js')) return false;
return true;
},
},
};
```
## When to use
Lazy barrel optimization is particularly beneficial when:
* Your codebase has many barrel modules (common in component libraries)
* Barrel modules re-export many modules but consumers typically use only a few
## Large barrel modules
Lazy barrel skips loading, parsing, and transforming unused re-exports, but the **resolve** step still runs for every entry. The resolver invokes `resolveId` plugin hooks for each import record, so a barrel with thousands of re-exports can dominate build time even when only a handful of them are actually used.
A typical example is `@mui/icons-material/esm/index.js`, which contains more than 10,000 re-export entries. When such a file is loaded, Rolldown still issues a resolve for every one of them, even though lazy barrel ensures only the requested icons are loaded and transformed afterwards.
When `experimental.lazyBarrel` is enabled and a barrel module contains more than 5,000 re-exports, Rolldown emits an info-level advice with the code `LARGE_BARREL_MODULES`:
```
advice[LARGE_BARREL_MODULES]: node_modules/@mui/icons-material/esm/index.js has 10611 re-exports. Eagerly resolving every entry can significantly slow down the build. Consider using `@rolldown/plugin-transform-imports` to rewrite imports at the source level so the barrel file is never loaded.
```
[`@rolldown/plugin-transform-imports`](https://github.com/rolldown/plugins/tree/main/packages/transform-imports) sidesteps the resolve cost by rewriting the imports at the source level so the barrel file is never loaded:
```js
// Before
import { Home, Search } from '@mui/icons-material';
// After (rewritten by the plugin)
import Home from '@mui/icons-material/esm/Home';
import Search from '@mui/icons-material/esm/Search';
```
To silence the advice, set `checks.largeBarrelModules` to `false` or pass `--no-checks.large-barrel-modules` on the CLI.
::: info Why is this a plugin instead of built-in behavior?
Deferring the resolve step inside Rolldown would change when `moduleParsed` fires and when `ModuleInfo` is fully populated — a visible departure from Rollup-compatible plugin semantics. To keep the plugin contract stable through Rolldown's 1.0 release, we prefer to solve this at the source level for the cases where it actually matters. Outside of outliers like icon packs, the resolve cost on typical barrels (tens to low hundreds of re-exports) is negligible.
:::
## Limitations
* Barrel modules with side effects cannot be optimized
* Unmatched named imports require loading all star re-exports to resolve
* Entry files, `import * as ns`, `import('..')`, `require('..')`, etc. will cause the barrel module to load all its exports
* When a barrel has its own exports (not just re-exports), using any own export causes all its import records to be loaded
---
---
url: /in-depth/native-magic-string.md
---
# Native MagicString
## Overview
`experimental.nativeMagicString` is an optimization feature that replaces the JavaScript-based MagicString implementation with a native Rust version, enabling source map generation in background threads for improving performance.
## What is MagicString?
MagicString is a JavaScript library developed by Rich Harris (the creator of Rollup and Svelte) that provides efficient string manipulation with automatic source map generation. It's commonly used by bundlers and build tools for:
* Code transformation in plugins
* Source map generation
* Precise line/column tracking
* Efficient string operations (replace, prepend, append, etc.)
## The JavaScript Implementation vs Native Rust
### Traditional JavaScript MagicString
The original MagicString implementation is written in JavaScript and runs in the Node.js environment. When bundlers perform code transformations, they typically:
1. Load source code as JavaScript strings
2. Apply transformations using MagicString API
3. Generate source maps for the transformed code
4. Process everything in the main JavaScript thread
### Native Rust Implementation
Rolldown's native MagicString implementation rewrites the core functionality in Rust, providing several advantages:
* **Performance**: Rust's memory safety and zero-cost abstractions make string operations faster
* **Parallel Processing**: Source map generation can happen in background threads
* **Memory Efficiency**: Better memory management for large codebases
* **Integration**: Seamless integration with Rolldown's Rust-based architecture
## How It Works
When `experimental.nativeMagicString` is enabled, Rolldown modifies the transformation pipeline. The diagrams below show the architectural differences:
:::info
Some technical details are simplified for better illustration. The native MagicString implementation provides a `magicString` object in the `meta` parameter of transform hooks, which plugins can use just like the JavaScript version.
:::
### Without Native MagicString
(Correction in the image: "rolldown without js magic-string" should be "rolldown without native magic-string")
### With Native MagicString
**Key Difference**: The native implementation is written in Rust, providing both Rust's performance advantages and background thread source map generation. Offloading to background threads improves overall CPU usage and enables significant performance improvements.
## API Compatibility
The native implementation maintains API compatibility with the JavaScript version. The most commonly used APIs are already implemented, with the remaining APIs planned for completion in future releases.
### Implemented Methods
The following MagicString methods are currently available in the native implementation:
**String Manipulation:**
* `append(content)` - Appends content to the end of the string
* `prepend(content)` - Prepends content to the beginning of the string
* `appendLeft(index, content)` - Appends content to the left of a specific index
* `appendRight(index, content)` - Appends content to the right of a specific index
* `prependLeft(index, content)` - Prepends content to the left of a specific index
* `prependRight(index, content)` - Prepends content to the right of a specific index
* `overwrite(start, end, content)` - Replaces content in a range
* `update(start, end, content)` - Updates content in a range
* `remove(start, end)` - Removes content in a range
* `replace(from, to)` - Replaces the first occurrence of a pattern
* `replaceAll(from, to)` - Replaces all occurrences of a pattern
**Transformations:**
* `indent(indentor?)` - Indents the content with optional custom indentation string
* `relocate(start, end, to)` - Moves content from one position to another
**Utilities:**
* `toString()` - Returns the transformed string
* `hasChanged()` - Checks if the string has been modified
* `length()` - Returns the length of the transformed string
* `isEmpty()` - Checks if the string is empty
* `clone()` - Returns a clone of the MagicString instance
* `trim(charType?)` - Trims whitespace or specified characters from both ends
* `trimStart(charType?)` - Trims whitespace or specified characters from the start
* `trimEnd(charType?)` - Trims whitespace or specified characters from the end
* `trimLines()` - Trims newlines from both ends
* `snip(start, end)` - Returns a clone with content outside the range removed
* `slice(start?, end?)` - Returns content between positions
* `reset(start, end)` - Resets a range to its original content
* `lastChar()` - Returns the last character
* `lastLine()` - Returns the content after the last newline
**Source Map Generation:**
* `generateMap(options?)` - Generates a source map as a JSON string
* `options.source` - Source file name
* `options.includeContent` - Include original source in the map
* `options.hires` - High-resolution mode: `true`, `false`, or `"boundary"`
### Not Yet Implemented
The following features are planned for future releases:
* `generateDecodedMap()` - Generate source map with decoded mappings
## Real-World Performance
use [rolldown/benchmarks](https://github.com/rolldown/benchmarks/) as benchmark cases
### Build time
| Runs | oxc raw transfer + js magicString | oxc raw transfer + native magicString | Time Saved | Speedup |
| ---------- | --------------------------------- | ------------------------------------- | ---------- | ------- |
| apps/1000 | 497.6 ms | 431.1 ms | 66.5 ms | 1.15x |
| apps/5000 | 1.100 s | 894.5 ms | 205.5 ms | 1.23x |
| apps/10000 | 1.814 s | 1.368 s | 446.0 ms | 1.33x |
### Plugin transform time (build time - noop plugin build time)
| Runs | Transform Time (oxc raw transfer + js magicString) | Transform Time (oxc raw transfer + native magicString) | Time Saved | Speedup |
| ----- | -------------------------------------------------- | ------------------------------------------------------ | ---------- | ------- |
| 1000 | 172.0 ms | 105.5 ms | 66.5 ms | 1.63x |
| 5000 | 455.4 ms | 249.9 ms | 205.5 ms | 1.82x |
| 10000 | 799.0 ms | 353.0 ms | 446.0 ms | 2.26x |
For detailed benchmark results, see the [benchmark pull request](https://github.com/rolldown/benchmarks/pull/9/files).
## Usage Examples
### Basic Plugin with Native MagicString
```js [rolldown.config.js]
import { defineConfig } from 'rolldown';
export default defineConfig({
experimental: {
nativeMagicString: true,
},
output: {
sourcemap: true,
},
plugins: [
{
name: 'transform-example',
transform(code, id, meta) {
if (!meta?.magicString) {
// Fallback when nativeMagicString is not available
return null;
}
const { magicString } = meta;
// Example transformation: Add debug comments
if (code.includes('console.log')) {
magicString.replace(/console\.log\(/g, 'console.log("[DEBUG]", ');
}
// Example: Add file header
magicString.prepend(`// Transformed from: ${id}\n`);
return {
code: magicString,
};
},
},
],
});
```
## Compatibility and Fallbacks
### Checking for Native MagicString Availability
```javascript [rolldown.config.js]
transform(code, id, meta) {
if (meta?.magicString) {
// Native MagicString is available
const { magicString } = meta;
// Use the native implementation
// Note: Return the magicString object directly, not a string
return {
code: magicString
};
} else {
// Fallback to regular string manipulation
// or use the JavaScript MagicString library
const MagicString = require('magic-string');
const ms = new MagicString(code);
// Your transformations here...
return {
code: ms.toString(),
map: ms.generateMap()
};
}
}
```
### Rollup Compatibility
This feature is Rolldown-specific and not available in Rollup. For plugins that need to work with both bundlers:
```javascript [plugin.js]
function createTransform() {
return function (code, id, meta) {
if (meta?.magicString) {
// Rolldown with native MagicString
return transformWithNativeMagicString(code, id, meta);
} else {
// Rollup or Rolldown without native MagicString
return transformWithJsMagicString(code, id);
}
};
}
```
::: tip
You can use [`rolldown-string`](https://github.com/sxzz/rolldown-string), which provides a unified interface that works with both bundlers.
:::
## When to Use Native MagicString
### Recommended Scenarios
1. **Large Codebases**: Projects with hundreds or thousands of files
2. **Complex Transformations**: Plugins that perform extensive code manipulation
3. **Source Map Intensive**: Projects requiring detailed source maps
4. **Performance-Critical**: Build processes where speed is crucial
5. **Development Mode**: Faster rebuild times during development
### When to Be Cautious
1. **Experimental Feature**: As an experimental feature, API may change
2. **Plugin Compatibility**: Some plugins may expect specific JavaScript MagicString behavior
3. **Debugging**: Native implementation may have different error messages
## Migration Guide
### Enabling Native MagicString
1. **Update Configuration**:
```javascript [rolldown.config.js]
export default {
experimental: {
nativeMagicString: true,
},
output: {
sourcemap: true, // Required for source map generation
},
};
```
2. **Update Plugins**:
```javascript [rolldown.config.js]
// Before
transform(code, id) {
const ms = new MagicString(code);
// ... transformations
return { code: ms.toString(), map: ms.generateMap() };
}
// After
transform(code, id, meta) {
if (meta?.magicString) {
const { magicString } = meta;
// ... transformations (same API)
return { code: magicString };
}
// Fallback logic
}
```
## Limitations and Considerations
### Current Limitations
1. **Experimental Status**: API may change in future versions
2. **Edge Cases**: Some edge cases may behave differently from JavaScript version
3. **Debugging**: Error messages may be less familiar
### Best Practices
1. **Always Check Availability**: Verify `meta?.magicString` exists before using
2. **Provide Fallbacks**: Include fallback logic for compatibility
3. **Test Thoroughly**: Test transformations with both implementations
4. **Report Issues**: Report any behavior differences to the Rolldown team
## Conclusion
`experimental.nativeMagicString` represents a significant performance optimization for Rolldown by leveraging Rust's efficiency for code transformation tasks. While it requires some considerations for compatibility, the performance benefits make it an attractive option for large-scale projects and performance-critical build processes.
As an experimental feature, it's recommended to test thoroughly in development environments before adopting in production workflows. The Rolldown team is actively working on this feature, and feedback from the community is valuable for its continued development.
---
---
url: /glossary/barrel-module.md
---
# Barrel Module
A barrel module is a module that re-exports functionality from other modules, commonly used to create a cleaner public API for a package or directory:
```js
// components/index.js (barrel module)
export { Button } from './Button';
export { Card } from './Card';
export { Modal } from './Modal';
export { Tabs } from './Tabs';
// ... dozens more components
```
This allows consumers to import from a single entry point:
```js
import { Button, Card } from './components';
```
However, barrel modules can cause performance issues because bundlers traditionally need to compile all re-exported modules, even if only a few are actually used. See [Lazy Barrel Optimization](/in-depth/lazy-barrel-optimization) for how Rolldown addresses this.
---
---
url: /glossary/entry.md
---
# Entry
Entry is an abstract term that represents a collection of multiple concepts. An entry means:
* An entry module used as a starting point for building the module graph
* An entry chunk that's created for exporting the entry module's exports. It will be also used to store the code of the entry module and its dependencies (if not code-split into separate chunks)
---
---
url: /glossary/entry-chunk.md
---
# Entry Chunk
An entry chunk is created, because we need to output a JavaScript file for:
* Exporting the exports of the entry module
* Representing the executing point of the corresponding [entry](./entry.md).
* Storing the code of the entry module and its dependencies (if not code-split into separate chunks)
Let's say you have an app that could run separately but also could be used as a library by other apps.
File structure:
```js
// component.js
export function component() {
return 'Hello World';
}
// render.js
export function render(component) {
console.log(component());
}
// app.js
import { component } from './component.js';
import { render } from './render.js';
render(component);
// lib.js
export { component } from './component.js';
```
Config:
```js
export default defineConfig({
input: {
app: './app.js',
lib: './lib.js',
},
});
```
Rolldown will create outputs like:
::: code-group
```js [app.js]
import { component } from './common.js';
function render(component) {
console.log(component());
}
render(component);
```
```js [lib.js]
export { component } from './common.js';
```
```js [common.js]
export function component() {
return 'Hello World';
}
```
:::
* `lib.js` is created because we need to create the export signature `export { component }` and export it in `lib.js`.
* For `app.js`, though it doesn't export anything, we still need to create `app.js` as the executing point of the app.
* You'll also notice, from the executing point `app.js`, only modules, like `render.js`, imported are executed. This is another reason and promise made by being the executing point.
---
---
url: /glossary/entry-name.md
---
# Entry Name
Entry name is a property of an entry. Rolldown will use the entry name to generate the file name for the corresponding entry chunk, which will replace the `[name]` placeholder in the [`output.entryFileNames`](/reference/OutputOptions.entryFileNames) pattern.
---
---
url: /glossary/user-defined-entry.md
---
# User-defined Entry
A user-defined entry is an [entry](./entry.md) that's explicitly defined by the user via the [`input`](/reference/InputOptions.input) option.
---
---
url: /reference/InputOptions.checks.md
---
# checks
* **Type**: object with the properties below
* **Optional**
Controls which warnings are emitted during the build process. Each option can be set to `true` (emit warning) or `false` (suppress warning).
## cannotCallNamespace?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when a namespace is called as a function.
A module namespace object is an object and not a function. Calling it as a function will cause a runtime error.
::: code-group
```js [main.js]
import * as utils from './utils.js';
// This will trigger the warning
// because `utils` is a namespace object, not a function
utils();
```
```js [utils.js]
export function greet() {
return 'Hello';
}
```
:::
### Default
```ts
true
```
## circularDependency?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when detecting circular dependency.
Circular dependencies lead to a bigger bundle size and sometimes cause execution order issues and are better to avoid.
::: code-group
```js [a.js]
import { b } from './b.js';
export const a = 'a' + b;
```
```js [b.js]
import { a } from './a.js';
export const b = 'b' + a;
```
```js [main.js]
import { a } from './a.js';
console.log(a);
```
:::
In this example, `a.js` imports from `b.js`, and `b.js` imports from `a.js`, creating a circular dependency.
### Default
```ts
false
```
## commonJsVariableInEsm?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when a CommonJS variable is used in an ES module.
CommonJS variables like `module` and `exports` are treated as global variables in ES modules and may not work as expected.
```js
export const version = '1.0.0';
module.exports = { legacy: true }; // This triggers the warning
```
### Default
```ts
true
```
## configurationFieldConflict?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when a config value is overridden by another config value with a higher priority.
::: code-group
```js [rolldown.config.js]
export default {
transform: {
jsx: 'preserve',
},
};
```
```json [tsconfig.json]
{
"compilerOptions": {
"jsx": "react"
}
}
```
:::
### Default
```ts
true
```
## couldNotCleanDirectory?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when Rolldown could not clean the output directory.
See [`output.cleanDir`](/reference/OutputOptions.cleanDir).
### Default
```ts
true
```
## duplicateShebang?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when both the code and postBanner contain shebang
Having multiple shebangs in a file is a syntax error.
### Default
```ts
true
```
## emptyImportMeta?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when `import.meta` is not supported with the output format and is replaced with an empty object (`{}`).
See [`import.meta` in Non-ESM Output Formats page](/in-depth/non-esm-output-formats#import-meta) for more details.
### Default
```ts
true
```
## eval?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when detecting uses of direct `eval`s.
See [Avoiding Direct `eval` in Troubleshooting page](/guide/troubleshooting#avoiding-direct-eval) for more details.
### Default
```ts
true
```
## filenameConflict?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when files generated have the same name with different contents.
For example, this warning happens with the following config:
```js [rolldown.config.js]
export default {
input: ['src/entry1.js', 'src/entry2.js'],
output: {
// Both entries will try to use the same filename
entryFileNames: 'bundle.js',
},
};
```
### Default
```ts
true
```
## importIsUndefined?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when an imported variable is not exported.
If the code is importing a variable that is not exported by the imported module, the value will always be `undefined`. This might be a mistake in the code.
::: code-group
```js [main.js]
import * as utils from './utils.js'; // 'nonExistent' is not exported
console.log(utils.nonExistent); // Always undefined
```
```js [utils.js]
export const helper = () => 'help';
```
:::
### Default
```ts
true
```
## ineffectiveDynamicImport?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when a module is dynamically imported but also statically imported, making the dynamic import ineffective for code splitting.
### Default
```ts
true
```
## invalidAnnotation?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when a `#__PURE__` / `@__PURE__` annotation has no effect due to its position.
Annotations placed where they cannot annotate a call expression (e.g. before a non-call expression,
before a statement declaration, or between an identifier and `=` in a variable declarator) are
ignored by the parser. Matches Rollup's `INVALID_ANNOTATION` log code.
By default, warnings are emitted only for local project files inside `cwd` and outside
`node_modules`. Set this option to `false` to disable the warning entirely.
### Default
```ts
true
```
## largeBarrelModules?
* **Type**: `boolean`
* **Optional**
Whether to emit info logs when a barrel module has a very large number of re-exports (more than 5000).
Such modules can significantly slow down module resolution. Consider using
[`@rolldown/plugin-transform-imports`](https://github.com/rolldown/plugins/tree/main/packages/transform-imports)
to rewrite barrel imports at the source level so the barrel file is never loaded.
See [Large barrel modules](/in-depth/lazy-barrel-optimization#large-barrel-modules) for more details.
### Default
```ts
true
```
## missingGlobalName?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when the `output.globals` option is missing when needed.
See [`output.globals`](/reference/OutputOptions.globals).
### Default
```ts
true
```
## missingNameOptionForIifeExport?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when the `output.name` option is missing when needed.
See [`output.name`](/reference/OutputOptions.name).
### Default
```ts
true
```
## mixedExports?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when the way to export values is ambiguous.
See [`output.exports`](/reference/OutputOptions.exports).
### Default
```ts
true
```
## pluginTimings?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when plugins take significant time during the build process.
When enabled, Rolldown measures how long your plugin hooks run and warns when they account for a significant share of the build.
**How it works:**
The clock starts and stops **inside the JavaScript callback**, not around the call. Rolldown dispatches most hooks concurrently and they queue up on JavaScript's single thread, so the time between handing a call over and getting a result back is mostly time the call spent waiting. Measuring from inside the callback excludes that wait by construction.
1. **Minimum build time**: to avoid noisy warnings for fast builds, the warning is only triggered if Rolldown's internal build time (Rust side) exceeds **3 seconds**.
2. **Detection threshold**: a warning is triggered when plugin time (total build time minus link stage time) exceeds 100x the link stage time. This threshold was determined by studying plugin impact on real-world projects. The link stage is the one part of a build that runs no plugins at all, which is what makes it a usable baseline.
3. **Rows**: up to 12 hooks are listed, sorted by measured time, each shown as a share of total build time with its call count. Only hooks costing at least 1 second get a line. User callbacks configured on the options rather than on a plugin — `external`, `treeshake.moduleSideEffects`, the file-name and addon callbacks, and the [`output.advancedChunks`](/reference/OutputOptions.advancedChunks) `groups[].name` classifier and `groups[].test` predicate — appear under `input options` / `output options`.
The headline figure is the wall time in which *any* plugin callback was running, counted once however much they overlap, so it can never exceed the build. Individual rows can add up to more than it, because one callback may run inside another — `this.emitFile()` in `buildStart` invokes your `assetFileNames`, and that time belongs to both.
> \[!IMPORTANT]
> **Some hooks are listed without a number**, under a heading saying they are not measurable.
>
> A span from callback entry to callback exit can be added to another span only if the two never overlap. A synchronous callback cannot overlap — it holds the thread until it returns. An `async` one can: it may suspend at an `await` and let another call of the same hook begin, and then both spans cover the same wall clock and adding them counts it twice. Overlap also changes what the span means — a hook that awaits Rolldown itself, via `this.resolve` or `this.load`, spends most of its span waiting for the bundler, so its elapsed time describes the bundler rather than your plugin.
>
> Rolldown measures the overlap rather than assuming it, and judges its size: it records exactly how much of a hook's total is double counted, and keeps the number when that is under 1% of the span. So a hook dispatched concurrently is still measured exactly when its calls happen not to overlap, and one incidental overlap among thousands of calls does not discard an otherwise good measurement — which also keeps the report stable from run to run rather than dependent on scheduling. A hook that genuinely overlaps itself is named but given no number, because any number would be an upper bound that ranks it above hooks doing more work. To find the real cost of those, profile the JavaScript directly — for example `node --cpu-prof` on your build script, which samples what is actually executing.
**What the listed numbers mean.** Measuring from inside the callback excludes the time a call spent queued; it does not separate running from awaiting. A listed hook is wall time for that callback, not CPU time, so one that awaits I/O without overlapping another call of itself is charged for the wait. The figure excludes the data conversion Rolldown does on either side of the call.
**Not covered.** Plugins written in Rust (`builtin:` and the plugins Rolldown ships internally) have no JavaScript callback to measure and never appear. Neither do parallel plugins, whose hooks run on worker threads. The report is produced when the build is closed, so watch and dev-server rebuilds do not emit it.
### Default
```ts
true
```
## preferBuiltinFeature?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when a plugin that is covered by a built-in feature is used.
Using built-in features is generally more performant than using plugins.
### Default
```ts
true
```
## sourcemapBroken?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when a plugin transforms code without generating a sourcemap.
### Default
```ts
true
```
## toleratedTransform?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when detecting tolerated transform.
### Default
```ts
true
```
## unresolvedEntry?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when an entrypoint cannot be resolved.
### Default
```ts
true
```
## unresolvedImport?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when an import cannot be resolved.
### Default
```ts
true
```
## unsupportedTsconfigOption?
* **Type**: `boolean`
* **Optional**
Whether to emit warnings when a tsconfig option or combination of options is not supported.
### Default
```ts
true
```
---
---
url: /reference/InputOptions.context.md
---
# context
* **Type**: `string`
* **Optional**
The value of `this` at the top level of each module. **Normally, you don't need to set this option.**
## Default
```ts
undefined
```
## Example
**Set custom context**
```js
export default {
context: 'globalThis',
output: {
format: 'iife',
},
};
```
## In-depth
The `context` option controls what `this` refers to in the top-level scope of the input modules.
In ES modules, the `this` value is `undefined` by specification. This option allows you to set a different value. For example, if your input modules expect `this` to be `window` like in non-ES module scripts, you can set `context` to `'window'`.
Note that if the input module is detected as CommonJS, Rolldown will use `exports` as the `this` value regardless of this option.
---
---
url: /reference/InputOptions.cwd.md
---
# cwd
* **Type**: `string`
* **Optional**
The working directory to use when resolving relative paths in the configuration.
## Default
```ts
process.cwd()
```
---
---
url: /reference/InputOptions.devtools.md
---
# devtools
* **Type**: object with the properties below
* **Optional**
* **Experimental**
Devtools integration options.
When enabled, Rolldown writes JSON-lines devtools output under
`node_modules/.rolldown/{session_id}/`, resolved against [`cwd`](./InputOptions.cwd).
Consumers can parse the output with `@rolldown/debug` after
`await bundle.close()` resolves.
## sessionId?
* **Type**: `string`
* **Optional**
---
---
url: /reference/InputOptions.experimental.md
---
# experimental
* **Type**: object with the properties below
* **Optional**
* **Experimental**
Experimental features that may change in future releases and can introduce behavior change without a major version bump.
## attachDebugInfo?
* **Type**: `"none"` | `"simple"` | `"full"`
* **Optional**
Attach debug information to the output bundle.
Available modes:
* `none`: No debug information is attached.
* `simple`: Attach comments indicating which files the bundled code comes from. These comments could be removed by the minifier.
* `full`: Attach detailed debug information to the output bundle. These comments are using legal comment syntax, so they won't be removed by the minifier.
### Default
'simple'
### In-depth
Each chunk will include a comment explaining the reason why it was created:
| Reason | Format | Description |
| --------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| User-defined Entry | `User-defined Entry: [Entry-Module-Id: ] [Name: Some("")]` | Explicit entry point from build config |
| Dynamic Entry | `Dynamic Entry: [Entry-Module-Id: ] [Name: None]` | Chunk created from `import()` expression |
| Common Chunk | `Common Chunk: [Shared-By: , , ...]` | Shared modules extracted for multiple entries |
| Manual Code Splitting | `ManualCodeSplitting: [Group-Name: ]` | Chunk created by [`output.codeSplitting`](/reference/OutputOptions.codeSplitting) option |
| Preserve Modules | `Enabling Preserve Module: [User-defined: ] [Module-Id: ]` | Per-module chunk from [`output.preserveModules`](/reference/OutputOptions.preserveModules) option |
When rolldown optimized away empty facade chunks (entry chunks with no modules of their own), the target chunk will include `Eliminated Facade Chunk: [Chunk-Name: ] [Entry-Module-Id: ]`.
## chunkImportMap?
* **Type**: `boolean` | { `baseUrl?`: `string`; `fileName?`: `string`; }
* **Optional**
Enables automatic generation of a chunk import map asset during build.
This map only includes chunks with hashed filenames, where keys are derived from the facade module
name or primary chunk name. It produces stable and unique hash-based filenames, effectively preventing
cascading cache invalidation caused by content hashes and maximizing browser cache reuse.
The output defaults to `importmap.json` unless overridden via `fileName`. A base URL prefix
(default `"/"`) can be applied to all paths. The resulting JSON is a valid import map and can be
directly injected into HTML via `/i,
``
);
fs.writeFileSync(htmlPath, html);
delete bundle['importmap.json'];
}
}
}
]
}
```
> \[!TIP]
> If you want to learn more, you can check out the example here: [examples/chunk-import-map](https://github.com/rolldown/rolldown/tree/main/examples/chunk-import-map)
### Default
```ts
false
```
## chunkModulesOrder?
* **Type**: `"exec-order"` | `"module-id"`
* **Optional**
Control which order should be used when rendering modules in a chunk.
Available options:
* `exec-order`: Almost equivalent to the topological order of the module graph, but specially handling when module graph has cycle.
* `module-id`: This is more friendly for gzip compression, especially for some javascript static asset lib (e.g. icon library)
> \[!NOTE]
> Try to sort the modules by their module id if possible (Since rolldown scope hoist all modules in the chunk, we only try to sort those modules by module id if we could ensure runtime behavior is correct after sorting).
### Default
```ts
'exec-order'
```
## chunkOptimization?
* **Type**: `boolean` | [`ChunkOptimizationOptions`](Interface.ChunkOptimizationOptions.md)
* **Optional**
Control chunk optimizations.
`true` enables both common-chunk merging and redundant dynamic chunk-load avoidance.
`false` disables all chunk optimizations. Use the object form to control
`mergeCommonChunks` and `avoidRedundantChunkLoads` separately.
These optimizations are automatically disabled when any module uses top-level await (TLA) or contains TLA dependencies,
as they could affect execution order guarantees.
### Default
```ts
true
```
## incrementalBuild?
* **Type**: `boolean`
* **Optional**
Enable incremental build support. Required to be used with `watch` mode.
### Default
```ts
false
```
## lazyBarrel?
* **Type**: `boolean`
* **Optional**
Control whether to enable lazy barrel optimization.
Lazy barrel optimization avoids compiling unused re-export modules in side-effect-free barrel modules,
significantly improving build performance for large codebases with many barrel modules.
This option is planned to be removed in the future. If you need to opt out, please open an issue
describing your use case so we can address it before the option is gone.
### See
[Lazy Barrel Documentation](/in-depth/lazy-barrel-optimization)
### Default
```ts
false
```
## nativeMagicString?
* **Type**: `boolean`
* **Optional**
Use native Rust implementation of MagicString for source map generation.
[MagicString](https://github.com/rich-harris/magic-string) is a JavaScript library commonly used by bundlers
for string manipulation and source map generation. When enabled, rolldown will use a native Rust
implementation of MagicString instead of the JavaScript version, providing significantly better performance
during source map generation and code transformation.
**Benefits**
* **Improved Performance**: The native Rust implementation is typically faster than the JavaScript version,
especially for large codebases with extensive source maps.
* **Background Processing**: Source map generation is performed asynchronously in a background thread,
allowing the main bundling process to continue without blocking. This parallel processing can significantly
reduce overall build times when working with JavaScript transform hooks.
* **Better Integration**: Seamless integration with rolldown's native Rust architecture.
### Example
```js
export default {
experimental: {
nativeMagicString: true
},
output: {
sourcemap: true
}
}
```
> \[!NOTE]
> This is an experimental feature. While it aims to provide identical behavior to the JavaScript
> implementation, there may be edge cases. Please report any discrepancies you encounter.
> For a complete working example, see [examples/native-magic-string](https://github.com/rolldown/rolldown/tree/main/examples/native-magic-string)
### Default
```ts
false
```
## resolveNewUrlToAsset?
* **Type**: `boolean`
* **Optional**
When enabled, `new URL()` calls will be transformed to a stable asset URL which includes the updated name and content hash.
It is necessary to pass `import.meta.url` as the second argument to the
`new URL` constructor, otherwise no transform will be applied.
:::warning
JavaScript and TypeScript files referenced via `new URL('./file.js', import.meta.url)` or `new URL('./file.ts', import.meta.url)` will **not** be transformed or bundled. The file will be copied as-is, meaning TypeScript files remain untransformed and dependencies are not resolved.
The expected behavior for JS/TS files is still being discussed and may
change in future releases. See [#7258](https://github.com/rolldown/rolldown/issues/7258) for more context.
:::
### Example
```js
// main.js
const url = new URL('./styles.css', import.meta.url);
console.log(url);
// Example output after bundling WITHOUT the option (default)
const url = new URL('./styles.css', import.meta.url);
console.log(url);
// Example output after bundling WITH `experimental.resolveNewUrlToAsset` set to `true`
const url = new URL('assets/styles-CjdrdY7X.css', import.meta.url);
console.log(url);
```
### Default
```ts
false
```
---
---
url: /reference/InputOptions.external.md
---
# external
* **Type**: `string` | `RegExp` | (`string` | `RegExp`)\[] | [`ExternalOptionFunction`](TypeAlias.ExternalOptionFunction.md)
* **Optional**
Specifies which modules should be treated as external and not bundled. External modules will be left as import statements in the output.
When creating an `iife` or `umd` bundle, you will need to provide global variable names to replace your external imports via the [`output.globals`](/reference/OutputOptions.globals) option.
## How Matching Works
The `external` option is checked **twice** during module resolution, against two different kinds of IDs:
1. **First check — raw import specifier** (e.g. `'lodash'`, `'./utils'`) is tested before any resolution happens, with `isResolved: false`. To mark `import "dependency"` as external, use `"dependency"` exactly as written in the import statement. If it matches, the module is immediately marked as external — **plugins and the internal resolver are skipped entirely**.
2. **Second check — resolved ID** (e.g. `'/project/node_modules/vue/dist/vue.runtime.esm-bundler.js'`) is tested after plugins and the internal resolver have run, with `isResolved: true`. If it matches, the module is marked as external.
The second check only runs if the first did not match. In both cases, [`makeAbsoluteExternalsRelative`](/reference/InputOptions.makeAbsoluteExternalsRelative) applies uniformly to determine whether absolute IDs are re-relativized in the output.
See the [External Modules guide](/in-depth/external-modules) for a detailed explanation of the full resolution flow and how the output path is determined.
## Examples
### String pattern
```js
export default {
external: 'react',
};
```
### Regular expression
```js
export default {
external: /^react\//,
};
```
### Array of patterns
```js
export default {
external: ['react', 'react-dom', /^lodash/],
};
```
### Function
```js
import path from 'node:path';
export default {
external: (id) => {
return !id.startsWith('.') && !path.isAbsolute(id);
},
};
```
::: warning Performance Overhead
Using the function form has significant performance overhead because Rolldown is written in Rust and must call JavaScript functions from Rust for every module in your dependency graph.
Unless the logic relies on values other than `id`, it is recommended to use non-function values.
:::
## Caveats
### Avoid `/node_modules/` for npm packages
Because the pattern `/node_modules/` can only match on the **second check** (the resolved absolute path), the full resolved path like `/path/to/node_modules/vue/dist/vue.runtime.esm-bundler.js` ends up in the output verbatim. This makes the output non-portable.
Instead, match packages by name or use a pattern for bare module IDs:
```js
export default {
// Exact package names
external: ['vue', 'react', 'react-dom'],
// Package name patterns
external: [/^vue/, /^react/, /^@mui/],
// All bare module IDs (not starting with `.` or `/` or `C:\`)
external: /^[^./](?!:[/\\])/,
};
```
---
---
url: /reference/InputOptions.input.md
---
# input
* **Type**: `string` | `string`\[] | `Record`<`string`, `string`>
* **Optional**
Defines entries and location(s) of entry modules for the bundle. Relative paths are resolved based on the [`cwd`](./InputOptions.cwd) option.
## Examples
### Single entry
```js
export default defineConfig({
input: 'src/index.js',
});
```
### Multiple entries
```js
export default defineConfig({
input: ['src/index.js', 'src/vendor.js'],
});
```
### Named multiple entries
```js
export default defineConfig({
input: {
index: 'src/index.js',
utils: 'src/utils/index.js',
'components/Foo': 'src/components/Foo.js',
},
});
```
## In-depth
`input` allows you to specify one or more [entries](/glossary/entry) with [names](/glossary/entry-name) for the bundling process.
When multiple entries are specified (either as an array or an object), Rolldown will create separate [entry chunks](/glossary/entry-chunk) for each entry. If a module is referenced from multiple entries, Rolldown will share the code of that module for those entries.
The generated chunk names will follow the [`output.chunkFileNames`](/reference/OutputOptions.chunkFileNames) option. When using the object form, the `[name]` portion of the file name will be the name of the object property while for the array form, it will be the file name of the entry point. Note that it is possible when using the object form to put entry points into different sub-folders by adding a `/` to the name.
If you want to convert a set of files to another format while maintaining the file structure and export signatures, the recommended way—instead of using [`output.preserveModules`](/reference/OutputOptions.preserveModules) that may tree-shake exports as well as emit virtual files created by plugins—is to turn every file into an entry point. You can do so dynamically e.g. via the [`tinyglobby`](https://github.com/SuperchupuDev/tinyglobby) package:
```js
import { defineConfig } from 'rolldown';
import { globSync } from 'tinyglobby';
import path from 'node:path';
export default defineConfig({
input: Object.fromEntries(
globSync('src/**/*.js').map((file) => [
// This removes `src/` as well as the file extension from each
// file, so e.g. src/nested/foo.js becomes nested/foo, and
// normalizes Windows backslashes to forward slashes.
path
.relative('src', file.slice(0, file.length - path.extname(file).length))
.split(path.sep)
.join('/'),
// This expands the relative paths to absolute paths, so e.g.
// src/nested/foo.js becomes /project/src/nested/foo.js
path.resolve(file),
]),
),
output: {
dir: 'dist',
format: 'esm',
},
});
```
---
---
url: /reference/InputOptions.logLevel.md
---
# logLevel
* **Type**: `"info"` | `"debug"` | `"warn"` | `"silent"`
* **Optional**
Controls the verbosity of console logging during the build.
The default logLevel of "info" means that info and warnings logs will be processed while debug logs will be swallowed, which means that they are neither passed to plugin [`onLog`](/reference/Interface.Plugin#onlog) hooks nor the [`onLog`](/reference/InputOptions.onLog) option or printed to the console.
## Default
```ts
'info'
```
---
---
url: /reference/InputOptions.makeAbsoluteExternalsRelative.md
---
# makeAbsoluteExternalsRelative
* **Type**: `false` | `true` | `"ifRelativeSource"`
* **Optional**
Determines if absolute external paths should be converted to relative paths in the output.
This does not only apply to paths that are absolute in the source but also to paths that are resolved to an absolute path by either a plugin or Rolldown core.
Despite the name, this option controls two things:
1. **Resolve-time normalization** — whether relative specifiers (e.g. `'./utils'`) are normalized to absolute paths internally for deduplication. Without normalization, `'./utils'` imported from different directories may collapse into one external module because they share the same raw string.
2. **Render-time output** — whether a resolved module ID (the absolute path after resolution) gets converted to a relative path in the output. It does not affect bare specifiers (e.g. `'lodash'`) or IDs that are already relative.
Both behaviors depend on the **original import specifier** (what you wrote in source code, e.g. `'./utils'`) vs the **resolved module ID** (the absolute path after resolution, e.g. `'/project/src/utils.js'`). See the [External Modules guide](/in-depth/external-modules) for how this fits into the full resolution flow.
## Values
### `"ifRelativeSource"` (default)
Only convert the resolved absolute ID to a relative path if the **original import specifier** was relative.
```js
// Original: relative specifier → converted to relative in output
import './lib/utils.js'; // → import './lib/utils.js'
// Original: absolute specifier → kept absolute in output
import '/project/lib/utils.js'; // → import '/project/lib/utils.js'
```
The idea: if you wrote a relative import, you probably want a relative import in the output. If you wrote an absolute import, you probably meant it to stay absolute.
### `true`
Always convert resolved absolute IDs to relative paths:
```js
// Both become relative in output
import './lib/utils.js'; // → import './lib/utils.js'
import '/project/lib/utils.js'; // → import '../lib/utils.js'
```
When converting an absolute path to a relative path, Rolldown does *not* take the [`file`](/reference/OutputOptions.file) or [`dir`](/reference/OutputOptions.dir) options into account, because those may not be present e.g. for builds using the JavaScript API. Instead, it assumes that the root of the generated bundle is located at the common shared parent directory of all entry points.
If the output chunk is itself nested in a subdirectory by choosing e.g. `chunkFileNames: "chunks/[name].js"`, the relative path is adjusted accordingly.
### `false`
Never convert. Resolved absolute IDs are kept as-is. Relative specifiers are also **not** normalized to absolute paths internally, which means two files importing `'./utils'` from different directories may be treated as the same external module.
```js
import './lib/utils.js'; // → import './lib/utils.js' (as-is)
import '/project/lib/utils.js'; // → import '/project/lib/utils.js' (as-is)
```
::: warning Deduplication issue with `false`
Setting `makeAbsoluteExternalsRelative: false` disables the normalization of relative specifiers. This means `'./utils'` imported from `src/a.js` and `'./utils'` imported from `src/b/c.js` may be treated as the same external module, even though they refer to different files. Use `false` only if you are certain all your external specifiers are already unique (e.g. bare package names).
:::
## Example
Given `import '/project/lib/utils.js'` (absolute specifier) in an external module, with output at `dist/index.js`:
| `makeAbsoluteExternalsRelative` | Output path |
| ------------------------------- | ------------------------- |
| `true` | `'../lib/utils.js'` |
| `"ifRelativeSource"` (default) | `'/project/lib/utils.js'` |
| `false` | `'/project/lib/utils.js'` |
Given `import './lib/utils.js'` (relative specifier) with a flat output at `dist/index.js`:
| `makeAbsoluteExternalsRelative` | Output path |
| ------------------------------- | ------------------ |
| `true` | `'./lib/utils.js'` |
| `"ifRelativeSource"` (default) | `'./lib/utils.js'` |
| `false` | `'./lib/utils.js'` |
The same relative specifier with a nested chunk at `dist/chunks/index.js`:
| `makeAbsoluteExternalsRelative` | Output path |
| ------------------------------- | ------------------- |
| `true` | `'../lib/utils.js'` |
| `"ifRelativeSource"` (default) | `'../lib/utils.js'` |
| `false` | `'./lib/utils.js'` |
With `true` or `"ifRelativeSource"`, relative specifiers are normalized to absolute paths internally, then re-relativized from the output chunk's location — so the path adjusts correctly for nested chunks. With `false`, the raw specifier is kept as-is with no adjustment.
---
---
url: /reference/InputOptions.moduleTypes.md
---
# moduleTypes
* **Type**: [`ModuleTypes`](TypeAlias.ModuleTypes.md)
* **Optional**
Maps file patterns to module types, controlling how files are processed.
This is conceptually similar to [esbuild's `loader`](https://esbuild.github.io/api/#loader) option, allowing you to specify how each file extensions should be handled.
See [the In-Depth Guide](/in-depth/module-types) for more details.
## Example
```js
import { defineConfig } from 'rolldown'
export default defineConfig({
moduleTypes: {
'.frag': 'text',
}
})
```
---
---
url: /reference/InputOptions.onLog.md
---
# onLog
* **Type**: (`level`, `log`, `defaultHandler`) => `void`
* **Optional**
A function that intercepts log messages. If not supplied, logs are printed to the console.
This handler will not be invoked if logs are filtered out by the [`logLevel`](/reference/InputOptions.logLevel) option. I.e. by default, `"debug"` logs will be swallowed.
If the default handler is not invoked, the log will not be printed to the console. Moreover, you can change the log level by invoking the default handler with a different level. Using the additional level `"error"` will turn the log into a thrown error that has all properties of the log attached.
## Parameters
### level
`"info"` | `"debug"` | `"warn"`
### log
[`RolldownLog`](Interface.RolldownLog.md)
### defaultHandler
[`LogOrStringHandler`](TypeAlias.LogOrStringHandler.md)
## Returns
`void`
## Example
```js
export default defineConfig({
onLog(level, log, defaultHandler) {
if (log.code === 'CIRCULAR_DEPENDENCY') {
return; // Ignore circular dependency warnings
}
if (level === 'warn') {
defaultHandler('error', log); // turn other warnings into errors
} else {
defaultHandler(level, log); // otherwise, just print the log
}
}
})
```
---
---
url: /reference/InputOptions.onwarn.md
---
# ~~onwarn~~
* **Type**: (`warning`, `defaultHandler`) => `void`
* **Optional**
A function that will intercept warning messages.
If the default handler is invoked, the log will be handled as a warning. If both an `onLog` and `onwarn` handler are provided, the `onwarn` handler will only be invoked if `onLog` calls its default handler with a `level` of `"warn"`.
## Parameters
### warning
[`RolldownLog`](Interface.RolldownLog.md)
### defaultHandler
(`warning`) => `void`
## Returns
`void`
## Deprecated
This is a legacy API. Consider using [`onLog`](./InputOptions.onLog) instead for better control over all log types.
To migrate from `onwarn` to `onLog`, check the `level` parameter to filter for warnings:
```js
// Before: Using `onwarn`
export default {
onwarn(warning, defaultHandler) {
// Suppress certain warnings
if (warning.code === 'CIRCULAR_DEPENDENCY') return;
// Handle other warnings with default behavior
defaultHandler(warning);
},
};
```
```js
// After: Using `onLog`
export default {
onLog(level, log, defaultHandler) {
// Handle only warnings (same behavior as `onwarn`)
if (level === 'warn') {
// Suppress certain warnings
if (log.code === 'CIRCULAR_DEPENDENCY') return;
// Handle other warnings with default behavior
defaultHandler(level, log);
} else {
// Let other log levels pass through
defaultHandler(level, log);
}
},
};
```
---
---
url: /reference/InputOptions.optimization.md
---
# optimization
* **Type**: object with the properties below
* **Optional**
Configure optimization features for the bundler.
## inlineConst?
* **Type**: `boolean` | { `mode?`: `"all"` | `"smart"`; `pass?`: `number`; }
* **Optional**
Inline imported constant values during bundling instead of preserving variable references.
When enabled, constant values from imported modules will be inlined at their usage sites,
potentially reducing bundle size and improving runtime performance by eliminating variable lookups.
**Options:**
* `true`: equivalent to `{ mode: 'all', pass: 1 }`, enabling constant inlining for all eligible constants with a single pass.
* `false`: Disable constant inlining
* `{ mode: 'smart' | 'all', pass?: number }`:
* `mode: 'smart'`: Only inline constants in specific scenarios where it is likely to reduce bundle size and improve performance.
Smart mode inlines constants in these specific scenarios:
1. `if (test) {} else {}` - condition expressions in if statements
2. `test ? a : b` - condition expressions in ternary operators
3. `test1 || test2` - logical OR expressions
4. `test1 && test2` - logical AND expressions
5. `test1 ?? test2` - nullish coalescing expressions
* `mode: 'all'`: Inline all imported constants wherever they are used.
* `pass`: Number of passes to perform for inlining constants.
### Example
```js
// Input files:
// constants.js
export const API_URL = 'https://api.example.com';
// main.js
import { API_URL } from './constants.js';
console.log(API_URL);
// With inlineConst: true, the bundled output becomes:
console.log('https://api.example.com');
// Instead of:
const API_URL = 'https://api.example.com';
console.log(API_URL);
```
### Default
```ts
{ mode: 'smart', pass: 1 }
```
## pifeForModuleWrappers?
* **Type**: `boolean`
* **Optional**
Use PIFE pattern for module wrappers.
Enabling this option improves the start up performance of the generated bundle with the cost of a slight increase in bundle size.
::: tip What is PIFE?
PIFE is the abbreviation of "Possibly-Invoked Function Expressions". It is a function expression wrapped with a parenthesized expression.
PIFEs annotate functions that are likely to be invoked eagerly. When [V8 JavaScript engine](https://v8.dev/) (the engine used in Chrome and Node.js) encounters such expressions, it compiles them eagerly (rather than compiling it later). See [V8's blog post](https://v8.dev/blog/preparser#pife) for more details.
:::
### Default
```ts
true
```
---
---
url: /reference/InputOptions.platform.md
---
# platform
* **Type**: `"node"` | `"browser"` | `"neutral"`
* **Optional**
Expected platform where the code run.
When the platform is set to neutral:
* When bundling is enabled the default output format is set to esm, which uses the export syntax introduced with ECMAScript 2015 (i.e. ES6). You can change the output format if this default is not appropriate.
* The main fields setting is empty by default. If you want to use npm-style packages, you will likely have to configure this to be something else such as main for the standard main field used by node.
* The conditions setting does not automatically include any platform-specific values.
## Default
* `'node'` if the format is `'cjs'`
* `'browser'` for other formats
## Examples
### Browser platform
```js
export default {
platform: 'browser',
output: {
format: 'esm',
},
};
```
### Node.js platform
```js
export default {
platform: 'node',
output: {
format: 'cjs',
},
};
```
### Platform-neutral
```js
export default {
platform: 'neutral',
output: {
format: 'esm',
},
};
```
## In-depth
The platform setting provides sensible defaults for module resolution and environment-specific behavior, similar to esbuild's `platform` option.
### `'node'`
Optimized for Node.js environments:
* **Conditions**: Includes `'node'`, `'import'`, `'require'` based on output format
* **Main fields**: `['main', 'module']`
* **Target**: Node.js runtime behavior
* **process.env handling**: Preserves `process.env.NODE_ENV` and other Node.js globals
### `'browser'`
Optimized for browser environments:
* **Conditions**: Includes `'browser'`, `'import'`, `'module'`, `'default'`
* **Main fields**: `['browser', 'module', 'main']` - prefers browser-specific entry points
* **Target**: Browser runtime behavior
* **Built-ins**: Node.js built-in modules are not polyfilled by default
:::tip
For browser builds, you may want to use [rolldown-plugin-node-polyfills](https://github.com/rolldown/rolldown-plugin-node-polyfills) to polyfill Node.js built-ins if needed.
:::
### `'neutral'`
Platform-agnostic configuration:
* **Default format**: Always `'esm'`
* **Conditions**: Only includes format-specific conditions, no platform-specific ones
* **Main fields**: Empty by default - relies on package.json `"exports"` field
* **Use cases**: Universal libraries that run in multiple environments
### Difference from esbuild
Notable differences from esbuild's `platform` option:
* The default output format is always `'esm'` regardless of platform (in esbuild, Node.js defaults to `'cjs'`)
### Choosing a Platform
**Use `'browser'`** when:
* Building for web applications
* Targeting modern browsers with ES modules support
* Need browser-specific package entry points
**Use `'node'`** when:
* Building server-side applications
* Creating CLI tools
* Need Node.js-specific features and modules
**Use `'neutral'`** when:
* Building universal libraries
* Want maximum portability
* Avoiding platform-specific assumptions
---
---
url: /reference/InputOptions.plugins.md
---
# plugins
* **Type**: [`RolldownPluginOption`](TypeAlias.RolldownPluginOption.md)
* **Optional**
The list of plugins to use.
Falsy plugins will be ignored, which can be used to easily activate or deactivate plugins. Nested plugins will be flattened. Async plugins will be awaited and resolved.
See [Plugin API document](/apis/plugin-api) for more details about creating plugins.
## Example
```js
import { defineConfig } from 'rolldown'
export default defineConfig({
plugins: [
examplePlugin1(),
// Conditional plugins
process.env.ENV1 && examplePlugin2(),
// Nested plugins arrays are flattened
[examplePlugin3(), examplePlugin4()],
]
})
```
---
---
url: /reference/InputOptions.preserveEntrySignatures.md
---
# preserveEntrySignatures
* **Type**: `false` | `"strict"` | `"allow-extension"` | `"exports-only"`
* **Optional**
Controls how entry chunk exports are preserved.
This determines whether Rolldown needs to create facade chunks (additional wrapper chunks) to maintain the exact export signatures of entry modules, or whether it can combine entry modules with other chunks for optimization.
## Default
`'exports-only'`
## Values
### `'exports-only'`
Follows `'strict'` behavior for entry modules that have exports, but allows `'allow-extension'` behavior for entry modules without exports.
### `'strict'`
Entry chunks will exactly match the exports of their corresponding entry modules. If additional internal bindings need to be exposed (for example, when modules are shared between chunks), Rolldown will create facade chunks to maintain the exact export signature.
**Use case:** This is the recommended setting for **libraries** where you need guaranteed, stable export signatures.
### `'allow-extension'`
Entry chunks can expose all exports from the corresponding entry module, and may also include additional exports from other modules if they're bundled together. This allows more optimization opportunities but may expose internal implementation details.
### `false`
Provides maximum flexibility. Entry chunks can be merged freely with other chunks regardless of export signatures. This can lead to better optimization but may change the exposed exports significantly.
**Use case:** This is the recommended setting for **application** where you don't need guaranteed, stable export signatures.
## Understanding Facade Chunks
A facade chunk is a small wrapper chunk that Rolldown creates to preserve the exact export signature of an entry module when the actual implementation has been bundled into another chunk.
**Example scenario:**
If you have two entry points that share code, and `preserveEntrySignatures` is set to `'strict'`, Rolldown might:
1. Bundle the shared code into a common chunk
2. Create facade chunks for each entry point that re-export from the common chunk
3. This ensures each entry point maintains its exact original export signature
## In-depth
### Override per Entry Point
The `preserveEntrySignatures` option is a global setting. The only way to override it for individual entry chunks is to use the plugin API and emit those chunks via [`this.emitFile`](/reference/Interface.PluginContext#emitfile) instead of using the [`input`](/reference/InputOptions.input) option.
#### Practical Example: Mixed Library and Application Build
```js
// rolldown.config.js
export default {
preserveEntrySignatures: 'exports-only', // Default for most entries
plugins: [
{
name: 'custom-entries',
buildStart() {
// Library entry that needs strict signature preservation
this.emitFile({
type: 'chunk',
id: 'src/library/index.js',
fileName: 'library.js',
preserveEntrySignature: 'strict',
});
// Application entry that can be optimized
this.emitFile({
type: 'chunk',
id: 'src/app/main.js',
fileName: 'app.js',
preserveEntrySignature: false,
});
},
},
],
};
```
When using `this.emitFile` with type `'chunk'`, you can specify:
* **`preserveEntrySignature`**: Override the global setting
* `false`: Maximum optimization, merge chunks freely
* `'strict'`: Exact export signature preservation
* `'allow-extension'`: Allow additional exports from merged chunks
* `'exports-only'`: Strict only for modules with exports
* **`fileName`**: Custom output filename for the entry chunk
* **`id`**: Module ID or path to use as the entry point
### When to Use Each Setting
* **`'strict'`**: Building libraries, need guaranteed export signatures
* **`'exports-only'`**: Most applications, balanced approach (default)
* **`'allow-extension'`**: Advanced optimizations, okay with exposing extra exports
* **`false`**: Maximum bundle size reduction, export signatures don't matter
---
---
url: /reference/InputOptions.resolve.md
---
# resolve
* **Type**: object with the properties below
* **Optional**
Options for built-in module resolution feature.
## alias?
* **Type**: `Record`<`string`, `string` | `false` | `string`\[]>
* **Optional**
Substitute one package for another.
One use case for this feature is replacing a node-only package with a browser-friendly package in third-party code that you don't control.
### Example
```js
resolve: {
alias: {
'@': '/src',
'utils': './src/utils',
}
}
```
> \[!WARNING]
> `resolve.alias` will not call [`resolveId`](/reference/Interface.Plugin#resolveid) hooks of other plugin.
> If you want to call `resolveId` hooks of other plugin, use `viteAliasPlugin` from `rolldown/experimental` instead.
> You could find more discussion in [this issue](https://github.com/rolldown/rolldown/issues/3615)
## aliasFields?
* **Type**: `string`\[]\[]
* **Optional**
Fields in package.json to check for aliased paths.
This option is expected to be used for `browser` field support.
### Default
* `[['browser']]` for `browser` platform
* `[]` for other platforms
## conditionNames?
* **Type**: `string`\[]
* **Optional**
Condition names to use when resolving exports in package.json.
### Default
Defaults based on platform and import kind:
* `browser` platform
* `["import", "browser", "default"]` for import statements
* `["require", "browser", "default"]` for require() calls
* `node` platform
* `["import", "node", "default"]` for import statements
* `["require", "node", "default"]` for require() calls
* `neutral` platform
* `["import", "default"]` for import statements
* `["require", "default"]` for require() calls
## exportsFields?
* **Type**: `string`\[]\[]
* **Optional**
Fields in package.json to check for exports.
### Default
`[['exports']]`
## extensionAlias?
* **Type**: `Record`<`string`, `string`\[]>
* **Optional**
Map of extensions to alternative extensions.
With writing `import './foo.js'` in a file, you want to resolve it to `foo.ts` instead of `foo.js`.
You can achieve this by setting: `extensionAlias: { '.js': ['.ts', '.js'] }`.
## extensions?
* **Type**: `string`\[]
* **Optional**
Extensions to try when resolving files. These are tried in order from first to last.
### Default
`['.tsx', '.ts', '.jsx', '.js', '.json']`
## mainFields?
* **Type**: `string`\[]
* **Optional**
Fields in package.json to check for entry points.
### Default
Defaults based on platform:
* `node` platform: `['main', 'module']`
* `browser` platform: `['browser', 'module', 'main']`
* `neutral` platform: `[]`
## mainFiles?
* **Type**: `string`\[]
* **Optional**
Filenames to try when resolving directories.
### Default
```ts
['index']
```
## modules?
* **Type**: `string`\[]
* **Optional**
Directories to search for modules.
### Default
```ts
['node_modules']
```
## symlinks?
* **Type**: `boolean`
* **Optional**
Whether to follow symlinks when resolving modules.
### Default
```ts
true
```
## ~~tsconfigFilename?~~
* **Type**: `string`
* **Optional**
### Deprecated
Use the top-level [`tsconfig`](./InputOptions.tsconfig) option instead.
---
---
url: /reference/InputOptions.shimMissingExports.md
---
# shimMissingExports
* **Type**: `boolean`
* **Optional**
When `true`, creates shim variables for missing exports instead of throwing an error.
## Default
false
## Examples
### Enable shimming
```js
export default {
shimMissingExports: true,
};
```
### Example scenario
**module-a.js:**
```js
export { nonExistent } from './module-b.js';
```
**module-b.js:**
```js
// nonExistent is not actually exported here
export const something = 'value';
```
With `shimMissingExports: false` (default), this would throw an error. With `shimMissingExports: true`, Rolldown will create a shim variable:
```js
// Bundled output (simplified)
const nonExistent = undefined;
export { nonExistent, something };
```
---
---
url: /reference/InputOptions.transform.md
---
# transform
* **Type**: object with the properties below
* **Optional**
Configure how the code is transformed. This process happens after the `transform` hook.
## Example
**Enable legacy decorators**
```js
export default defineConfig({
transform: {
decorator: {
legacy: true,
},
},
})
```
Note that if you have correct `tsconfig.json` file, Rolldown will automatically detect and enable legacy decorators support.
## In-depth
Rolldown uses Oxc under the hood for transformation.
While Oxc does not support lowering the latest decorators proposal yet, Rolldown is able to bundle them.
## assumptions?
* **Type**: `CompilerAssumptions`
* **Optional**
Set assumptions in order to produce smaller output.
### Inherited from
`Omit.assumptions`
## decorator?
* **Type**: `DecoratorOptions`
* **Optional**
Decorator plugin
### Inherited from
`Omit.decorator`
## define?
* **Type**: `Record`<`string`, `string`>
* **Optional**
Replace global variables or [property accessors](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors) with the provided values.
See Oxc's [`define` option](https://oxc.rs/docs/guide/usage/transformer/global-variable-replacement.html#define) for more details.
### Example
**Replace the global variable `IS_PROD` with `true`**
```js [rolldown.config.js]
export default defineConfig({
transform: { define: { IS_PROD: 'true' } }
})
```
Result:
```js
// Input
if (IS_PROD) {
console.log('Production mode')
}
// After bundling
if (true) {
console.log('Production mode')
}
```
**Replace the property accessor `process.env.NODE_ENV` with `'production'`**
```js [rolldown.config.js]
export default defineConfig({
transform: { define: { 'process.env.NODE_ENV': "'production'" } }
})
```
Result:
```js
// Input
if (process.env.NODE_ENV === 'production') {
console.log('Production mode')
}
// After bundling
if ('production' === 'production') {
console.log('Production mode')
}
```
## dropLabels?
* **Type**: `string`\[]
* **Optional**
Remove labeled statements with these label names.
Labeled statements are JavaScript statements prefixed with a label identifier.
This option allows you to strip specific labeled statements from the output,
which is useful for removing debug-only code in production builds.
### Example
```js rolldown.config.js
export default defineConfig({
transform: { dropLabels: ['DEBUG', 'DEV'] }
})
```
Result:
```js
// Input
DEBUG: console.log('Debug info');
DEV: {
console.log('Development mode');
}
console.log('Production code');
// After bundling
console.log('Production code');
```
## helpers?
* **Type**: `Helpers`
* **Optional**
Behaviour for runtime helpers.
### Inherited from
`Omit.helpers`
## inject?
* **Type**: `Record`<`string`, `string` | \[`string`, `string`]>
* **Optional**
Inject import statements on demand.
The API is aligned with `@rollup/plugin-inject`.
See Oxc's [`inject` option](https://oxc.rs/docs/guide/usage/transformer/global-variable-replacement.html#inject) for more details.
### Supported patterns
```js
{
// import { Promise } from 'es6-promise'
Promise: ['es6-promise', 'Promise'],
// import { Promise as P } from 'es6-promise'
P: ['es6-promise', 'Promise'],
// import $ from 'jquery'
$: 'jquery',
// import * as fs from 'node:fs'
fs: ['node:fs', '*'],
// Inject shims for property access pattern
'Object.assign': path.resolve( 'src/helpers/object-assign.js' ),
}
```
## jsx?
* **Type**: `false` | `"react"` | `"react-jsx"` | `"preserve"` | `JsxOptions`
* **Optional**
Controls how JSX syntax is transformed.
* If set to `false`, an error will be thrown if JSX syntax is encountered.
* If set to `'react'`, JSX syntax will be transformed to classic runtime React code.
* If set to `'react-jsx'`, JSX syntax will be transformed to automatic runtime React code.
* If set to `'preserve'`, JSX syntax will be preserved as-is.
## plugins?
* **Type**: `PluginsOptions`
* **Optional**
Third-party plugins to use.
### See
### Inherited from
`Omit.plugins`
## target?
* **Type**: `string` | `string`\[]
* **Optional**
Sets the target environment for the generated JavaScript.
The lowest target is `es2015`.
Example:
* `'es2015'`
* `['es2020', 'chrome58', 'edge16', 'firefox57', 'node12', 'safari11']`
### Default
`esnext` (No transformation)
### See
### Inherited from
`Omit.target`
## typescript?
* **Type**: `TypeScriptOptions`
* **Optional**
Configure how TypeScript is transformed.
`typescript.declaration` is evaluated before all transforms.
### See
### Inherited from
`Omit.typescript`
---
---
url: /reference/InputOptions.treeshake.md
---
# treeshake
* **Type**: `boolean` | object with the properties below
* **Optional**
Controls tree-shaking (dead code elimination).
See the [In-depth Dead Code Elimination Guide](/in-depth/dead-code-elimination) for more details.
When `false`, tree-shaking will be disabled.
When `true`, it is equivalent to setting each options to the default value.
## Default
```ts
true
```
## annotations?
* **Type**: `boolean`
* **Optional**
Whether to respect `/*@__PURE__*/` annotations and other tree-shaking hints in the code.
See [related Oxc documentation](https://oxc.rs/docs/guide/usage/minifier/dead-code-elimination#pure-annotations) for more details.
### Default
```ts
true
```
## commonjs?
* **Type**: `boolean`
* **Optional**
Whether to enable tree-shaking for CommonJS modules. When `true`, unused exports from CommonJS modules can be eliminated from the bundle, similar to ES modules. When disabled, CommonJS modules will always be included in their entirety.
This option allows rolldown to analyze `exports.property` assignments in CommonJS modules and remove unused exports while preserving the module's side effects.
### Example
```js
// source.js (CommonJS)
exports.used = 'This will be kept';
exports.unused = 'This will be tree-shaken away';
// main.js
import { used } from './source.js';
// With commonjs: true, only the 'used' export is included in the bundle
// With commonjs: false, both exports are included
```
### Default
```ts
true
```
## invalidImportSideEffects?
* **Type**: `boolean`
* **Optional**
Whether to assume that invalid import statements might have side effects.
See [related Oxc documentation](https://oxc.rs/docs/guide/usage/minifier/dead-code-elimination#ignoring-invalid-import-statement-side-effects) for more details.
### Default
```ts
false
```
## manualPureFunctions?
* **Type**: readonly `string`\[]
* **Optional**
Array of function names that should be considered pure (no side effects) even if they can't be automatically detected as pure.
See [related Oxc documentation](https://oxc.rs/docs/guide/usage/minifier/dead-code-elimination#define-pure-functions) for more details.
### Example
```js
treeshake: {
manualPureFunctions: ['console.log', 'debug.trace']
}
```
### Default
```ts
[]
```
## moduleSideEffects?
* **Type**: `ModuleSideEffectsOption`
* **Optional**
**Values:**
* **`true`**: All modules are assumed to have side effects and will be included in the bundle even if none of their exports are used.
* **`false`**: No modules have side effects. This enables aggressive tree-shaking, removing any modules whose exports are not used.
* **`string[]`**: Array of module IDs that have side effects. Only modules in this list will be preserved if unused; all others can be tree-shaken when their exports are unused.
* **`'no-external'`**: Assumes no external modules have side effects while preserving the default behavior for local modules.
* **`ModuleSideEffectsRule[]`**: Array of rules with `test`, `external`, and `sideEffects` properties for fine-grained control.
* **`function`**: Function that receives `(id, external)` and returns whether the module has side effects.
**Important:** Setting this to `false` or using an array/string assumes that your modules and their dependencies have no side effects other than their exports. Only use this if you're certain that removing unused modules won't break your application.
> \[!NOTE]
> **Performance: Prefer `ModuleSideEffectsRule[]` over functions**
>
> When possible, use rule-based configuration instead of functions. Rules are processed entirely in Rust, while JavaScript functions require runtime calls between Rust and JavaScript, which can hurt CPU utilization during builds.
>
> **Functions should be a last resort**: Only use the function signature when your logic cannot be expressed with patterns or simple string matching.
>
> **Rule advantages**: `ModuleSideEffectsRule[]` provides better performance by avoiding Rust-JavaScript runtime calls, clearer intent, and easier maintenance.
### Example
```js
// Assume no modules have side effects (aggressive tree-shaking)
treeshake: {
moduleSideEffects: false
}
// Only specific modules have side effects (string array)
treeshake: {
moduleSideEffects: [
'lodash',
'react-dom',
]
}
// Use rules for pattern matching and granular control
treeshake: {
moduleSideEffects: [
{ test: /^node:/, sideEffects: true },
{ test: /\.css$/, sideEffects: true },
{ test: /some-package/, sideEffects: false, external: false },
]
}
// Custom function to determine side effects
treeshake: {
moduleSideEffects: (id, external) => {
if (external) return false; // external modules have no side effects
return id.includes('/side-effects/') || id.endsWith('.css');
}
}
// Assume no external modules have side effects
treeshake: {
moduleSideEffects: 'no-external',
}
```
**Common Use Cases:**
* **CSS files**: `{ test: /\.css$/, sideEffects: true }` - preserve CSS imports
* **Polyfills**: Add specific polyfill modules to the array
* **Plugins**: Modules that register themselves globally on import
* **Library development**: Set to `false` for libraries where unused exports should be removed
### Default
```ts
true
```
## propertyReadSideEffects?
* **Type**: `false` | `"always"`
* **Optional**
Controls whether reading properties from objects is considered to have side effects.
Set to `false` for more aggressive tree-shaking behavior.
See [related Oxc documentation](https://oxc.rs/docs/guide/usage/minifier/dead-code-elimination#ignoring-property-read-side-effects) for more details.
### Default
```ts
'always'
```
## propertyWriteSideEffects?
* **Type**: `false` | `"always"`
* **Optional**
Controls whether writing properties to objects is considered to have side effects.
Set to `false` for more aggressive behavior.
### Default
```ts
'always'
```
## unknownGlobalSideEffects?
* **Type**: `boolean`
* **Optional**
Whether to assume that accessing unknown global properties might have side effects.
See [related Oxc documentation](https://oxc.rs/docs/guide/usage/minifier/dead-code-elimination#ignoring-global-variable-access-side-effects) for more details.
### Default
```ts
true
```
---
---
url: /reference/InputOptions.tsconfig.md
---
# tsconfig
* **Type**: `string` | `boolean`
* **Optional**
Configures TypeScript configuration file resolution and usage.
## Options
### Auto-discovery mode (`true`)
When set to `true`, Rolldown enables auto-discovery mode. For each module, both the resolver and transformer search **upward** from the module's directory, starting at the nearest `tsconfig.json`. If it has `references`, Rolldown checks each referenced project's `files`/`include`/`exclude` and uses the first one that matches the file. If no reference matches, it checks the `tsconfig.json`'s own `files`/`include`/`exclude`. If the file matches neither, Rolldown continues upward to the next `tsconfig.json` and repeats. If no `tsconfig.json` matches the file, no config is applied (no `paths`/`baseUrl`), the same as TypeScript.
Whether an `include` glob matches a file depends on its extension: by default only TypeScript files (`.ts`/`.tsx`/`.mts`/`.cts`) match, plus `.js`/`.jsx`/`.mjs`/`.cjs` when `allowJs` is enabled. A glob that names an explicit extension (for example `src/**/*.vue`) matches that extension verbatim, so a non-TS file can pick up the project's `paths`/`baseUrl`. (`files` lists exact paths and matches them regardless of extension or `allowJs`)
If the tsconfig has `references`, Rolldown resolves them the way TypeScript does: a referenced project that includes the file **takes precedence over the root**, and the first matching reference wins. Each referenced project matches with its own `compilerOptions` (such as `allowJs`). If no referenced project includes the file, Rolldown falls back to the root's own `files`/`include`/`exclude`. A solution-style root (only `references` with an explicit empty `files`/`include`, as Vite scaffolds) has no file patterns of its own, so once none of its references match either, it does **not** own the file, and discovery continues in the parent directories as described above.
```js
export default {
tsconfig: true,
};
```
### Explicit path (`string`)
Specifies the path to a specific TypeScript configuration file. You may provide a relative path (resolved relative to `cwd`) or an absolute path.
If the tsconfig has `references`, this mode behaves like auto-discovery mode for reference resolution.
```js
export default {
tsconfig: './tsconfig.json',
};
```
```js
export default {
tsconfig: '/absolute/path/to/tsconfig.json',
};
```
:::tip
Rolldown respects `references` and `include`/`exclude` patterns in tsconfig, while esbuild does not. If you need esbuild-compatible behavior, specify a tsconfig without `references`. You can use [`extends`](https://www.typescriptlang.org/tsconfig/#extends) to share the options between the two.
:::
## What's used from tsconfig
When a tsconfig is resolved, Rolldown uses different parts for different purposes:
### Resolver
Uses the following for module path mapping:
* `compilerOptions.paths`: Path mapping for module resolution
* `compilerOptions.baseUrl`: Base directory for path resolution
### Transformer
Uses select compiler options including:
* `jsx`: JSX transformation mode
* `experimentalDecorators`: Enable decorator support
* `emitDecoratorMetadata`: Emit decorator metadata
* `strictNullChecks` (falling back to `strict`): Controls whether `null`/`undefined` are elided from nullable-union `design:type` decorator metadata, and only applies when `emitDecoratorMetadata` is enabled. When neither is set it defaults to enabled, matching TypeScript 6.0+ (where `strict` is on by default)
* `verbatimModuleSyntax`: Module syntax preservation
* `useDefineForClassFields`: Class field semantics
* And other TypeScript-specific options
### Example
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"]
}
}
}
```
With this configuration:
* JSX will use React's automatic runtime
* Path aliases like `@/utils` will resolve to `src/utils`
## Priority
Top-level `transform` options always take precedence over tsconfig settings:
```js
export default {
tsconfig: './tsconfig.json', // Has jsx: 'react-jsx'
transform: {
jsx: {
mode: 'classic', // This takes precedence
},
},
};
```
:::tip
For TypeScript projects, it's recommended to use `tsconfig: true` for auto-discovery or specify an explicit path to ensure consistent compilation behavior and enable path mapping.
:::
## Default
```ts
true
```
---
---
url: /reference/InputOptions.watch.md
---
# watch
* **Type**: `false` | object with the properties below
* **Optional**
* **Experimental**
Watch mode related options.
These options only take effect when running with the [`--watch`](/apis/cli#w-watch) flag, or using [`watch()`](Function.watch.md) API.
Rolldown uses the following APIs to watch for changes by default:
* Linux, Android: `inotify`
* macOS: `FSEvents`
* Windows: `ReadDirectoryChangesW`
* BSD descendants (e.g. FreeBSD): `kqueue`
* Other: None (polling)
There are some limitations for each API. If you need to work around them, you can use [`watcher.usePolling`](/reference/Interface.WatcherFileWatcherOptions#usepolling) to force Rolldown to use polling instead of the native API.
::: warning Using on Windows Subsystem for Linux (WSL) 2
When running Rolldown on WSL2, file system watching does not work when a file is edited by Windows applications (non-WSL2 process). This is due to [a WSL2 limitation](https://github.com/microsoft/WSL/issues/4739). This also applies to running on Docker with a WSL2 backend.
To fix it, you could either:
* **Recommended**: Use WSL2 applications to edit your files.
* It is also recommended to move the project folder outside of a Windows filesystem. Accessing Windows filesystem from WSL2 is slow. Removing that overhead will improve performance.
* Set [`usePolling: true`](/reference/Interface.WatcherFileWatcherOptions#usepolling).
* Note that `usePolling` leads to higher CPU utilization.
:::
## buildDelay?
* **Type**: `number`
* **Optional**
Configures how long Rolldown will wait for further changes until it triggers
a rebuild in milliseconds.
Even if this value is set to 0, there's a small debounce timeout configured
in the file system watcher. Setting this to a value greater than 0 will mean
that Rolldown will only trigger a rebuild if there was no change for the
configured number of milliseconds. If several configurations are watched,
Rolldown will use the largest configured build delay.
This option is useful if you use a tool that regenerates multiple source files
very slowly. Rebuilding immediately after the first change could cause Rolldown
to generate a broken intermediate build before generating a successful final
build, which can be confusing and distracting.
### Default
```ts
0
```
## clearScreen?
* **Type**: `boolean`
* **Optional**
Whether to clear the screen when a rebuild is triggered.
### Default
```ts
true
```
## exclude?
* **Type**: `string` | `RegExp` | (`string` | `RegExp`)\[]
* **Optional**
Filter to prevent files from being watched.
Strings are treated as glob patterns.
### Example
```js
export default defineConfig({
watch: {
exclude: 'node_modules/**',
},
})
```
### Default
```ts
[]
```
## include?
* **Type**: `string` | `RegExp` | (`string` | `RegExp`)\[]
* **Optional**
Filter to limit the file-watching to certain files.
Strings are treated as glob patterns.
Note that this only filters the module graph but does not allow adding
additional watch files.
### Example
```js
export default defineConfig({
watch: {
include: 'src/**',
},
})
```
### Default
```ts
[]
```
## onInvalidate?
* **Type**: (`id`) => `void`
* **Optional**
An optional function that will be called immediately every time
a module changes that is part of the build.
This is different from the [`watchChange`](Interface.Plugin.md#watchchange) plugin hook, which is
only called once the running build has finished. This may for
instance be used to prevent additional steps from being performed
if we know another build will be started anyway once the current
build finished. This callback may be called multiple times per
build as it tracks every change.
### Parameters
##### id
`string`
The id of the changed module.
### Returns
`void`
## skipWrite?
* **Type**: `boolean`
* **Optional**
Whether to skip the [`bundle.write()`](Interface.RolldownBuild.md#write) step when a rebuild is triggered.
### Default
```ts
false
```
## watcher?
* **Type**: [`WatcherFileWatcherOptions`](Interface.WatcherFileWatcherOptions.md)
* **Optional**
File watcher options for configuring how file changes are detected.
---
---
url: /reference/OutputOptions.advancedChunks.md
---
# ~~advancedChunks~~
* **Type**: object with the properties below
* **Optional**
## ~~groups?~~
* **Type**: [`CodeSplittingGroup`](TypeAlias.CodeSplittingGroup.md)\[]
* **Optional**
## ~~includeDependenciesRecursively?~~
* **Type**: `boolean`
* **Optional**
## ~~maxModuleSize?~~
* **Type**: `number`
* **Optional**
## ~~maxSize?~~
* **Type**: `number`
* **Optional**
## ~~minModuleSize?~~
* **Type**: `number`
* **Optional**
## ~~minShareCount?~~
* **Type**: `number`
* **Optional**
## ~~minSize?~~
* **Type**: `number`
* **Optional**
## Deprecated
Please use [`output.codeSplitting`](./OutputOptions.codeSplitting) instead.
Allows you to do manual chunking.
:::warning
If `advancedChunks` and `codeSplitting` are both specified, `advancedChunks` option will be ignored.
:::
---
---
url: /reference/OutputOptions.assetFileNames.md
---
# assetFileNames
* **Type**: `string` | ((`chunkInfo`) => `string`)
* **Optional**
The pattern to use for naming custom emitted assets to include in the build output, or a function that is called per asset with [`PreRenderedAsset`](Interface.PreRenderedAsset.md) to return such a pattern.
Patterns support the following placeholders:
* `[extname]`: The file extension of the asset including a leading dot, e.g. `.css`.
* `[ext]`: The file extension without a leading dot, e.g. css.
* `[hash]`: A hash based on the content of the asset. You can also set a specific hash length via e.g. `[hash:10]`. By default, it will create a base-64 hash. If you need a reduced character set, see [`output.hashCharacters`](./OutputOptions.hashCharacters).
* `[name]`: The file name of the asset excluding any extension.
Forward slashes (`/`) can be used to place files in sub-directories.
See also [`output.chunkFileNames`](./OutputOptions.chunkFileNames), [`output.entryFileNames`](./OutputOptions.entryFileNames).
## Default
```ts
'assets/[name]-[hash][extname]'
```
---
---
url: /reference/OutputOptions.banner.md
---
# banner
* **Type**: `string` | ((`chunk`) => `string` | `Promise`<`string`>)
* **Optional**
A string to prepend to the bundle before [`renderChunk`](Interface.Plugin.md#renderchunk) hook.
See [`output.intro`](./OutputOptions.intro), [`output.postBanner`](./OutputOptions.postBanner) as well.
:::warning
When using `output.banner` with minification enabled, the banner content may be stripped out unless it is formatted as a legal comment. To ensure your banner persists through minification, do either:
* Use [`output.postBanner`](/reference/OutputOptions.postBanner) instead, which are added after minification, or
* Use one of these comment formats:
* Comments starting with `/*!` (e.g., `/*! My banner */`)
* Comments containing `@license` (e.g., `/* @license My banner */`)
* Comments containing `@preserve` (e.g., `/* @preserve My banner */`)
* Comments starting with `//!` (for single-line comments)
The latter way's behavior is controlled by the [`output.legalComments`](/reference/OutputOptions.legalComments) option, which defaults to `'inline'` and preserves these special comment formats.
:::
## Examples
### Adding shebang for CLI tools
```js
export default {
output: {
banner: (chunk) => {
// Add shebang only to the CLI entry point
if (chunk.name === 'cli') {
return '#!/usr/bin/env node';
}
return '';
},
},
};
```
### Adding "use strict" directive
```js
export default {
output: {
format: 'cjs',
banner: '"use strict";',
},
};
```
---
---
url: /reference/OutputOptions.chunkFileNames.md
---
# chunkFileNames
* **Type**: `string` | ((`chunkInfo`) => `string`)
* **Optional**
The pattern to use for naming shared chunks created when code-splitting, or a function that is called per chunk with [`PreRenderedChunk`](Interface.PreRenderedChunk.md) to return such a pattern.
Patterns support the following placeholders:
* `[format]`: The rendering format defined in the output options. The value is any of [`InternalModuleFormat`](TypeAlias.InternalModuleFormat.md).
* `[hash]`: A hash based only on the content of the final generated chunk, including transformations in `renderChunk` and any referenced file hashes. You can also set a specific hash length via e.g. `[hash:10]`. By default, it will create a base-64 hash. If you need a reduced character set, see [`output.hashCharacters`](./OutputOptions.hashCharacters).
* `[name]`: The name of the chunk. This can be explicitly set via the [`output.codeSplitting`](./OutputOptions.codeSplitting) option or when the chunk is created by a plugin via `this.emitFile`. Otherwise, it will be derived from the chunk contents.
Forward slashes (`/`) can be used to place files in sub-directories.
See also [`output.assetFileNames`](./OutputOptions.assetFileNames), [`output.entryFileNames`](./OutputOptions.entryFileNames).
## Default
```ts
'[name]-[hash].js'
```
---
---
url: /reference/OutputOptions.cleanDir.md
---
# cleanDir
* **Type**: `boolean`
* **Optional**
Clean output directory ([`output.dir`](./OutputOptions.dir)) before emitting output.
## Default
false
## Examples
### Basic usage
```js
export default {
output: {
cleanDir: true,
},
};
```
### Multiple outputs in one config
When multiple outputs share the same directory, only set `cleanDir: true` for the first output:
```js
export default {
output: [
{
dir: 'dist',
format: 'es',
cleanDir: true, // Clean on first output
},
{
dir: 'dist',
format: 'cjs',
// cleanDir defaults to false, so files from first output are preserved
},
],
};
```
### Multiple configurations
When multiple configurations share the same directory, only set `cleanDir: true` for the first configuration:
```js
export default [
{
input: 'src/index.js',
output: {
dir: 'dist',
cleanDir: true, // Clean on first configuration
},
},
{
input: 'src/other.js',
output: {
dir: 'dist',
// cleanDir defaults to false, so files from first config are preserved
},
},
];
```
### Different directories in multiple outputs
When multiple outputs use different directories, you can safely use `cleanDir: true` for each:
```js
export default {
output: [
{
dir: 'dist/es',
format: 'es',
cleanDir: true, // Safe - different directory
},
{
dir: 'dist/cjs',
format: 'cjs',
cleanDir: true, // Safe - different directory
},
],
};
```
## In-depth
### Execution timing
The timing of the directory cleanup is important for plugin compatibility:
* The cleanup occurs **before** the `generateBundle` hook is called
* Files created by plugins during `generateBundle` or `writeBundle` hooks are **not** deleted
* This ensures that plugin-generated files are preserved even when `cleanDir` is enabled
For advanced use cases involving multiple outputs with the same `output.dir`, consider using a separate cleanup script for more control over the cleanup process.
### ⚠️ Multiple configurations behavior
When using multiple configurations or outputs, the `cleanDir` option will be executed **separately for each configuration/output** following the order they are defined.
**The two patterns:**
* **Multiple configurations**: `export default defineConfig([{ output: { cleanDir: true, ... } }, { output: {...} }])`
* **Multiple outputs in one config**: `defineConfig({ output: [{ cleanDir: true, ... }, { ... }] })`
**The problem:**
If multiple outputs share the same `output.dir` and have `cleanDir: true`, later outputs may clean files generated by earlier outputs. This happens because each output executes its cleanup independently.
**Best practice:**
To avoid this issue, only set `cleanDir: true` for the first output, or use different output directories. This ensures that all generated files are preserved.
---
---
url: /reference/OutputOptions.codeSplitting.md
---
# codeSplitting
* **Type**: `boolean` | object with the properties below
* **Optional**
Controls how code splitting is performed.
* `true`: Default behavior, automatic code splitting. **(default)**
* `false`: Inline all dynamic imports into a single bundle (equivalent to deprecated `inlineDynamicImports: true`).
* `object`: Advanced manual code splitting configuration.
For deeper understanding, please refer to the in-depth [documentation](/in-depth/manual-code-splitting).
:::warning
Be aware that manual code splitting can change the behavior of the application if side effects are triggered before the corresponding modules are actually used. You can change the chunking configuration to keep order-sensitive modules together, or you can use the [`output.strictExecutionOrder`](/reference/OutputOptions.strictExecutionOrder) option to preserve source execution order. The option wraps modules so their bodies run in source order, at a bundle-size cost; `experimental.onDemandWrapping` replaces wrap-all with a conservative plan derived from predicted chunk execution hazards.
:::
## Example
**Basic vendor chunk**
```js
export default defineConfig({
output: {
codeSplitting: {
minSize: 20000,
groups: [
{
name: 'vendor',
test: /node_modules/,
},
],
},
},
});
```
**Multiple chunk groups with priorities**
```js
export default defineConfig({
output: {
codeSplitting: {
groups: [
{
name: 'react-vendor',
test: /node_modules[\\/]react/,
priority: 20,
},
{
name: 'ui-vendor',
test: /node_modules[\\/]antd/,
priority: 15,
},
{
name: 'vendor',
test: /node_modules/,
priority: 10,
},
{
name: 'common',
minShareCount: 2,
minSize: 10000,
priority: 5,
},
],
},
},
});
```
**Size-based splitting**
```js
export default defineConfig({
output: {
codeSplitting: {
groups: [
{
name: 'large-libs',
test: /node_modules/,
minSize: 100000, // 100KB
maxSize: 250000, // 250KB
priority: 10,
},
],
},
},
});
```
## Default
```ts
true
```
## groups?
* **Type**: [`CodeSplittingGroup`](TypeAlias.CodeSplittingGroup.md)\[]
* **Optional**
Groups to be used for code splitting.
## includeDependenciesRecursively?
* **Type**: `boolean`
* **Optional**
Global fallback of [`group.includeDependenciesRecursively`](TypeAlias.CodeSplittingGroup.md#includedependenciesrecursively), if it's not specified in the group.
## maxModuleSize?
* **Type**: `number`
* **Optional**
Global fallback of [`group.maxModuleSize`](TypeAlias.CodeSplittingGroup.md#maxmodulesize), if it's not specified in the group.
## maxSize?
* **Type**: `number`
* **Optional**
Global fallback of [`group.maxSize`](TypeAlias.CodeSplittingGroup.md#maxsize), if it's not specified in the group.
## minModuleSize?
* **Type**: `number`
* **Optional**
Global fallback of [`group.minModuleSize`](TypeAlias.CodeSplittingGroup.md#minmodulesize), if it's not specified in the group.
## minShareCount?
* **Type**: `number`
* **Optional**
Global fallback of [`group.minShareCount`](TypeAlias.CodeSplittingGroup.md#minsharecount), if it's not specified in the group.
## minSize?
* **Type**: `number`
* **Optional**
Global fallback of [`group.minSize`](TypeAlias.CodeSplittingGroup.md#minsize), if it's not specified in the group.
---
---
url: /reference/OutputOptions.comments.md
---
# comments
* **Type**: `boolean` | object with the properties below
* **Optional**
Control which comments are preserved in the output.
* `true`: Preserve legal, annotation, and JSDoc comments (default)
* `false`: Strip all comments
* Object: Granular control over comment categories
Note: Regular line and block comments without these markers
are always removed regardless of this option.
When both `legalComments` and `comments.legal` are set, `comments.legal` takes priority.
## Default
```ts
true
```
## annotation?
* **Type**: `boolean`
* **Optional**
Comments that contain `@__PURE__`, `@__NO_SIDE_EFFECTS__` or `@vite-ignore`
## jsdoc?
* **Type**: `boolean`
* **Optional**
JSDoc comments
## legal?
* **Type**: `boolean`
* **Optional**
Comments that contain `@license`, `@preserve` or start with `//!` or `/*!`
---
---
url: /reference/OutputOptions.dir.md
---
# dir
* **Type**: `string`
* **Optional**
The directory in which all generated chunks are placed.
The [`output.file`](./OutputOptions.file) option can be used instead if only a single chunk is generated.
The output directory will be generated if it does not already exist, but it will not be cleared if it already contains some files. Any generated files will silently overwrite existing files with the same name. If you want the output directory to only contain files from the current run, you can use [`output.cleanDir`](/reference/OutputOptions.cleanDir) option.
## Default
```ts
'dist'
```
---
---
url: /reference/OutputOptions.dynamicImportInCjs.md
---
# dynamicImportInCjs
* **Type**: `boolean`
* **Optional**
Whether to keep external dynamic imports as `import(...)` expressions in CommonJS output.
If set to `false`, external dynamic imports will be rewritten to use `require(...)` calls.
This may be necessary to support environments that do not support dynamic `import()` in CommonJS modules like old Node.js versions.
## Default
```ts
true
```
---
---
url: /reference/OutputOptions.entryFileNames.md
---
# entryFileNames
* **Type**: `string` | ((`chunkInfo`) => `string`)
* **Optional**
The pattern to use for chunks created from entry points, or a function that is called per entry chunk with [`PreRenderedChunk`](Interface.PreRenderedChunk.md) to return such a pattern.
Patterns support the following placeholders:
* `[format]`: The rendering format defined in the output options. The value is any of [`InternalModuleFormat`](TypeAlias.InternalModuleFormat.md).
* `[hash]`: A hash based only on the content of the final generated chunk, including transformations in `renderChunk` and any referenced file hashes. You can also set a specific hash length via e.g. `[hash:10]`. By default, it will create a base-64 hash. If you need a reduced character set, see [`output.hashCharacters`](./OutputOptions.hashCharacters).
* `[name]`: The file name (without extension) of the entry point, unless the object form of input was used to define a different name.
Forward slashes (`/`) can be used to place files in sub-directories. This pattern will also be used for every file when setting the [`output.preserveModules`](./OutputOptions.preserveModules) option.
See also [`output.assetFileNames`](./OutputOptions.assetFileNames), [`output.chunkFileNames`](./OutputOptions.chunkFileNames).
## Default
```ts
'[name].js'
```
---
---
url: /reference/OutputOptions.esModule.md
---
# esModule
* **Type**: `boolean` | `"if-default-prop"`
* **Optional**
Whether to add a `__esModule: true` property when generating exports for non-ES [formats](./OutputOptions.format).
This property signifies that the exported value is the namespace of an ES module and that the default export of this module corresponds to the `.default` property of the exported object.
* `true`: Always add the property when using [named exports mode](./OutputOptions.exports), which is similar to what other tools do.
* `"if-default-prop"`: Only add the property when using [named exports mode](./OutputOptions.exports) and there also is a default export. The subtle difference is that if there is no default export, consumers of the CommonJS version of your library will get all named exports as default export instead of an error or `undefined`.
* `false`: Never add the property even if the default export would become a property `.default`.
## Default
'if-default-prop'
## Interaction with Consuming Tools
Different tools handle the `__esModule` marker differently when importing your bundle:
* **Rolldown**: Use heuristics based on Node.js's behavior. See the [Bundling CJS](/in-depth/bundling-cjs#ambiguous-default-import-from-cjs-modules) guide for more details.
* **esbuild**: Use heuristics based on Node.js's behavior.
* **Node.js**: Does not respect `__esModule`. The default export is the `module.exports` value.
* **Babel**: Respects `__esModule`.
---
---
url: /reference/OutputOptions.exports.md
---
# exports
* **Type**: `"auto"` | `"named"` | `"default"` | `"none"`
* **Optional**
Which exports mode to use.
When `'auto'` is used, Rolldown will automatically determine the export mode based on the exports of the `input` modules. If the `input` modules have a single default export, then `'default'` mode is used. If the `input` modules have named exports, then `'named'` mode is used. If there are no exports, then `'none'` mode is used.
`'default'` can only be used when the `input` modules have a single default export. `'none'` can only be used when the `input` modules have no exports. Otherwise, Rolldown will throw an error.
The difference between `'default'` and `'named'` affects how other people can consume your bundle. If you use `'default'`, a CommonJS user could do this, for example:
```js
// your-lib package entry
export default 'Hello world';
// a CommonJS consumer
/* require( "your-lib" ) returns "Hello world" */
const hello = require('your-lib');
```
With `'named'`, a user would do this instead:
```js
// your-lib package entry
export const hello = 'Hello world';
// a CommonJS consumer
/* require( "your-lib" ) returns {hello: "Hello world"} */
const hello = require('your-lib').hello;
/* or using destructuring */
const { hello } = require('your-lib');
```
The wrinkle is that if you use `'named'` exports but also have a default export, a user would have to do something like this to use the default export:
```js
// your-lib package entry
export default 'foo';
export const bar = 'bar';
// a CommonJS consumer
/* require( "your-lib" ) returns {default: "foo", bar: "bar"} */
const foo = require('your-lib').default;
const bar = require('your-lib').bar;
/* or using destructuring */
const { default: foo, bar } = require('your-lib');
```
::: tip
There are many tools that are capable of resolving a CommonJS `require(...)` call with an ES module. If you are generating CommonJS output that is meant to be interchangeable with ESM output for those tools, you should always use `'named'` export mode. The reason is that most of those tools will by default return the namespace of an ES module on `require` where the default export is the `.default` property.
In other words for those tools, you cannot create a package interface where `const lib = require("your-lib")` yields the same as `import lib from "your-lib"`. With `'named'` export mode however, `const {lib} = require("your-lib")` will be equivalent to `import {lib} from "your-lib"`.
:::
## Default
```ts
'auto'
```
---
---
url: /reference/OutputOptions.extend.md
---
# extend
* **Type**: `boolean`
* **Optional**
Whether to extend the global variable defined by the [`name`](./OutputOptions.name) option in `umd` or `iife` [formats](./OutputOptions.format).
When `true`, the global variable will be defined as `global.name = global.name || {}`.
When `false`, the global defined by name will be overwritten like `global.name = {}`.
## Default
```ts
false
```
---
---
url: /reference/OutputOptions.externalLiveBindings.md
---
# externalLiveBindings
* **Type**: `boolean`
* **Optional**
Whether to generate code to support live bindings for [external](Interface.InputOptions.md#external) imports.
With the default value of `true`, Rolldown will generate code to support live bindings for external imports.
When set to `false`, Rolldown will assume that exports from external modules do not change. This will allow Rolldown to generate smaller code. Note that this can cause issues when there are circular dependencies involving an external dependency.
## Default
true
## Example
```js
// input
export { x } from 'external';
```
```js
// CJS output with externalLiveBindings: true
var external = require('external');
Object.defineProperty(exports, 'x', {
enumerable: true,
get: function () {
return external.x;
},
});
```
```js
// CJS output with externalLiveBindings: false
var external = require('external');
exports.x = external.x;
```
---
---
url: /reference/OutputOptions.file.md
---
# file
* **Type**: `string`
* **Optional**
The file path for the single generated chunk.
The [`output.dir`](./OutputOptions.dir) option should be used instead if multiple chunks are generated.
---
---
url: /reference/OutputOptions.footer.md
---
# footer
* **Type**: `string` | ((`chunk`) => `string` | `Promise`<`string`>)
* **Optional**
A string to append to the bundle before [`renderChunk`](Interface.Plugin.md#renderchunk) hook.
See [`output.outro`](./OutputOptions.outro), [`output.postFooter`](./OutputOptions.postFooter) as well.
:::warning
When using `output.footer` with minification enabled, the footer content may be stripped out unless it is formatted as a legal comment. To ensure your footer persists through minification, do either:
* Use [`output.postFooter`](/reference/OutputOptions.postFooter) instead, which is added after minification, or
* Use one of these comment formats:
* Comments starting with `/*!` (e.g., `/*! My footer */`)
* Comments containing `@license` (e.g., `/* @license My footer */`)
* Comments containing `@preserve` (e.g., `/* @preserve My footer */`)
* Comments starting with `//!` (for single-line comments)
The latter way's behavior is controlled by the [`output.legalComments`](/reference/OutputOptions.legalComments) option, which defaults to `'inline'` and preserves these special comment formats.
:::
## Examples
### Expose the default export as `module.exports` for CJS output with all named exports as properties
```js
export default {
output: {
format: 'cjs',
exports: 'named',
footer: (chunk) => {
if (chunk.isEntry) {
return `
module.exports = exports.default;
module.exports.default = module.exports;
module.exports.foo = module.exports.default.foo;`;
}
return '';
},
},
};
```
---
---
url: /reference/OutputOptions.format.md
---
# format
* **Type**: `"es"` | `"cjs"` | `"iife"` | `"umd"` | `"module"` | `"esm"` | `"commonjs"`
* **Optional**
Expected format of generated code.
* `'es'`, `'esm'` and `'module'` are the same format, all stand for ES module.
* `'cjs'` and `'commonjs'` are the same format, all stand for CommonJS module.
* `'iife'` stands for [Immediately Invoked Function Expression](https://developer.mozilla.org/en-US/docs/Glossary/IIFE).
* `'umd'` stands for [Universal Module Definition](https://github.com/umdjs/umd).
## Default
'es'
## In-depth
### ES Module
[ES modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) (ESM) are the official JavaScript module standard. When `output.format: 'es'` is used, the bundle will use `export` syntax like this:
```js
function exportedFunction() {
/* ... */
}
let exportedValue = '/* ... */';
export { exportedFunction, exportedValue };
```
To load ES modules, use `/i,
``
);
fs.writeFileSync(htmlPath, html);
delete bundle['importmap.json'];
}
}
}
]
}
```
> \[!TIP]
> If you want to learn more, you can check out the example here: [examples/chunk-import-map](https://github.com/rolldown/rolldown/tree/main/examples/chunk-import-map)
##### Default
```ts
false
```
#### chunkModulesOrder?
* **Type**: `"exec-order"` | `"module-id"`
* **Optional**
Control which order should be used when rendering modules in a chunk.
Available options:
* `exec-order`: Almost equivalent to the topological order of the module graph, but specially handling when module graph has cycle.
* `module-id`: This is more friendly for gzip compression, especially for some javascript static asset lib (e.g. icon library)
> \[!NOTE]
> Try to sort the modules by their module id if possible (Since rolldown scope hoist all modules in the chunk, we only try to sort those modules by module id if we could ensure runtime behavior is correct after sorting).
##### Default
```ts
'exec-order'
```
#### chunkOptimization?
* **Type**: `boolean` | [`ChunkOptimizationOptions`](Interface.ChunkOptimizationOptions.md)
* **Optional**
Control chunk optimizations.
`true` enables both common-chunk merging and redundant dynamic chunk-load avoidance.
`false` disables all chunk optimizations. Use the object form to control
`mergeCommonChunks` and `avoidRedundantChunkLoads` separately.
These optimizations are automatically disabled when any module uses top-level await (TLA) or contains TLA dependencies,
as they could affect execution order guarantees.
##### Default
```ts
true
```
#### incrementalBuild?
* **Type**: `boolean`
* **Optional**
Enable incremental build support. Required to be used with `watch` mode.
##### Default
```ts
false
```
#### lazyBarrel?
* **Type**: `boolean`
* **Optional**
Control whether to enable lazy barrel optimization.
Lazy barrel optimization avoids compiling unused re-export modules in side-effect-free barrel modules,
significantly improving build performance for large codebases with many barrel modules.
This option is planned to be removed in the future. If you need to opt out, please open an issue
describing your use case so we can address it before the option is gone.
##### See
[Lazy Barrel Documentation](/in-depth/lazy-barrel-optimization)
##### Default
```ts
false
```
#### nativeMagicString?
* **Type**: `boolean`
* **Optional**
Use native Rust implementation of MagicString for source map generation.
[MagicString](https://github.com/rich-harris/magic-string) is a JavaScript library commonly used by bundlers
for string manipulation and source map generation. When enabled, rolldown will use a native Rust
implementation of MagicString instead of the JavaScript version, providing significantly better performance
during source map generation and code transformation.
**Benefits**
* **Improved Performance**: The native Rust implementation is typically faster than the JavaScript version,
especially for large codebases with extensive source maps.
* **Background Processing**: Source map generation is performed asynchronously in a background thread,
allowing the main bundling process to continue without blocking. This parallel processing can significantly
reduce overall build times when working with JavaScript transform hooks.
* **Better Integration**: Seamless integration with rolldown's native Rust architecture.
##### Example
```js
export default {
experimental: {
nativeMagicString: true
},
output: {
sourcemap: true
}
}
```
> \[!NOTE]
> This is an experimental feature. While it aims to provide identical behavior to the JavaScript
> implementation, there may be edge cases. Please report any discrepancies you encounter.
> For a complete working example, see [examples/native-magic-string](https://github.com/rolldown/rolldown/tree/main/examples/native-magic-string)
##### Default
```ts
false
```
#### resolveNewUrlToAsset?
* **Type**: `boolean`
* **Optional**
When enabled, `new URL()` calls will be transformed to a stable asset URL which includes the updated name and content hash.
It is necessary to pass `import.meta.url` as the second argument to the
`new URL` constructor, otherwise no transform will be applied.
:::warning
JavaScript and TypeScript files referenced via `new URL('./file.js', import.meta.url)` or `new URL('./file.ts', import.meta.url)` will **not** be transformed or bundled. The file will be copied as-is, meaning TypeScript files remain untransformed and dependencies are not resolved.
The expected behavior for JS/TS files is still being discussed and may
change in future releases. See [#7258](https://github.com/rolldown/rolldown/issues/7258) for more context.
:::
##### Example
```js
// main.js
const url = new URL('./styles.css', import.meta.url);
console.log(url);
// Example output after bundling WITHOUT the option (default)
const url = new URL('./styles.css', import.meta.url);
console.log(url);
// Example output after bundling WITH `experimental.resolveNewUrlToAsset` set to `true`
const url = new URL('assets/styles-CjdrdY7X.css', import.meta.url);
console.log(url);
```
##### Default
```ts
false
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`experimental`](Interface.InputOptions.md#experimental)
***
### external?
* **Type**: `string` | `RegExp` | (`string` | `RegExp`)\[] | [`ExternalOptionFunction`](TypeAlias.ExternalOptionFunction.md)
* **Optional**
Specifies which modules should be treated as external and not bundled. External modules will be left as import statements in the output.
When creating an `iife` or `umd` bundle, you will need to provide global variable names to replace your external imports via the [`output.globals`](/reference/OutputOptions.globals) option.
#### How Matching Works
The `external` option is checked **twice** during module resolution, against two different kinds of IDs:
1. **First check — raw import specifier** (e.g. `'lodash'`, `'./utils'`) is tested before any resolution happens, with `isResolved: false`. To mark `import "dependency"` as external, use `"dependency"` exactly as written in the import statement. If it matches, the module is immediately marked as external — **plugins and the internal resolver are skipped entirely**.
2. **Second check — resolved ID** (e.g. `'/project/node_modules/vue/dist/vue.runtime.esm-bundler.js'`) is tested after plugins and the internal resolver have run, with `isResolved: true`. If it matches, the module is marked as external.
The second check only runs if the first did not match. In both cases, [`makeAbsoluteExternalsRelative`](/reference/InputOptions.makeAbsoluteExternalsRelative) applies uniformly to determine whether absolute IDs are re-relativized in the output.
See the [External Modules guide](/in-depth/external-modules) for a detailed explanation of the full resolution flow and how the output path is determined.
#### Examples
##### String pattern
```js
export default {
external: 'react',
};
```
##### Regular expression
```js
export default {
external: /^react\//,
};
```
##### Array of patterns
```js
export default {
external: ['react', 'react-dom', /^lodash/],
};
```
##### Function
```js
import path from 'node:path';
export default {
external: (id) => {
return !id.startsWith('.') && !path.isAbsolute(id);
},
};
```
::: warning Performance Overhead
Using the function form has significant performance overhead because Rolldown is written in Rust and must call JavaScript functions from Rust for every module in your dependency graph.
Unless the logic relies on values other than `id`, it is recommended to use non-function values.
:::
#### Caveats
##### Avoid `/node_modules/` for npm packages
Because the pattern `/node_modules/` can only match on the **second check** (the resolved absolute path), the full resolved path like `/path/to/node_modules/vue/dist/vue.runtime.esm-bundler.js` ends up in the output verbatim. This makes the output non-portable.
Instead, match packages by name or use a pattern for bare module IDs:
```js
export default {
// Exact package names
external: ['vue', 'react', 'react-dom'],
// Package name patterns
external: [/^vue/, /^react/, /^@mui/],
// All bare module IDs (not starting with `.` or `/` or `C:\`)
external: /^[^./](?!:[/\\])/,
};
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`external`](Interface.InputOptions.md#external)
***
### input?
* **Type**: `string` | `string`\[] | `Record`<`string`, `string`>
* **Optional**
Defines entries and location(s) of entry modules for the bundle. Relative paths are resolved based on the [`cwd`](Interface.InputOptions.md#cwd) option.
#### Examples
##### Single entry
```js
export default defineConfig({
input: 'src/index.js',
});
```
##### Multiple entries
```js
export default defineConfig({
input: ['src/index.js', 'src/vendor.js'],
});
```
##### Named multiple entries
```js
export default defineConfig({
input: {
index: 'src/index.js',
utils: 'src/utils/index.js',
'components/Foo': 'src/components/Foo.js',
},
});
```
#### In-depth
`input` allows you to specify one or more [entries](/glossary/entry) with [names](/glossary/entry-name) for the bundling process.
When multiple entries are specified (either as an array or an object), Rolldown will create separate [entry chunks](/glossary/entry-chunk) for each entry. If a module is referenced from multiple entries, Rolldown will share the code of that module for those entries.
The generated chunk names will follow the [`output.chunkFileNames`](/reference/OutputOptions.chunkFileNames) option. When using the object form, the `[name]` portion of the file name will be the name of the object property while for the array form, it will be the file name of the entry point. Note that it is possible when using the object form to put entry points into different sub-folders by adding a `/` to the name.
If you want to convert a set of files to another format while maintaining the file structure and export signatures, the recommended way—instead of using [`output.preserveModules`](/reference/OutputOptions.preserveModules) that may tree-shake exports as well as emit virtual files created by plugins—is to turn every file into an entry point. You can do so dynamically e.g. via the [`tinyglobby`](https://github.com/SuperchupuDev/tinyglobby) package:
```js
import { defineConfig } from 'rolldown';
import { globSync } from 'tinyglobby';
import path from 'node:path';
export default defineConfig({
input: Object.fromEntries(
globSync('src/**/*.js').map((file) => [
// This removes `src/` as well as the file extension from each
// file, so e.g. src/nested/foo.js becomes nested/foo, and
// normalizes Windows backslashes to forward slashes.
path
.relative('src', file.slice(0, file.length - path.extname(file).length))
.split(path.sep)
.join('/'),
// This expands the relative paths to absolute paths, so e.g.
// src/nested/foo.js becomes /project/src/nested/foo.js
path.resolve(file),
]),
),
output: {
dir: 'dist',
format: 'esm',
},
});
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`input`](Interface.InputOptions.md#input)
***
### logLevel?
* **Type**: `"info"` | `"debug"` | `"warn"` | `"silent"`
* **Optional**
Controls the verbosity of console logging during the build.
The default logLevel of "info" means that info and warnings logs will be processed while debug logs will be swallowed, which means that they are neither passed to plugin [`onLog`](/reference/Interface.Plugin#onlog) hooks nor the [`onLog`](/reference/InputOptions.onLog) option or printed to the console.
#### Default
```ts
'info'
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`logLevel`](Interface.InputOptions.md#loglevel)
***
### makeAbsoluteExternalsRelative?
* **Type**: `false` | `true` | `"ifRelativeSource"`
* **Optional**
Determines if absolute external paths should be converted to relative paths in the output.
This does not only apply to paths that are absolute in the source but also to paths that are resolved to an absolute path by either a plugin or Rolldown core.
Despite the name, this option controls two things:
1. **Resolve-time normalization** — whether relative specifiers (e.g. `'./utils'`) are normalized to absolute paths internally for deduplication. Without normalization, `'./utils'` imported from different directories may collapse into one external module because they share the same raw string.
2. **Render-time output** — whether a resolved module ID (the absolute path after resolution) gets converted to a relative path in the output. It does not affect bare specifiers (e.g. `'lodash'`) or IDs that are already relative.
Both behaviors depend on the **original import specifier** (what you wrote in source code, e.g. `'./utils'`) vs the **resolved module ID** (the absolute path after resolution, e.g. `'/project/src/utils.js'`). See the [External Modules guide](/in-depth/external-modules) for how this fits into the full resolution flow.
#### Values
##### `"ifRelativeSource"` (default)
Only convert the resolved absolute ID to a relative path if the **original import specifier** was relative.
```js
// Original: relative specifier → converted to relative in output
import './lib/utils.js'; // → import './lib/utils.js'
// Original: absolute specifier → kept absolute in output
import '/project/lib/utils.js'; // → import '/project/lib/utils.js'
```
The idea: if you wrote a relative import, you probably want a relative import in the output. If you wrote an absolute import, you probably meant it to stay absolute.
##### `true`
Always convert resolved absolute IDs to relative paths:
```js
// Both become relative in output
import './lib/utils.js'; // → import './lib/utils.js'
import '/project/lib/utils.js'; // → import '../lib/utils.js'
```
When converting an absolute path to a relative path, Rolldown does *not* take the [`file`](/reference/OutputOptions.file) or [`dir`](/reference/OutputOptions.dir) options into account, because those may not be present e.g. for builds using the JavaScript API. Instead, it assumes that the root of the generated bundle is located at the common shared parent directory of all entry points.
If the output chunk is itself nested in a subdirectory by choosing e.g. `chunkFileNames: "chunks/[name].js"`, the relative path is adjusted accordingly.
##### `false`
Never convert. Resolved absolute IDs are kept as-is. Relative specifiers are also **not** normalized to absolute paths internally, which means two files importing `'./utils'` from different directories may be treated as the same external module.
```js
import './lib/utils.js'; // → import './lib/utils.js' (as-is)
import '/project/lib/utils.js'; // → import '/project/lib/utils.js' (as-is)
```
::: warning Deduplication issue with `false`
Setting `makeAbsoluteExternalsRelative: false` disables the normalization of relative specifiers. This means `'./utils'` imported from `src/a.js` and `'./utils'` imported from `src/b/c.js` may be treated as the same external module, even though they refer to different files. Use `false` only if you are certain all your external specifiers are already unique (e.g. bare package names).
:::
#### Example
Given `import '/project/lib/utils.js'` (absolute specifier) in an external module, with output at `dist/index.js`:
| `makeAbsoluteExternalsRelative` | Output path |
| ------------------------------- | ------------------------- |
| `true` | `'../lib/utils.js'` |
| `"ifRelativeSource"` (default) | `'/project/lib/utils.js'` |
| `false` | `'/project/lib/utils.js'` |
Given `import './lib/utils.js'` (relative specifier) with a flat output at `dist/index.js`:
| `makeAbsoluteExternalsRelative` | Output path |
| ------------------------------- | ------------------ |
| `true` | `'./lib/utils.js'` |
| `"ifRelativeSource"` (default) | `'./lib/utils.js'` |
| `false` | `'./lib/utils.js'` |
The same relative specifier with a nested chunk at `dist/chunks/index.js`:
| `makeAbsoluteExternalsRelative` | Output path |
| ------------------------------- | ------------------- |
| `true` | `'../lib/utils.js'` |
| `"ifRelativeSource"` (default) | `'../lib/utils.js'` |
| `false` | `'./lib/utils.js'` |
With `true` or `"ifRelativeSource"`, relative specifiers are normalized to absolute paths internally, then re-relativized from the output chunk's location — so the path adjusts correctly for nested chunks. With `false`, the raw specifier is kept as-is with no adjustment.
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`makeAbsoluteExternalsRelative`](Interface.InputOptions.md#makeabsoluteexternalsrelative)
***
### moduleTypes?
* **Type**: [`ModuleTypes`](TypeAlias.ModuleTypes.md)
* **Optional**
Maps file patterns to module types, controlling how files are processed.
This is conceptually similar to [esbuild's `loader`](https://esbuild.github.io/api/#loader) option, allowing you to specify how each file extensions should be handled.
See [the In-Depth Guide](/in-depth/module-types) for more details.
#### Example
```js
import { defineConfig } from 'rolldown'
export default defineConfig({
moduleTypes: {
'.frag': 'text',
}
})
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`moduleTypes`](Interface.InputOptions.md#moduletypes)
***
### onLog?
* **Type**: (`level`, `log`, `defaultHandler`) => `void`
* **Optional**
A function that intercepts log messages. If not supplied, logs are printed to the console.
This handler will not be invoked if logs are filtered out by the [`logLevel`](/reference/InputOptions.logLevel) option. I.e. by default, `"debug"` logs will be swallowed.
If the default handler is not invoked, the log will not be printed to the console. Moreover, you can change the log level by invoking the default handler with a different level. Using the additional level `"error"` will turn the log into a thrown error that has all properties of the log attached.
#### Parameters
##### level
`"info"` | `"debug"` | `"warn"`
##### log
[`RolldownLog`](Interface.RolldownLog.md)
##### defaultHandler
[`LogOrStringHandler`](TypeAlias.LogOrStringHandler.md)
#### Returns
`void`
#### Example
```js
export default defineConfig({
onLog(level, log, defaultHandler) {
if (log.code === 'CIRCULAR_DEPENDENCY') {
return; // Ignore circular dependency warnings
}
if (level === 'warn') {
defaultHandler('error', log); // turn other warnings into errors
} else {
defaultHandler(level, log); // otherwise, just print the log
}
}
})
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`onLog`](Interface.InputOptions.md#onlog)
***
### ~~onwarn?~~
* **Type**: (`warning`, `defaultHandler`) => `void`
* **Optional**
A function that will intercept warning messages.
If the default handler is invoked, the log will be handled as a warning. If both an `onLog` and `onwarn` handler are provided, the `onwarn` handler will only be invoked if `onLog` calls its default handler with a `level` of `"warn"`.
#### Parameters
##### warning
[`RolldownLog`](Interface.RolldownLog.md)
##### defaultHandler
(`warning`) => `void`
#### Returns
`void`
#### Deprecated
This is a legacy API. Consider using [`onLog`](Interface.InputOptions.md#onlog) instead for better control over all log types.
To migrate from `onwarn` to `onLog`, check the `level` parameter to filter for warnings:
```js
// Before: Using `onwarn`
export default {
onwarn(warning, defaultHandler) {
// Suppress certain warnings
if (warning.code === 'CIRCULAR_DEPENDENCY') return;
// Handle other warnings with default behavior
defaultHandler(warning);
},
};
```
```js
// After: Using `onLog`
export default {
onLog(level, log, defaultHandler) {
// Handle only warnings (same behavior as `onwarn`)
if (level === 'warn') {
// Suppress certain warnings
if (log.code === 'CIRCULAR_DEPENDENCY') return;
// Handle other warnings with default behavior
defaultHandler(level, log);
} else {
// Let other log levels pass through
defaultHandler(level, log);
}
},
};
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`onwarn`](Interface.InputOptions.md#onwarn)
***
### optimization?
* **Type**: [`OptimizationOptions`](TypeAlias.OptimizationOptions.md)
* **Optional**
Configure optimization features for the bundler.
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`optimization`](Interface.InputOptions.md#optimization)
***
### output?
* **Type**: [`OutputOptions`](Interface.OutputOptions.md) | [`OutputOptions`](Interface.OutputOptions.md)\[]
* **Optional**
***
### platform?
* **Type**: `"node"` | `"browser"` | `"neutral"`
* **Optional**
Expected platform where the code run.
When the platform is set to neutral:
* When bundling is enabled the default output format is set to esm, which uses the export syntax introduced with ECMAScript 2015 (i.e. ES6). You can change the output format if this default is not appropriate.
* The main fields setting is empty by default. If you want to use npm-style packages, you will likely have to configure this to be something else such as main for the standard main field used by node.
* The conditions setting does not automatically include any platform-specific values.
#### Default
* `'node'` if the format is `'cjs'`
* `'browser'` for other formats
#### Examples
##### Browser platform
```js
export default {
platform: 'browser',
output: {
format: 'esm',
},
};
```
##### Node.js platform
```js
export default {
platform: 'node',
output: {
format: 'cjs',
},
};
```
##### Platform-neutral
```js
export default {
platform: 'neutral',
output: {
format: 'esm',
},
};
```
#### In-depth
The platform setting provides sensible defaults for module resolution and environment-specific behavior, similar to esbuild's `platform` option.
##### `'node'`
Optimized for Node.js environments:
* **Conditions**: Includes `'node'`, `'import'`, `'require'` based on output format
* **Main fields**: `['main', 'module']`
* **Target**: Node.js runtime behavior
* **process.env handling**: Preserves `process.env.NODE_ENV` and other Node.js globals
##### `'browser'`
Optimized for browser environments:
* **Conditions**: Includes `'browser'`, `'import'`, `'module'`, `'default'`
* **Main fields**: `['browser', 'module', 'main']` - prefers browser-specific entry points
* **Target**: Browser runtime behavior
* **Built-ins**: Node.js built-in modules are not polyfilled by default
:::tip
For browser builds, you may want to use [rolldown-plugin-node-polyfills](https://github.com/rolldown/rolldown-plugin-node-polyfills) to polyfill Node.js built-ins if needed.
:::
##### `'neutral'`
Platform-agnostic configuration:
* **Default format**: Always `'esm'`
* **Conditions**: Only includes format-specific conditions, no platform-specific ones
* **Main fields**: Empty by default - relies on package.json `"exports"` field
* **Use cases**: Universal libraries that run in multiple environments
##### Difference from esbuild
Notable differences from esbuild's `platform` option:
* The default output format is always `'esm'` regardless of platform (in esbuild, Node.js defaults to `'cjs'`)
##### Choosing a Platform
**Use `'browser'`** when:
* Building for web applications
* Targeting modern browsers with ES modules support
* Need browser-specific package entry points
**Use `'node'`** when:
* Building server-side applications
* Creating CLI tools
* Need Node.js-specific features and modules
**Use `'neutral'`** when:
* Building universal libraries
* Want maximum portability
* Avoiding platform-specific assumptions
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`platform`](Interface.InputOptions.md#platform)
***
### plugins?
* **Type**: [`RolldownPluginOption`](TypeAlias.RolldownPluginOption.md)
* **Optional**
The list of plugins to use.
Falsy plugins will be ignored, which can be used to easily activate or deactivate plugins. Nested plugins will be flattened. Async plugins will be awaited and resolved.
See [Plugin API document](/apis/plugin-api) for more details about creating plugins.
#### Example
```js
import { defineConfig } from 'rolldown'
export default defineConfig({
plugins: [
examplePlugin1(),
// Conditional plugins
process.env.ENV1 && examplePlugin2(),
// Nested plugins arrays are flattened
[examplePlugin3(), examplePlugin4()],
]
})
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`plugins`](Interface.InputOptions.md#plugins)
***
### preserveEntrySignatures?
* **Type**: `false` | `"strict"` | `"allow-extension"` | `"exports-only"`
* **Optional**
Controls how entry chunk exports are preserved.
This determines whether Rolldown needs to create facade chunks (additional wrapper chunks) to maintain the exact export signatures of entry modules, or whether it can combine entry modules with other chunks for optimization.
#### Default
`'exports-only'`
#### Values
##### `'exports-only'`
Follows `'strict'` behavior for entry modules that have exports, but allows `'allow-extension'` behavior for entry modules without exports.
##### `'strict'`
Entry chunks will exactly match the exports of their corresponding entry modules. If additional internal bindings need to be exposed (for example, when modules are shared between chunks), Rolldown will create facade chunks to maintain the exact export signature.
**Use case:** This is the recommended setting for **libraries** where you need guaranteed, stable export signatures.
##### `'allow-extension'`
Entry chunks can expose all exports from the corresponding entry module, and may also include additional exports from other modules if they're bundled together. This allows more optimization opportunities but may expose internal implementation details.
##### `false`
Provides maximum flexibility. Entry chunks can be merged freely with other chunks regardless of export signatures. This can lead to better optimization but may change the exposed exports significantly.
**Use case:** This is the recommended setting for **application** where you don't need guaranteed, stable export signatures.
#### Understanding Facade Chunks
A facade chunk is a small wrapper chunk that Rolldown creates to preserve the exact export signature of an entry module when the actual implementation has been bundled into another chunk.
**Example scenario:**
If you have two entry points that share code, and `preserveEntrySignatures` is set to `'strict'`, Rolldown might:
1. Bundle the shared code into a common chunk
2. Create facade chunks for each entry point that re-export from the common chunk
3. This ensures each entry point maintains its exact original export signature
#### In-depth
##### Override per Entry Point
The `preserveEntrySignatures` option is a global setting. The only way to override it for individual entry chunks is to use the plugin API and emit those chunks via [`this.emitFile`](/reference/Interface.PluginContext#emitfile) instead of using the [`input`](/reference/InputOptions.input) option.
###### Practical Example: Mixed Library and Application Build
```js
// rolldown.config.js
export default {
preserveEntrySignatures: 'exports-only', // Default for most entries
plugins: [
{
name: 'custom-entries',
buildStart() {
// Library entry that needs strict signature preservation
this.emitFile({
type: 'chunk',
id: 'src/library/index.js',
fileName: 'library.js',
preserveEntrySignature: 'strict',
});
// Application entry that can be optimized
this.emitFile({
type: 'chunk',
id: 'src/app/main.js',
fileName: 'app.js',
preserveEntrySignature: false,
});
},
},
],
};
```
When using `this.emitFile` with type `'chunk'`, you can specify:
* **`preserveEntrySignature`**: Override the global setting
* `false`: Maximum optimization, merge chunks freely
* `'strict'`: Exact export signature preservation
* `'allow-extension'`: Allow additional exports from merged chunks
* `'exports-only'`: Strict only for modules with exports
* **`fileName`**: Custom output filename for the entry chunk
* **`id`**: Module ID or path to use as the entry point
##### When to Use Each Setting
* **`'strict'`**: Building libraries, need guaranteed export signatures
* **`'exports-only'`**: Most applications, balanced approach (default)
* **`'allow-extension'`**: Advanced optimizations, okay with exposing extra exports
* **`false`**: Maximum bundle size reduction, export signatures don't matter
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`preserveEntrySignatures`](Interface.InputOptions.md#preserveentrysignatures)
***
### resolve?
* **Type**: object with the properties below
* **Optional**
Options for built-in module resolution feature.
#### alias?
* **Type**: `Record`<`string`, `string` | `false` | `string`\[]>
* **Optional**
Substitute one package for another.
One use case for this feature is replacing a node-only package with a browser-friendly package in third-party code that you don't control.
##### Example
```js
resolve: {
alias: {
'@': '/src',
'utils': './src/utils',
}
}
```
> \[!WARNING]
> `resolve.alias` will not call [`resolveId`](/reference/Interface.Plugin#resolveid) hooks of other plugin.
> If you want to call `resolveId` hooks of other plugin, use `viteAliasPlugin` from `rolldown/experimental` instead.
> You could find more discussion in [this issue](https://github.com/rolldown/rolldown/issues/3615)
#### aliasFields?
* **Type**: `string`\[]\[]
* **Optional**
Fields in package.json to check for aliased paths.
This option is expected to be used for `browser` field support.
##### Default
* `[['browser']]` for `browser` platform
* `[]` for other platforms
#### conditionNames?
* **Type**: `string`\[]
* **Optional**
Condition names to use when resolving exports in package.json.
##### Default
Defaults based on platform and import kind:
* `browser` platform
* `["import", "browser", "default"]` for import statements
* `["require", "browser", "default"]` for require() calls
* `node` platform
* `["import", "node", "default"]` for import statements
* `["require", "node", "default"]` for require() calls
* `neutral` platform
* `["import", "default"]` for import statements
* `["require", "default"]` for require() calls
#### exportsFields?
* **Type**: `string`\[]\[]
* **Optional**
Fields in package.json to check for exports.
##### Default
`[['exports']]`
#### extensionAlias?
* **Type**: `Record`<`string`, `string`\[]>
* **Optional**
Map of extensions to alternative extensions.
With writing `import './foo.js'` in a file, you want to resolve it to `foo.ts` instead of `foo.js`.
You can achieve this by setting: `extensionAlias: { '.js': ['.ts', '.js'] }`.
#### extensions?
* **Type**: `string`\[]
* **Optional**
Extensions to try when resolving files. These are tried in order from first to last.
##### Default
`['.tsx', '.ts', '.jsx', '.js', '.json']`
#### mainFields?
* **Type**: `string`\[]
* **Optional**
Fields in package.json to check for entry points.
##### Default
Defaults based on platform:
* `node` platform: `['main', 'module']`
* `browser` platform: `['browser', 'module', 'main']`
* `neutral` platform: `[]`
#### mainFiles?
* **Type**: `string`\[]
* **Optional**
Filenames to try when resolving directories.
##### Default
```ts
['index']
```
#### modules?
* **Type**: `string`\[]
* **Optional**
Directories to search for modules.
##### Default
```ts
['node_modules']
```
#### symlinks?
* **Type**: `boolean`
* **Optional**
Whether to follow symlinks when resolving modules.
##### Default
```ts
true
```
#### ~~tsconfigFilename?~~
* **Type**: `string`
* **Optional**
##### Deprecated
Use the top-level [`tsconfig`](Interface.InputOptions.md#tsconfig) option instead.
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`resolve`](Interface.InputOptions.md#resolve)
***
### shimMissingExports?
* **Type**: `boolean`
* **Optional**
When `true`, creates shim variables for missing exports instead of throwing an error.
#### Default
false
#### Examples
##### Enable shimming
```js
export default {
shimMissingExports: true,
};
```
##### Example scenario
**module-a.js:**
```js
export { nonExistent } from './module-b.js';
```
**module-b.js:**
```js
// nonExistent is not actually exported here
export const something = 'value';
```
With `shimMissingExports: false` (default), this would throw an error. With `shimMissingExports: true`, Rolldown will create a shim variable:
```js
// Bundled output (simplified)
const nonExistent = undefined;
export { nonExistent, something };
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`shimMissingExports`](Interface.InputOptions.md#shimmissingexports)
***
### transform?
* **Type**: [`TransformOptions`](Interface.TransformOptions.md)
* **Optional**
Configure how the code is transformed. This process happens after the `transform` hook.
#### Example
**Enable legacy decorators**
```js
export default defineConfig({
transform: {
decorator: {
legacy: true,
},
},
})
```
Note that if you have correct `tsconfig.json` file, Rolldown will automatically detect and enable legacy decorators support.
#### In-depth
Rolldown uses Oxc under the hood for transformation.
While Oxc does not support lowering the latest decorators proposal yet, Rolldown is able to bundle them.
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`transform`](Interface.InputOptions.md#transform)
***
### treeshake?
* **Type**: `boolean` | [`TreeshakingOptions`](TypeAlias.TreeshakingOptions.md)
* **Optional**
Controls tree-shaking (dead code elimination).
See the [In-depth Dead Code Elimination Guide](/in-depth/dead-code-elimination) for more details.
When `false`, tree-shaking will be disabled.
When `true`, it is equivalent to setting each options to the default value.
#### Default
```ts
true
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`treeshake`](Interface.InputOptions.md#treeshake)
***
### tsconfig?
* **Type**: `string` | `boolean`
* **Optional**
Configures TypeScript configuration file resolution and usage.
#### Options
##### Auto-discovery mode (`true`)
When set to `true`, Rolldown enables auto-discovery mode. For each module, both the resolver and transformer search **upward** from the module's directory, starting at the nearest `tsconfig.json`. If it has `references`, Rolldown checks each referenced project's `files`/`include`/`exclude` and uses the first one that matches the file. If no reference matches, it checks the `tsconfig.json`'s own `files`/`include`/`exclude`. If the file matches neither, Rolldown continues upward to the next `tsconfig.json` and repeats. If no `tsconfig.json` matches the file, no config is applied (no `paths`/`baseUrl`), the same as TypeScript.
Whether an `include` glob matches a file depends on its extension: by default only TypeScript files (`.ts`/`.tsx`/`.mts`/`.cts`) match, plus `.js`/`.jsx`/`.mjs`/`.cjs` when `allowJs` is enabled. A glob that names an explicit extension (for example `src/**/*.vue`) matches that extension verbatim, so a non-TS file can pick up the project's `paths`/`baseUrl`. (`files` lists exact paths and matches them regardless of extension or `allowJs`)
If the tsconfig has `references`, Rolldown resolves them the way TypeScript does: a referenced project that includes the file **takes precedence over the root**, and the first matching reference wins. Each referenced project matches with its own `compilerOptions` (such as `allowJs`). If no referenced project includes the file, Rolldown falls back to the root's own `files`/`include`/`exclude`. A solution-style root (only `references` with an explicit empty `files`/`include`, as Vite scaffolds) has no file patterns of its own, so once none of its references match either, it does **not** own the file, and discovery continues in the parent directories as described above.
```js
export default {
tsconfig: true,
};
```
##### Explicit path (`string`)
Specifies the path to a specific TypeScript configuration file. You may provide a relative path (resolved relative to `cwd`) or an absolute path.
If the tsconfig has `references`, this mode behaves like auto-discovery mode for reference resolution.
```js
export default {
tsconfig: './tsconfig.json',
};
```
```js
export default {
tsconfig: '/absolute/path/to/tsconfig.json',
};
```
:::tip
Rolldown respects `references` and `include`/`exclude` patterns in tsconfig, while esbuild does not. If you need esbuild-compatible behavior, specify a tsconfig without `references`. You can use [`extends`](https://www.typescriptlang.org/tsconfig/#extends) to share the options between the two.
:::
#### What's used from tsconfig
When a tsconfig is resolved, Rolldown uses different parts for different purposes:
##### Resolver
Uses the following for module path mapping:
* `compilerOptions.paths`: Path mapping for module resolution
* `compilerOptions.baseUrl`: Base directory for path resolution
##### Transformer
Uses select compiler options including:
* `jsx`: JSX transformation mode
* `experimentalDecorators`: Enable decorator support
* `emitDecoratorMetadata`: Emit decorator metadata
* `strictNullChecks` (falling back to `strict`): Controls whether `null`/`undefined` are elided from nullable-union `design:type` decorator metadata, and only applies when `emitDecoratorMetadata` is enabled. When neither is set it defaults to enabled, matching TypeScript 6.0+ (where `strict` is on by default)
* `verbatimModuleSyntax`: Module syntax preservation
* `useDefineForClassFields`: Class field semantics
* And other TypeScript-specific options
##### Example
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"]
}
}
}
```
With this configuration:
* JSX will use React's automatic runtime
* Path aliases like `@/utils` will resolve to `src/utils`
#### Priority
Top-level `transform` options always take precedence over tsconfig settings:
```js
export default {
tsconfig: './tsconfig.json', // Has jsx: 'react-jsx'
transform: {
jsx: {
mode: 'classic', // This takes precedence
},
},
};
```
:::tip
For TypeScript projects, it's recommended to use `tsconfig: true` for auto-discovery or specify an explicit path to ensure consistent compilation behavior and enable path mapping.
:::
#### Default
```ts
true
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`tsconfig`](Interface.InputOptions.md#tsconfig)
***
### watch?
* **Type**: `false` | [`WatcherOptions`](Interface.WatcherOptions.md)
* **Optional**
* **Experimental**
Watch mode related options.
These options only take effect when running with the [`--watch`](/apis/cli#w-watch) flag, or using [`watch()`](Function.watch.md) API.
Rolldown uses the following APIs to watch for changes by default:
* Linux, Android: `inotify`
* macOS: `FSEvents`
* Windows: `ReadDirectoryChangesW`
* BSD descendants (e.g. FreeBSD): `kqueue`
* Other: None (polling)
There are some limitations for each API. If you need to work around them, you can use [`watcher.usePolling`](/reference/Interface.WatcherFileWatcherOptions#usepolling) to force Rolldown to use polling instead of the native API.
::: warning Using on Windows Subsystem for Linux (WSL) 2
When running Rolldown on WSL2, file system watching does not work when a file is edited by Windows applications (non-WSL2 process). This is due to [a WSL2 limitation](https://github.com/microsoft/WSL/issues/4739). This also applies to running on Docker with a WSL2 backend.
To fix it, you could either:
* **Recommended**: Use WSL2 applications to edit your files.
* It is also recommended to move the project folder outside of a Windows filesystem. Accessing Windows filesystem from WSL2 is slow. Removing that overhead will improve performance.
* Set [`usePolling: true`](/reference/Interface.WatcherFileWatcherOptions#usepolling).
* Note that `usePolling` leads to higher CPU utilization.
:::
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`watch`](Interface.InputOptions.md#watch)
---
---
url: /reference/Interface.Plugin.md
---
# Interface: Plugin\
The Plugin interface.
See [Plugin API document](/apis/plugin-api) for details.
## Extends
* `OutputPlugin`.`Partial`<`PluginHooks`>
## Type Parameters
### A
`A` = `any`
The type of the [api](#api) property.
## Properties
### api?
* **Type**: `A`
* **Optional**
Used for inter-plugin communication.
***
### meta?
* **Type**: [`PluginMeta`](Interface.PluginMeta.md)
* **Optional**
* **Experimental**
Descriptive metadata about the plugin, such as the npm package it ships in.
This does not affect bundling; it is informational and intended to be
surfaced by tooling that inspects a build. See [`PluginMeta`](Interface.PluginMeta.md).
#### Inherited from
`OutputPlugin.meta`
***
### name
* **Type**: `string`
The name of the plugin, for use in error messages and logs.
#### Inherited from
`OutputPlugin.name`
***
### version?
* **Type**: `string`
* **Optional**
The version of the plugin, for use in inter-plugin communication scenarios.
#### Inherited from
`OutputPlugin.version`
## Build Hooks
### buildEnd?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => `void` | `Promise`<`void`>, { `sequential?`: `boolean`; }>
* **Kind**: `async`, `parallel`
* **Optional**
Called when Rolldown has finished bundling, but before Output Generation Hooks.
If an error occurred during the build, it is passed on to this hook.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`buildEnd`](Interface.FunctionPluginHooks.md#buildend)
***
### buildStart?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => `void` | `Promise`<`void`>, { `sequential?`: `boolean`; }>
* **Kind**: `async`, `parallel`
* **Optional**
Called on each [`rolldown()`](Function.rolldown.md) build.
This is the recommended hook to use when you need access to the options passed to [`rolldown()`](Function.rolldown.md) as it takes the transformations by all options hooks into account and also contains the right default values for unset options.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`buildStart`](Interface.FunctionPluginHooks.md#buildstart)
***
### closeWatcher?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => `void` | `Promise`<`void`>, { `sequential?`: `boolean`; }>
* **Kind**: `async`, `parallel`
* **Optional**
Notifies a plugin when the watcher process will close so that all open resources can be closed too.
This hook cannot be used by output plugins.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`closeWatcher`](Interface.FunctionPluginHooks.md#closewatcher)
***
### load?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => MaybePromise\ | Promise\>, { `filter?`: [`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md)\[] | `Pick`<[`HookFilter`](Interface.HookFilter.md), `"id"`>; }>
* **Kind**: `async`, `first`
* **Optional**
Defines a custom loader.
Returning `null` defers to other `load` hooks or the built-in loading mechanism.
You can use [`this.getModuleInfo()`](Interface.PluginContext.md#getmoduleinfo) to find out the previous values of `meta`, `moduleSideEffects` inside this hook.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`load`](Interface.FunctionPluginHooks.md#load)
***
### moduleParsed?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => `void` | `Promise`<`void`>, { `sequential?`: `boolean`; }>
* **Kind**: `async`, `parallel`
* **Optional**
This hook is called each time a module has been fully parsed by Rolldown.
This hook will wait until all imports are resolved so that the information in
[`moduleInfo.importedIds`](Interface.ModuleInfo.md#importedids),
[`moduleInfo.dynamicallyImportedIds`](Interface.ModuleInfo.md#dynamicallyimportedids)
are complete and accurate. Note however that information about importing modules
may be incomplete as additional importers could be discovered later.
If you need this information, use the [`buildEnd`](Interface.FunctionPluginHooks.md#buildend) hook.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`moduleParsed`](Interface.FunctionPluginHooks.md#moduleparsed)
***
### onLog?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, `level`, `log`) => boolean | NullValue, { }>
* **Kind**: `sync`, `sequential`
* **Optional**
A function that receives and filters logs and warnings generated by Rolldown and
plugins before they are passed to the [`onLog`](Interface.InputOptions.md#onlog) option
or printed to the console.
If `false` is returned, the log will be filtered out.
Otherwise, the log will be handed to the `onLog` hook of the next plugin,
the [`onLog`](Interface.InputOptions.md#onlog) option, or printed to the console.
Plugins can also change the log level of a log or turn a log into an error by passing
the `log` object to [`this.error`](Interface.MinimalPluginContext.md#error),
[`this.warn`](Interface.MinimalPluginContext.md#warn),
[`this.info`](Interface.MinimalPluginContext.md#info) or
[`this.debug`](Interface.MinimalPluginContext.md#debug) and returning `false`.
Note that unlike other plugin hooks that add e.g. the plugin name to the log, those functions will not add or change properties of the log. Additionally, logs generated by an `onLog` hook will not be passed back to
the `onLog` hook of the same plugin. If another plugin generates a log in response to such a log in its own `onLog` hook, this log will not be passed to the original `onLog` hook, either.
#### Example
```js
function plugin1() {
return {
name: 'plugin1',
buildStart() {
this.info({ message: 'Hey', pluginCode: 'SPECIAL_CODE' });
},
onLog(level, log) {
if (log.plugin === 'plugin1' && log.pluginCode === 'SPECIAL_CODE') {
// We turn logs into warnings based on their code. This warnings
// will not be passed back to the same plugin to avoid an
// infinite loop, but other plugins will still receive it.
this.warn(log);
return false;
}
},
};
}
function plugin2() {
return {
name: 'plugin2',
onLog(level, log) {
if (log.plugin === 'plugin1' && log.pluginCode === 'SPECIAL_CODE') {
// You can modify logs in this hooks as well
log.meta = 'processed by plugin 2';
// This turns the log back to "info". If this happens in
// response to the first plugin, it will not be passed back to
// either plugin to avoid an infinite loop. If both plugins are
// active, the log will be an info log if the second plugin is
// placed after the first one
this.info(log);
return false;
}
},
};
}
```
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`onLog`](Interface.FunctionPluginHooks.md#onlog)
***
### options?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => NullValue | InputOptions | Promise\, { }>
* **Kind**: `async`, `sequential`
* **Optional**
Replaces or manipulates the options object passed to [`rolldown()`](Function.rolldown.md).
Returning `null` does not replace anything.
If you just need to read the options, it is recommended to use
the [`buildStart`](Interface.FunctionPluginHooks.md#buildstart) hook as that hook has access to the options
after the transformations from all `options` hooks have been taken into account.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`options`](Interface.FunctionPluginHooks.md#options)
***
### outputOptions?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, `options`) => OutputOptions | NullValue, { }>
* **Kind**: `sync`, `sequential`
* **Optional**
Replaces or manipulates the output options object passed to
[`bundle.generate()`](Interface.RolldownBuild.md#generate) or
[`bundle.write()`](Interface.RolldownBuild.md#write).
Returning null does not replace anything.
If you just need to read the output options, it is recommended to use
the [`renderStart`](Interface.FunctionPluginHooks.md#renderstart) hook as this hook has access to the output options
after the transformations from all `outputOptions` hooks have been taken into account.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`outputOptions`](Interface.FunctionPluginHooks.md#outputoptions)
***
### ~~resolveDynamicImport?~~
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => ResolveIdResult | Promise\, { }>
* **Kind**: `async`, `first`
* **Optional**
Defines a custom resolver for dynamic imports.
#### Deprecated
This hook exists only for Rollup compatibility. Please use [`resolveId`](Interface.FunctionPluginHooks.md#resolveid) instead.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`resolveDynamicImport`](Interface.FunctionPluginHooks.md#resolvedynamicimport)
***
### resolveId?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => ResolveIdResult | Promise\, { `filter?`: [`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md)\[] | { `id?`: GeneralHookFilter\ | undefined; }; }>
* **Kind**: `async`, `first`
* **Optional**
Defines a custom resolver.
A resolver can be useful for e.g. locating third-party dependencies.
Returning `null` defers to other `resolveId` hooks and eventually the default resolution behavior.
Returning `false` signals that `source` should be treated as an external module and not included in the bundle. If this happens for a relative import, the id will be renormalized the same way as when the [`InputOptions.external`](Interface.InputOptions.md#external) option is used.
If you return an object, then it is possible to resolve an import to a different id while excluding it from the bundle at the same time.
Note that while `resolveId` will be called for each import of a module and can therefore
resolve to the same `id` many times, values for `external`, `meta` or `moduleSideEffects`
can only be set once before the module is loaded. The reason is that after this call,
Rolldown will continue with the [`load`](Interface.FunctionPluginHooks.md#load) and [`transform`](Interface.FunctionPluginHooks.md#transform) hooks for that
module that may override these values and should take precedence if they do so.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`resolveId`](Interface.FunctionPluginHooks.md#resolveid)
***
### transform?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => TransformResult | Promise\, { `filter?`: [`HookFilter`](Interface.HookFilter.md) | [`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md)\[]; }>
* **Kind**: `async`, `sequential`
* **Optional**
Can be used to transform individual modules.
Note that it's possible to return only properties and no code transformations.
You can use [`this.getModuleInfo()`](Interface.PluginContext.md#getmoduleinfo) to find out the previous values of `meta`, `moduleSideEffects` inside this hook.
::: warning Changing `moduleType`
When you change the [type of the module](/in-depth/module-types) by returning [`moduleType`](/reference/Interface.SourceDescription#moduletype) property, the module is not thrown back to the beginning of the plugin chain. This means the `transform` hooks of the plugins that already saw this module will not be called with the new `moduleType`. For this reason, it is recommended to place the plugins that change the `moduleType` at the beginning of the plugin list.
If you need to let all the plugins be called, you can create a [virtual module](/apis/plugin-api#virtual-modules) with a different `moduleType` instead of changing the `moduleType` directly in the `transform` hook.
:::
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`transform`](Interface.FunctionPluginHooks.md#transform)
***
### watchChange?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => `void` | `Promise`<`void`>, { `sequential?`: `boolean`; }>
* **Kind**: `async`, `parallel`
* **Optional**
Notifies a plugin whenever Rolldown has detected a change to a monitored file in watch mode.
If a build is currently running, this hook is called once the build finished.
It will be called once for every file that changed.
This hook cannot be used by output plugins.
If you need to be notified immediately when a file changed, you can use the [`watch.onInvalidate`](Interface.WatcherOptions.md#oninvalidate) option.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`watchChange`](Interface.FunctionPluginHooks.md#watchchange)
## Output Generation Hooks
### augmentChunkHash?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, `chunk`) => `string` | `void`, { }>
* **Kind**: `sync`, `sequential`
* **Optional**
Can be used to augment the hash of individual chunks. Called for each Rolldown output chunk.
Returning a falsy value will not modify the hash.
Truthy values will be used as an additional source for hash calculation.
#### Example
The following plugin will invalidate the hash of chunk foo with the current timestamp:
```js
function augmentWithDatePlugin() {
return {
name: 'augment-with-date',
augmentChunkHash(chunkInfo) {
if (chunkInfo.name === 'foo') {
return Date.now().toString();
}
},
};
}
```
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`augmentChunkHash`](Interface.FunctionPluginHooks.md#augmentchunkhash)
***
### banner?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<`AddonHook`, { }>
* **Kind**: `async`, `sequential`
* **Optional**
A hook equivalent to [`output.banner`](Interface.OutputOptions.md#banner) option.
#### Inherited from
`OutputPlugin.banner`
***
### closeBundle?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => `void` | `Promise`<`void`>, { `sequential?`: `boolean`; }>
* **Kind**: `async`, `parallel`
* **Optional**
Can be used to clean up any external service that may be running.
Rolldown's CLI will make sure this hook is called after each run, but it is the responsibility
of users of the JavaScript API to manually call
[`bundle.close()`](Interface.RolldownBuild.md#close) once they are done generating bundles.
For that reason, any plugin relying on this feature should carefully mention this in
its documentation.
If a plugin wants to retain resources across builds in watch mode, they can check for
[`this.meta.watchMode`](Interface.PluginContextMeta.md#watchmode) in this hook and perform
the necessary cleanup for watch mode in closeWatcher.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`closeBundle`](Interface.FunctionPluginHooks.md#closebundle)
***
### footer?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<`AddonHook`, { }>
* **Kind**: `async`, `sequential`
* **Optional**
A hook equivalent to [`output.footer`](Interface.OutputOptions.md#footer) option.
#### Inherited from
`OutputPlugin.footer`
***
### generateBundle?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => `void` | `Promise`<`void`>, { }>
* **Kind**: `async`, `sequential`
* **Optional**
Called at the end of [`bundle.generate()`](Interface.RolldownBuild.md#generate) or
immediately before the files are written in
[`bundle.write()`](Interface.RolldownBuild.md#write).
To modify the files after they have been written, use the [`writeBundle`](Interface.FunctionPluginHooks.md#writebundle) hook.
You can prevent files from being emitted by deleting them from the bundle object in this hook. To emit additional files, use the [`this.emitFile`](/reference/Interface.PluginContext#emitfile) function.
::: danger
Do not directly add assets to the bundle. This will not work as expected as Rolldown will ignore those assets. This is [not recommended in Rollup](https://rollupjs.org/plugin-development/#generatebundle) as well.
Instead, always use [`this.emitFile`](/reference/Interface.PluginContext#emitfile).
:::
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`generateBundle`](Interface.FunctionPluginHooks.md#generatebundle)
***
### intro?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<`AddonHook`, { }>
* **Kind**: `async`, `sequential`
* **Optional**
A hook equivalent to [`output.intro`](Interface.OutputOptions.md#intro) option.
#### Inherited from
`OutputPlugin.intro`
***
### outro?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<`AddonHook`, { }>
* **Kind**: `async`, `sequential`
* **Optional**
A hook equivalent to [`output.outro`](Interface.OutputOptions.md#outro) option.
#### Inherited from
`OutputPlugin.outro`
***
### renderChunk?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => string | RolldownMagicString | NullValue | { code: string | RolldownMagicString; map?: SourceMapInput | undefined; } | Promise<...>, { `filter?`: [`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md)\[] | `Pick`<[`HookFilter`](Interface.HookFilter.md), `"code"`>; }>
* **Kind**: `async`, `sequential`
* **Optional**
Can be used to transform individual chunks. Called for each Rolldown output chunk file.
Returning null will apply no transformations. If you change code in this hook and want to support source maps, you need to return a map describing your changes, see [Source Code Transformations section](/apis/plugin-api/transformations#source-code-transformations).
`chunk` is mutable and changes applied in this hook will propagate to other plugins and
to the generated bundle.
That means if you add or remove imports or exports in this hook, you should update
[`imports`](Interface.RenderedChunk.md#imports), RenderedChunk.importedBindings | importedBindings and/or [`exports`](Interface.RenderedChunk.md#exports) accordingly.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`renderChunk`](Interface.FunctionPluginHooks.md#renderchunk)
***
### renderError?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => `void` | `Promise`<`void`>, { `sequential?`: `boolean`; }>
* **Kind**: `async`, `parallel`
* **Optional**
Called when Rolldown encounters an error during
[`bundle.generate()`](Interface.RolldownBuild.md#generate) or
[`bundle.write()`](Interface.RolldownBuild.md#write).
To get notified when generation completes successfully, use the
[`generateBundle`](Interface.FunctionPluginHooks.md#generatebundle) hook.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`renderError`](Interface.FunctionPluginHooks.md#rendererror)
***
### renderStart?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => `void` | `Promise`<`void`>, { `sequential?`: `boolean`; }>
* **Kind**: `async`, `parallel`
* **Optional**
Called initially each time [`bundle.generate()`](Interface.RolldownBuild.md#generate) or
[`bundle.write()`](Interface.RolldownBuild.md#write) is called.
To get notified when generation has completed, use the [`generateBundle`](Interface.FunctionPluginHooks.md#generatebundle) and
[`renderError`](Interface.FunctionPluginHooks.md#rendererror) hooks.
This is the recommended hook to use when you need access to the output options passed to
[`bundle.generate()`](Interface.RolldownBuild.md#generate) or
[`bundle.write()`](Interface.RolldownBuild.md#write) as it takes the transformations by all outputOptions hooks into account and also contains the right default values for unset options.
It also receives the input options passed to [`rolldown()`](Function.rolldown.md) so that
plugins that can be used as output plugins, i.e. plugins that only use generate phase hooks,
can get access to them.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`renderStart`](Interface.FunctionPluginHooks.md#renderstart)
***
### resolveFileUrl?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, `args`) => string | NullValue, { }>
* **Optional**
Allows customizing how Rolldown resolves URLs of files that were emitted by plugins via [`this.emitFile`](/reference/Interface.PluginContext#emitfile). By default, Rolldown will generate code for `import.meta.ROLLDOWN_FILE_URL_referenceId` that resolves the emitted file relative to `import.meta.url`. This generates correct absolute URLs for the `esm` format, and for the `cjs` format on the `node` platform where `import.meta.url` is [polyfilled](/in-depth/non-esm-output-formats#well-known-import-meta-properties). For the `iife` and `umd` formats, `import.meta.url` is not available and the generated code will not work — Rolldown emits a warning in that case. To support these formats, this hook needs to be implemented to return code that does not rely on `import.meta.url`. See [File URLs](/apis/plugin-api/file-urls) for more details and an example.
This hook can be used to customize the behavior of `import.meta.ROLLDOWN_FILE_URL_referenceId`.
The returned string must be a single JavaScript expression. Also the returned expression must be side-effect free. If the URL is not used in the code, Rolldown will remove it.
Rolldown additionally accepts `import.meta.ROLLDOWN_FILE_URL_referenceId_urlId`, where `urlId` is an arbitrary identifier of your choosing. It is passed to this hook as `args.urlId`, letting a single plugin resolve the same emitted file differently depending on the reference. The `urlId` API is experimental and may change in minor versions. The `urlId` is not available on the Rollup-compatible `ROLLUP_FILE_URL_` alias. Use only ASCII identifier characters in a `urlId`: letters, digits, `_`, and `$`.
::: tip `import.meta.url` in the returned string
If the returned string contains `import.meta.url`, it will be rewritten for non-ESM formats similarly to [when `import.meta.url` is used in the code directly](/in-depth/non-esm-output-formats#well-known-import-meta-properties). Unlike Rolldown, Rollup outputs `import.meta.url` as-is.
:::
#### Example
The following plugin will always resolve all files relative to the current document:
```js
function resolveToDocumentPlugin() {
return {
name: 'resolve-to-document',
resolveFileUrl({ fileName }) {
return `new URL(${JSON.stringify(fileName)}, document.baseURI).href`;
},
};
}
```
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`resolveFileUrl`](Interface.FunctionPluginHooks.md#resolvefileurl)
***
### writeBundle?
* **Type**: [`ObjectHook`](TypeAlias.ObjectHook.md)<(`this`, ...`parameters`) => `void` | `Promise`<`void`>, { `sequential?`: `boolean`; }>
* **Kind**: `async`, `parallel`
* **Optional**
Called only at the end of [`bundle.write()`](Interface.RolldownBuild.md#write) once
all files have been written.
#### Inherited from
[`FunctionPluginHooks`](Interface.FunctionPluginHooks.md).[`writeBundle`](Interface.FunctionPluginHooks.md#writebundle)
---
---
url: /reference/Interface.PluginContext.md
---
# Interface: PluginContext
## Extends
* [`MinimalPluginContext`](Interface.MinimalPluginContext.md)
## Extended by
* [`TransformPluginContext`](Interface.TransformPluginContext.md)
## Properties
### fs
* **Type**: [`RolldownFsModule`](Interface.RolldownFsModule.md)
Provides abstract access to the file system.
***
### meta
* **Type**: [`PluginContextMeta`](Interface.PluginContextMeta.md)
An object containing potentially useful metadata.
#### Inherited from
[`MinimalPluginContext`](Interface.MinimalPluginContext.md).[`meta`](Interface.MinimalPluginContext.md#meta)
## Methods
### getModuleInfo
* **Type**: (`moduleId`) => [`ModuleInfo`](Interface.ModuleInfo.md) | `null`
Get additional information about the module in question.
During the build, this object represents currently available information about the module which may be inaccurate before the [`buildEnd`](/reference/Interface.Plugin#buildend) hook:
* [`id`](/reference/Interface.ModuleInfo#id) will never change.
* [`code`](/reference/Interface.ModuleInfo#code), [`exports`](/reference/Interface.ModuleInfo#exports) are only available after parsing, i.e. in the [`moduleParsed`](/reference/Interface.Plugin#moduleparsed) hook or after awaiting [`this.load`](/reference/Interface.PluginContext#load). At that point, they will no longer change.
* [`isEntry`](/reference/Interface.ModuleInfo#isentry) is `true`, it will no longer change. It is however possible for modules to become entry points after they are parsed, either via [`this.emitFile`](/reference/Interface.PluginContext#emitfile) or because a plugin inspects a potential entry point via [`this.load`](/reference/Interface.PluginContext#load) in the [`resolveId`](/reference/Interface.Plugin#resolveid) hook when resolving an entry point. Therefore, it is not recommended relying on this flag in the [`transform`](/reference/Interface.Plugin#transform) hook. It will no longer change after [`buildEnd`](/reference/Interface.Plugin#buildend).
* [`importers`](/reference/Interface.ModuleInfo#importers) and [`dynamicImporters`](/reference/Interface.ModuleInfo#dynamicimporters) will start as empty arrays, which receive additional entries as new importers and are discovered. They will no longer change after [`buildEnd`](/reference/Interface.Plugin#buildend).
* [`importedIds`](/reference/Interface.ModuleInfo#importedids) and [`dynamicallyImportedIds`](/reference/Interface.ModuleInfo#dynamicallyimportedids) are available when a module has been parsed and its dependencies have been resolved. This is the case in the [`moduleParsed`](/reference/Interface.Plugin#moduleparsed) hook or after awaiting [`this.load`](/reference/Interface.PluginContext#load) with the `resolveDependencies` flag. At that point, they will no longer change.
* [`meta`](/reference/Interface.ModuleInfo#meta) and [`moduleSideEffects`](/reference/Interface.ModuleInfo#modulesideeffects) can be changed by [`load`](/reference/Interface.PluginContext#load) and [`transform`](/reference/Interface.Plugin#transform) hooks. Moreover, while most properties are read-only, these properties are writable and changes will be picked up if they occur before the [`buildEnd`](/reference/Interface.Plugin#buildend) hook is triggered. meta itself should not be overwritten, but it is ok to mutate its properties at any time to store meta information about a module. The advantage of doing this instead of keeping state in a plugin is that meta is persisted to and restored from the cache if it is used, e.g. when using watch mode from the CLI.
#### Parameters
##### moduleId
`string`
#### Returns
[`ModuleInfo`](Interface.ModuleInfo.md) | `null`
Module information for that module. `null` if the module could not be found.
***
### addWatchFile()
* **Type**: (`id`: `string`) => `void`
Adds additional files to be monitored in watch mode so that changes to these files will trigger rebuilds.
Note that when emitting assets that correspond to an existing file, it is recommended to set the [`originalFileName`](/reference/Interface.EmittedAsset#originalfilename) property in the [`this.emitFile`](/reference/Interface.PluginContext#emitfile) call instead as that will not only watch the file but also make the connection transparent to other plugins.
Note: Usually in watch mode to improve rebuild speed, the transform hook will only be triggered for a given module if its contents actually changed. Using `this.addWatchFile` from within the transform hook will make sure the transform hook is also reevaluated for this module if the watched file changes.
In general, it is recommended to use `this.addWatchFile` from within the hook that depends on the watched file.
#### Parameters
##### id
`string`
The path to be monitored.
This can be an absolute path to a file or directory or a path relative to the current working directory.
#### Returns
`void`
***
### emitFile()
* **Type**: (`file`: [`EmittedAsset`](Interface.EmittedAsset.md) | [`EmittedChunk`](Interface.EmittedChunk.md) | [`EmittedPrebuiltChunk`](Interface.EmittedPrebuiltChunk.md)) => `string`
Emits a new file that is included in the build output.
You can emit chunks, prebuilt chunks or assets.
#### In-depth (`type: 'chunk'`)
If the `type` is `'chunk'`, this emits a new chunk with the given module `id` as entry point. This will not result in duplicate modules in the graph, instead if necessary, existing chunks will be split or a facade chunk with reexports will be created. Chunks with a specified [`fileName`](/reference/Interface.EmittedChunk#filename) will always generate separate chunks while other emitted chunks may be deduplicated with existing chunks even if the name does not match. If such a chunk is not deduplicated, the [`output.chunkFileNames`](/reference/OutputOptions.chunkFileNames) pattern will be used.
You can reference the URL of an emitted file in any code returned by a [`load`](/reference/Interface.Plugin#load) or [`transform`](/reference/Interface.Plugin#transform) plugin hook via `import.meta.ROLLDOWN_FILE_URL_referenceId` (returns a string). See [File URLs](/apis/plugin-api/file-urls) for more details and an example.
You can use [`this.getFileName(referenceId)`](/reference/Interface.PluginContext#getfilename) to determine the file name as soon as it is available. If the file name is not set explicitly, then:
* asset file names are available starting with the [`renderStart`](/reference/Interface.Plugin#renderstart) hook. For assets that are emitted later, the file name will be available immediately after emitting the asset.
* chunk file names that do not contain a hash are available as soon as chunks are created after the [`renderStart`](/reference/Interface.Plugin#renderstart) hook.
* if a chunk file name would contain a hash, using [`getFileName`](/reference/Interface.PluginContext#getfilename) in any hook before [`generateBundle`](/reference/Interface.Plugin#generatebundle) will return a name containing a placeholder instead of the actual name. If you use this file name or parts of it in a chunk you transform in [`renderChunk`](/reference/Interface.Plugin#renderchunk), Rolldown will replace the placeholder with the actual hash before [`generateBundle`](/reference/Interface.Plugin#generatebundle), making sure the hash reflects the actual content of the final generated chunk including all referenced file hashes.
#### In-depth (`type: 'prebuilt-chunk'`)
If the `type` is `'prebuilt-chunk'`, this emits a chunk with fixed contents provided by the [`code`](/reference/Interface.EmittedPrebuiltChunk#code) property.
To reference a prebuilt chunk in imports, we need to mark the "module" as external in the [`resolveId`](/reference/Interface.Plugin#resolveid) hook as prebuilt chunks are not part of the module graph. Instead, they behave like assets with chunk meta-data:
```js
function emitPrebuiltChunkPlugin() {
return {
name: 'emit-prebuilt-chunk',
resolveId: {
filter: { id: /^\.\/my-prebuilt-chunk\.js$/ },
handler(source) {
return {
id: source,
external: true,
};
},
},
buildStart() {
this.emitFile({
type: 'prebuilt-chunk',
fileName: 'my-prebuilt-chunk.js',
code: 'export const foo = "foo"',
exports: ['foo'],
});
},
};
}
```
Then you can reference the prebuilt chunk in your code by `import { foo } from './my-prebuilt-chunk.js';`.
#### In-depth (`type: 'asset'`)
If the `type` is `'asset'`, this emits an arbitrary new file with the given source as content. Assets with a specified [`fileName`](/reference/Interface.EmittedAsset#filename) will always generate separate files while other emitted assets may be deduplicated with existing assets if they have the same source even if the name does not match. If an asset without a [`fileName`](/reference/Interface.EmittedAsset#filename) is not deduplicated, the [`output.assetFileNames`](/reference/OutputOptions.assetFileNames) pattern will be used.
#### Parameters
##### file
[`EmittedAsset`](Interface.EmittedAsset.md) | [`EmittedChunk`](Interface.EmittedChunk.md) | [`EmittedPrebuiltChunk`](Interface.EmittedPrebuiltChunk.md)
#### Returns
`string`
A `referenceId` for the emitted file that can be used in various places to reference the emitted file.
***
### getFileName()
* **Type**: (`referenceId`: `string`) => `string`
Get the file name of a chunk or asset that has been emitted via
[`this.emitFile`](#emitfile).
#### Parameters
##### referenceId
`string`
#### Returns
`string`
The file name of the emitted file. Relative to [`output.dir`](Interface.OutputOptions.md#dir).
***
### getModuleIds()
* **Type**: () => `IterableIterator`<`string`>
Get all module ids in the current module graph.
#### Returns
`IterableIterator`<`string`>
An iterator of module ids. It can be iterated via
```js
for (const moduleId of this.getModuleIds()) {
// ...
}
```
or converted into an array via `Array.from(this.getModuleIds())`.
***
### load()
* **Type**: (`options`: { `id`: `string`; `resolveDependencies?`: `boolean`; } & `Partial`<[`PartialNull`](TypeAlias.PartialNull.md)<[`ModuleOptions`](Interface.ModuleOptions.md)>>) => `Promise`<[`ModuleInfo`](Interface.ModuleInfo.md)>
Loads and parses the module corresponding to the given id, attaching additional
meta information to the module if provided. This will trigger the same
[`load`](Interface.Plugin.md#load), [`transform`](Interface.Plugin.md#transform) and
[`moduleParsed`](Interface.Plugin.md#moduleparsed) hooks as if the module was imported
by another module.
This allows you to inspect the final content of modules before deciding how to resolve them in the [`resolveId`](/reference/Interface.Plugin#resolveid) hook and e.g. resolve to a proxy module instead. If the module becomes part of the graph later, there is no additional overhead from using this context function as the module will not be parsed again. The signature allows you to directly pass the return value of [`this.resolve`](/reference/Interface.PluginContext#resolve) to this function as long as it is neither `null` nor external.
The returned Promise will resolve once the module has been fully transformed and parsed but before any imports have been resolved. That means that the resulting [`ModuleInfo`](/reference/Interface.ModuleInfo) will have empty [`importedIds`](/reference/Interface.ModuleInfo#importedids) and [`dynamicallyImportedIds`](/reference/Interface.ModuleInfo#dynamicallyimportedids). This helps to avoid deadlock situations when awaiting `this.load` in a [`resolveId`](/reference/Interface.Plugin#resolveid) hook. If you are interested in [`importedIds`](/reference/Interface.ModuleInfo#importedids) and [`dynamicallyImportedIds`](/reference/Interface.ModuleInfo#dynamicallyimportedids), you can either implement a [`moduleParsed`](/reference/Interface.Plugin#moduleparsed) hook or pass the `resolveDependencies` flag, which will make the Promise returned by `this.load` wait until all dependency ids have been resolved.
Note that with regard to the `meta` and `moduleSideEffects` options, the same restrictions apply as for the [`resolveId`](/reference/Interface.Plugin#resolveid) hook: Their values only have an effect if the module has not been loaded yet. Thus, it is very important to use [`this.resolve`](/reference/Interface.PluginContext#resolve) first to find out if any plugins want to set special values for these options in their [`resolveId`](/reference/Interface.Plugin#resolveid) hook, and pass these options on to `this.load` if appropriate. The example below showcases how this can be handled to add a proxy module for modules containing a special code comment. Note the special handling for re-exporting the default export:
```js
export default function addProxyPlugin() {
return {
async resolveId(source, importer, options) {
if (importer?.endsWith('?proxy')) {
// Do not proxy ids used in proxies
return null;
}
// We make sure to pass on any resolveId options to
// this.resolve to get the module id
const resolution = await this.resolve(source, importer, options);
// We can only pre-load existing and non-external ids
if (resolution && !resolution.external) {
// we pass on the entire resolution information
const moduleInfo = await this.load(resolution);
if (moduleInfo.code.includes('/* use proxy */')) {
return `${resolution.id}?proxy`;
}
}
// As we already fully resolved the module, there is no reason
// to resolve it again
return resolution;
},
load: {
filter: { id: /\?proxy$/ },
handler(id) {
const importee = id.slice(0, -'?proxy'.length);
// Note that namespace reexports do not reexport default exports
let code =
`console.log('proxy for ${importee}'); ` + `export * from ${JSON.stringify(importee)};`;
// We know that while resolving the proxy, importee was
// already fully loaded and parsed, so we can rely on `exports`
if (this.getModuleInfo(importee).exports.includes('default')) {
code += `export { default } from ${JSON.stringify(importee)};`;
}
return code;
},
},
};
}
```
If the module was already loaded, `this.load` will just wait for the parsing to complete and then return its module information. If the module was not yet imported by another module, it will not automatically trigger loading other modules imported by this module. Instead, static and dynamic dependencies will only be loaded once this module has actually been imported at least once.
::: warning Deadlocks caused by awaiting `this.load` in cyclic dependencies
While it is safe to use `this.load` in a [`resolveId`](/reference/Interface.Plugin#resolveid) hook, you should be very careful when awaiting it in a [`load`](/reference/Interface.Plugin#load) or [`transform`](/reference/Interface.Plugin#transform) hook. If there are cyclic dependencies in the module graph, this can easily lead to a deadlock, so any plugin needs to manually take care to avoid waiting for `this.load` inside the [`load`](/reference/Interface.Plugin#load) or [`transform`](/reference/Interface.Plugin#transform) of the any module that is in a cycle with the loaded module.
:::
#### Parameters
##### options
{ `id`: `string`; `resolveDependencies?`: `boolean`; } & `Partial`<[`PartialNull`](TypeAlias.PartialNull.md)<[`ModuleOptions`](Interface.ModuleOptions.md)>>
#### Returns
`Promise`<[`ModuleInfo`](Interface.ModuleInfo.md)>
***
### parse()
* **Type**: (`input`: `string`, `options?`: `ParserOptions` | `null`) => `Program`
Use Rolldown's internal parser to parse code to an [ESTree-compatible](https://github.com/estree/estree) AST.
#### Parameters
##### input
`string`
##### options?
`ParserOptions` | `null`
#### Returns
`Program`
***
### resolve()
* **Type**: (`source`: `string`, `importer?`: `string`, `options?`: [`PluginContextResolveOptions`](Interface.PluginContextResolveOptions.md)) => `Promise`<[`ResolvedId`](Interface.ResolvedId.md) | `null`>
Resolve imports to module ids (i.e. file names) using the same plugins that Rolldown uses,
and determine if an import should be external.
When calling this function from a [`resolveId`](Interface.Plugin.md#resolveid) hook, you should
always check if it makes sense for you to pass along the
[options](Interface.PluginContextResolveOptions.md).
#### Parameters
##### source
`string`
##### importer?
`string`
##### options?
[`PluginContextResolveOptions`](Interface.PluginContextResolveOptions.md)
#### Returns
`Promise`<[`ResolvedId`](Interface.ResolvedId.md) | `null`>
If `Promise` is returned, the import could not be resolved by Rolldown or any plugin
but was not explicitly marked as external by the user.
If an absolute external id is returned that should remain absolute in the output either
via the
[`makeAbsoluteExternalsRelative`](Interface.InputOptions.md#makeabsoluteexternalsrelative)
option or by explicit plugin choice in the [`resolveId`](Interface.Plugin.md#resolveid) hook,
`external` will be `"absolute"` instead of `true`.
## Logging Methods
### debug
* **Type**: (`log`) => `void`
Generate a `"debug"` level log.
[`code`](Interface.RolldownError.md#code) will be set to `"PLUGIN_LOG"` by Rolldown.
Make sure to add a distinctive [`pluginCode`](Interface.RolldownError.md#plugincode) to
those logs for easy filtering.
These logs are only processed if the [`logLevel`](/reference/InputOptions.logLevel) option is explicitly set to `"debug"`, otherwise it does nothing. Therefore, it is encouraged to add helpful debug logs to plugins as that can help spot issues while they will be efficiently muted by default.
::: tip Lazily Compute
If you need to do expensive computations to generate the log, make sure to use the function form so that these computations are only performed if the log is actually processed.
```js
function plugin() {
return {
name: 'test',
transform(code, id) {
this.debug(
() => `transforming ${id},\n` + `module contains, ${code.split('\n').length} lines`,
);
},
};
}
```
:::
#### Parameters
##### log
`string` | [`RolldownLog`](Interface.RolldownLog.md) | (() => `string` | [`RolldownLog`](Interface.RolldownLog.md))
The log object or message.
The string argument is equivalent to passing an object with only the
[`message`](Interface.RolldownError.md#message) property.
#### Returns
`void`
#### Inherited from
[`MinimalPluginContext`](Interface.MinimalPluginContext.md).[`debug`](Interface.MinimalPluginContext.md#debug)
***
### error
* **Type**: (`e`) => `never`
Similar to [`this.warn`](Interface.MinimalPluginContext.md#warn), except that it will also abort
the bundling process with an error.
If an Error instance is passed, it will be used as-is, otherwise a new Error
instance will be created with the given error message and all additional
provided properties.
In all hooks except the [`onLog`](Interface.Plugin.md#onlog) hook, the error will
be augmented with [`code: "PLUGIN_ERROR"`](Interface.RolldownError.md#code) and
[`plugin: plugin.name`](Interface.RolldownError.md#plugin) properties.
If a `code` property already exists and the code does not start with `PLUGIN_`,
it will be renamed to [`pluginCode`](Interface.RolldownError.md#plugincode).
#### Parameters
##### e
`string` | [`RolldownError`](Interface.RolldownError.md)
#### Returns
`never`
#### Inherited from
[`MinimalPluginContext`](Interface.MinimalPluginContext.md).[`error`](Interface.MinimalPluginContext.md#error)
***
### info
* **Type**: (`log`) => `void`
Generate a `"info"` level log.
[`code`](Interface.RolldownError.md#code) will be set to `"PLUGIN_LOG"` by Rolldown.
As these logs are displayed by default, use them for information that is not a warning
but makes sense to display to all users on every build.
If the [`logLevel`](/reference/InputOptions.logLevel) option is set to `"warn"` or `"silent"`, this method will do nothing.
#### Parameters
##### log
`string` | [`RolldownLog`](Interface.RolldownLog.md) | (() => `string` | [`RolldownLog`](Interface.RolldownLog.md))
The log object or message.
The string argument is equivalent to passing an object with only the
[`message`](Interface.RolldownError.md#message) property.
#### Returns
`void`
#### Inherited from
[`MinimalPluginContext`](Interface.MinimalPluginContext.md).[`info`](Interface.MinimalPluginContext.md#info)
***
### warn
* **Type**: (`log`) => `void`
Generate a `"warn"` level log.
Just like internally generated warnings, these logs will be first passed to and
filtered by plugin [`onLog`](Interface.Plugin.md#onlog) hooks before they are forwarded
to custom [`onLog`](Interface.InputOptions.md#onlog) or
[`onwarn`](Interface.InputOptions.md#onwarn) handlers or printed to the console.
We encourage you to use objects with a [`pluginCode`](Interface.RolldownError.md#plugincode)
property as that will allow users to easily filter for those logs in an `onLog` handler.
If you need to add additional information, you can use the [`meta`](/reference/Interface.RolldownLog#meta) property. If the log contains a [`code`](/reference/Interface.RolldownLog#code) and does not yet have a [`pluginCode`](/reference/Interface.RolldownLog#plugincode) property, it will be renamed to [`pluginCode`](/reference/Interface.RolldownLog#plugincode) as plugin warnings always get a code of `PLUGIN_WARNING` added by Rolldown.
If the logLevel option is set to `"silent"`, this method will do nothing.
::: tip Lazily Compute
If you need to do expensive computations to generate the log, make sure to use the function form so that these computations are only performed if the log is actually processed.
:::
#### Parameters
##### log
`string` | [`RolldownLog`](Interface.RolldownLog.md) | (() => `string` | [`RolldownLog`](Interface.RolldownLog.md))
The log object or message.
The string argument is equivalent to passing an object with only the
[`message`](Interface.RolldownError.md#message) property.
#### Returns
`void`
#### Inherited from
[`MinimalPluginContext`](Interface.MinimalPluginContext.md).[`warn`](Interface.MinimalPluginContext.md#warn)
---
---
url: /reference/Variable.VERSION.md
---
# Variable: VERSION
* **Type**: `string`
* **Default**: `version`
The version of Rolldown.
## Example
```ts
`'1.0.0'`
```
---
---
url: /reference/TypeAlias.AsyncPluginHooks.md
---
# Type Alias: AsyncPluginHooks
* **Type**: `Exclude`\
---
---
url: /reference/TypeAlias.BufferEncoding.md
---
# Type Alias: BufferEncoding
* **Type**: `"ascii"` | `"utf8"` | `"utf16le"` | `"ucs2"` | `"base64"` | `"base64url"` | `"latin1"` | `"binary"` | `"hex"`
---
---
url: /reference/Interface.CustomPluginOptions.md
---
# Interface: CustomPluginOptions
## Indexable
> \[`plugin`: `string`]: `any`
---
---
url: /reference/Interface.EmittedAsset.md
---
# Interface: EmittedAsset
Either a [`name`](#name) or a [`fileName`](#filename) can be supplied.
If a [`fileName`](#filename) is provided, it will be used unmodified as the name
of the generated file, throwing an error if this causes a conflict.
Otherwise, if a [`name`](#name) is supplied, this will be used as substitution
for `[name]` in the corresponding
[`output.assetFileNames`](Interface.OutputOptions.md#assetfilenames) pattern, possibly
adding a unique number to the end of the file name to avoid conflicts.
If neither a [`name`](#name) nor [`fileName`](#filename) is supplied, a default name will be used.
## Properties
### fileName?
* **Type**: `string`
* **Optional**
***
### name?
* **Type**: `string`
* **Optional**
***
### originalFileName?
* **Type**: `string`
* **Optional**
An absolute path to the original file if this asset corresponds to a file on disk.
This property will be passed on to subsequent plugin hooks that receive a
[`PreRenderedAsset`](Interface.PreRenderedAsset.md) or an [`OutputAsset`](Interface.OutputAsset.md) like
[`generateBundle`](Interface.Plugin.md#generatebundle).
In watch mode, Rolldown will also automatically watch this file for changes and
trigger a rebuild if it changes. Therefore, it is not necessary to call
[`this.addWatchFile`](Interface.PluginContext.md#addwatchfile) for this file.
***
### source
* **Type**: `string` | `Uint8Array`<`ArrayBufferLike`>
***
### type
* **Type**: `"asset"`
---
---
url: /reference/Interface.EmittedChunk.md
---
# Interface: EmittedChunk
Either a [`name`](#name) or a [`fileName`](#filename) can be supplied.
If a [`fileName`](#filename) is provided, it will be used unmodified as the name
of the generated file, throwing an error if this causes a conflict.
Otherwise, if a [`name`](#name) is supplied, this will be used as substitution
for `[name]` in the corresponding
[`output.chunkFileNames`](Interface.OutputOptions.md#chunkfilenames) pattern, possibly
adding a unique number to the end of the file name to avoid conflicts.
If neither a [`name`](#name) nor [`fileName`](#filename) is supplied, a default name will be used.
## Properties
### fileName?
* **Type**: `string`
* **Optional**
***
### id
* **Type**: `string`
The module id of the entry point of the chunk.
It will be passed through build hooks just like regular entry points,
starting with [`resolveId`](Interface.Plugin.md#resolveid).
***
### importer?
* **Type**: `string`
* **Optional**
The value to be passed to [`resolveId`](Interface.Plugin.md#resolveid)'s [`importer`](#importer) parameter when resolving the entry point.
This is important to properly resolve relative paths. If it is not provided,
paths will be resolved relative to the current working directory.
***
### name?
* **Type**: `string`
* **Optional**
***
### preserveSignature?
* **Type**: `false` | `"strict"` | `"allow-extension"` | `"exports-only"`
* **Optional**
When provided, this will override
[`preserveEntrySignatures`](Interface.InputOptions.md#preserveentrysignatures) for this particular
chunk.
***
### type
* **Type**: `"chunk"`
---
---
url: /reference/TypeAlias.EmittedFile.md
---
# Type Alias: EmittedFile
* **Type**: [`EmittedAsset`](Interface.EmittedAsset.md) | [`EmittedChunk`](Interface.EmittedChunk.md) | [`EmittedPrebuiltChunk`](Interface.EmittedPrebuiltChunk.md)
---
---
url: /reference/Interface.EmittedPrebuiltChunk.md
---
# Interface: EmittedPrebuiltChunk
## Properties
### code
* **Type**: `string`
The code of this chunk.
***
### exports?
* **Type**: `string`\[]
* **Optional**
The list of exported variable names from this chunk.
This should be provided if the chunk exports any variables.
***
### facadeModuleId?
* **Type**: `string`
* **Optional**
The module id of the facade module for this chunk, if any.
***
### fileName
* **Type**: `string`
***
### isDynamicEntry?
* **Type**: `boolean`
* **Optional**
Whether this chunk corresponds to a dynamic entry point.
***
### isEntry?
* **Type**: `boolean`
* **Optional**
Whether this chunk corresponds to an entry point.
***
### map?
* **Type**: [`SourceMap`](Interface.SourceMap.md)
* **Optional**
The corresponding source map for this chunk.
***
### name?
* **Type**: `string`
* **Optional**
A semantic name for the chunk. If not provided, `fileName` will be used.
***
### sourcemapFileName?
* **Type**: `string`
* **Optional**
***
### type
* **Type**: `"prebuilt-chunk"`
---
---
url: /reference/Interface.ExistingRawSourceMap.md
---
# Interface: ExistingRawSourceMap
## Properties
### file?
* **Type**: `string` | `null`
* **Optional**
***
### mappings
* **Type**: `string`
***
### names?
* **Type**: `string`\[]
* **Optional**
***
### sourceRoot?
* **Type**: `string`
* **Optional**
***
### sources?
* **Type**: (`string` | `null`)\[]
* **Optional**
***
### sourcesContent?
* **Type**: (`string` | `null` | `undefined`)\[]
* **Optional**
***
### version?
* **Type**: `number`
* **Optional**
***
### x\_google\_ignoreList?
* **Type**: `number`\[]
* **Optional**
---
---
url: /reference/Interface.FunctionPluginHooks.md
---
# Interface: FunctionPluginHooks
## Build Hooks
### buildEnd
* **Type**: (`this`, `err?`) => `void`
* **Kind**: `async`, `parallel`
Called when Rolldown has finished bundling, but before Output Generation Hooks.
If an error occurred during the build, it is passed on to this hook.
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### err?
`Error`
The error occurred during the build if applicable. Normally [`BundleError`](TypeAlias.BundleError.md)
#### Returns
`void`
***
### buildStart
* **Type**: (`this`, `options`) => `void`
* **Kind**: `async`, `parallel`
Called on each [`rolldown()`](Function.rolldown.md) build.
This is the recommended hook to use when you need access to the options passed to [`rolldown()`](Function.rolldown.md) as it takes the transformations by all options hooks into account and also contains the right default values for unset options.
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### options
[`NormalizedInputOptions`](Interface.NormalizedInputOptions.md)
#### Returns
`void`
***
### closeWatcher
* **Type**: (`this`) => `void`
* **Kind**: `async`, `parallel`
Notifies a plugin when the watcher process will close so that all open resources can be closed too.
This hook cannot be used by output plugins.
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
#### Returns
`void`
***
### load
* **Type**: (`this`, `id`) => `MaybePromise`<`undefined` | `null` | `string` | `void` | [`SourceDescription`](Interface.SourceDescription.md)>
* **Kind**: `async`, `first`
Defines a custom loader.
Returning `null` defers to other `load` hooks or the built-in loading mechanism.
You can use [`this.getModuleInfo()`](Interface.PluginContext.md#getmoduleinfo) to find out the previous values of `meta`, `moduleSideEffects` inside this hook.
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### id
`string`
#### Returns
`MaybePromise`<`undefined` | `null` | `string` | `void` | [`SourceDescription`](Interface.SourceDescription.md)>
***
### moduleParsed
* **Type**: (`this`, `moduleInfo`) => `void`
* **Kind**: `async`, `parallel`
This hook is called each time a module has been fully parsed by Rolldown.
This hook will wait until all imports are resolved so that the information in
[`moduleInfo.importedIds`](Interface.ModuleInfo.md#importedids),
[`moduleInfo.dynamicallyImportedIds`](Interface.ModuleInfo.md#dynamicallyimportedids)
are complete and accurate. Note however that information about importing modules
may be incomplete as additional importers could be discovered later.
If you need this information, use the [`buildEnd`](#buildend) hook.
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### moduleInfo
[`ModuleInfo`](Interface.ModuleInfo.md)
#### Returns
`void`
***
### onLog
* **Type**: (`this`, `level`, `log`) => `boolean` | `undefined` | `null` | `void`
* **Kind**: `sync`, `sequential`
A function that receives and filters logs and warnings generated by Rolldown and
plugins before they are passed to the [`onLog`](Interface.InputOptions.md#onlog) option
or printed to the console.
If `false` is returned, the log will be filtered out.
Otherwise, the log will be handed to the `onLog` hook of the next plugin,
the [`onLog`](Interface.InputOptions.md#onlog) option, or printed to the console.
Plugins can also change the log level of a log or turn a log into an error by passing
the `log` object to [`this.error`](Interface.MinimalPluginContext.md#error),
[`this.warn`](Interface.MinimalPluginContext.md#warn),
[`this.info`](Interface.MinimalPluginContext.md#info) or
[`this.debug`](Interface.MinimalPluginContext.md#debug) and returning `false`.
Note that unlike other plugin hooks that add e.g. the plugin name to the log, those functions will not add or change properties of the log. Additionally, logs generated by an `onLog` hook will not be passed back to
the `onLog` hook of the same plugin. If another plugin generates a log in response to such a log in its own `onLog` hook, this log will not be passed to the original `onLog` hook, either.
#### Example
```js
function plugin1() {
return {
name: 'plugin1',
buildStart() {
this.info({ message: 'Hey', pluginCode: 'SPECIAL_CODE' });
},
onLog(level, log) {
if (log.plugin === 'plugin1' && log.pluginCode === 'SPECIAL_CODE') {
// We turn logs into warnings based on their code. This warnings
// will not be passed back to the same plugin to avoid an
// infinite loop, but other plugins will still receive it.
this.warn(log);
return false;
}
},
};
}
function plugin2() {
return {
name: 'plugin2',
onLog(level, log) {
if (log.plugin === 'plugin1' && log.pluginCode === 'SPECIAL_CODE') {
// You can modify logs in this hooks as well
log.meta = 'processed by plugin 2';
// This turns the log back to "info". If this happens in
// response to the first plugin, it will not be passed back to
// either plugin to avoid an infinite loop. If both plugins are
// active, the log will be an info log if the second plugin is
// placed after the first one
this.info(log);
return false;
}
},
};
}
```
#### Parameters
##### this
[`MinimalPluginContext`](Interface.MinimalPluginContext.md)
##### level
`"info"` | `"debug"` | `"warn"`
##### log
[`RolldownLog`](Interface.RolldownLog.md)
#### Returns
`boolean` | `undefined` | `null` | `void`
***
### options
* **Type**: (`this`, `options`) => `undefined` | `null` | `void` | [`InputOptions`](Interface.InputOptions.md)
* **Kind**: `async`, `sequential`
Replaces or manipulates the options object passed to [`rolldown()`](Function.rolldown.md).
Returning `null` does not replace anything.
If you just need to read the options, it is recommended to use
the [`buildStart`](#buildstart) hook as that hook has access to the options
after the transformations from all `options` hooks have been taken into account.
#### Parameters
##### this
[`MinimalPluginContext`](Interface.MinimalPluginContext.md)
##### options
[`InputOptions`](Interface.InputOptions.md)
#### Returns
`undefined` | `null` | `void` | [`InputOptions`](Interface.InputOptions.md)
***
### outputOptions
* **Type**: (`this`, `options`) => [`OutputOptions`](Interface.OutputOptions.md) | `undefined` | `null` | `void`
* **Kind**: `sync`, `sequential`
Replaces or manipulates the output options object passed to
[`bundle.generate()`](Interface.RolldownBuild.md#generate) or
[`bundle.write()`](Interface.RolldownBuild.md#write).
Returning null does not replace anything.
If you just need to read the output options, it is recommended to use
the [`renderStart`](#renderstart) hook as this hook has access to the output options
after the transformations from all `outputOptions` hooks have been taken into account.
#### Parameters
##### this
[`MinimalPluginContext`](Interface.MinimalPluginContext.md)
##### options
[`OutputOptions`](Interface.OutputOptions.md)
#### Returns
[`OutputOptions`](Interface.OutputOptions.md) | `undefined` | `null` | `void`
***
### ~~resolveDynamicImport~~
* **Type**: (`this`, `source`, `importer`) => `undefined` | `null` | `string` | `false` | `void` | [`PartialResolvedId`](Interface.PartialResolvedId.md)
* **Kind**: `async`, `first`
Defines a custom resolver for dynamic imports.
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### source
`string`
The importee exactly as it is written in the import statement.
For example, given `import('./foo.js')`, the `source` will be `"./foo.js"`.
In Rollup, this parameter can also be an AST node. But Rolldown always provides a string.
##### importer
`string` | `undefined`
The fully resolved id of the importing module.
This will be `undefined` when [`this.resolve(source, undefined, { kind: 'dynamic-import' `](Interface.PluginContext.md#resolve))} is called.
#### Returns
`undefined` | `null` | `string` | `false` | `void` | [`PartialResolvedId`](Interface.PartialResolvedId.md)
#### Deprecated
This hook exists only for Rollup compatibility. Please use [`resolveId`](#resolveid) instead.
***
### resolveId
* **Type**: (`this`, `source`, `importer`, `extraOptions`) => `undefined` | `null` | `string` | `false` | `void` | [`PartialResolvedId`](Interface.PartialResolvedId.md)
* **Kind**: `async`, `first`
Defines a custom resolver.
A resolver can be useful for e.g. locating third-party dependencies.
Returning `null` defers to other `resolveId` hooks and eventually the default resolution behavior.
Returning `false` signals that `source` should be treated as an external module and not included in the bundle. If this happens for a relative import, the id will be renormalized the same way as when the [`InputOptions.external`](Interface.InputOptions.md#external) option is used.
If you return an object, then it is possible to resolve an import to a different id while excluding it from the bundle at the same time.
Note that while `resolveId` will be called for each import of a module and can therefore
resolve to the same `id` many times, values for `external`, `meta` or `moduleSideEffects`
can only be set once before the module is loaded. The reason is that after this call,
Rolldown will continue with the [`load`](#load) and [`transform`](#transform) hooks for that
module that may override these values and should take precedence if they do so.
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### source
`string`
The importee exactly as it is written in the import statement.
For example, given `import foo from './foo.js'`, the `source` will be `"./foo.js"`.
##### importer
`string` | `undefined`
The fully resolved id of the importing module.
When resolving entry points, `importer` will usually be undefined.
An exception here is entry points generated via
[`this.emitFile`](Interface.PluginContext.md#emitfile) as here, you can provide
an importer argument.
For those cases, the [`isEntry`](Interface.ResolveIdExtraOptions.md#isentry) option
will tell you if we are resolving a user defined entry point, an emitted chunk,
or if the `isEntry` parameter was provided for the
[`this.resolve`](Interface.PluginContext.md#resolve) function.
##### extraOptions
###### custom?
[`CustomPluginOptions`](Interface.CustomPluginOptions.md)
Plugin-specific options.
See [Custom resolver options section](/apis/plugin-api/inter-plugin-communication#custom-resolver-options) for more details.
###### isEntry
`boolean`
Whether this is resolution for an entry point.
::: details Define custom proxy modules for entry points
This can be used for instance as a mechanism to define custom proxy modules for entry points. The following plugin will proxy all entry points to inject a polyfill import.
```js
import { exactRegex } from '@rolldown/pluginutils';
// We prefix the polyfill id with \0 to tell other plugins not to try to load or
// transform it
const POLYFILL_ID = '\0polyfill';
const PROXY_SUFFIX = '?inject-polyfill-proxy';
function injectPolyfillPlugin() {
return {
name: 'inject-polyfill',
async resolveId(source, importer, options) {
if (source === POLYFILL_ID) {
// It is important that side effects are always respected for polyfills,
// otherwise using `treeshake.moduleSideEffects: false` may prevent the
// polyfill from being included.
return { id: POLYFILL_ID, moduleSideEffects: true };
}
if (options.isEntry) {
// Determine what the actual entry would have been.
const resolution = await this.resolve(source, importer, options);
// If it cannot be resolved or is external, just return it so that Rolldown
// can display an error
if (!resolution || resolution.external) return resolution;
// In the load hook of the proxy, we need to know if the entry has a
// default export. There, however, we no longer have the full "resolution"
// object that may contain meta-data from other plugins that is only added
// on first load. Therefore we trigger loading here.
const moduleInfo = await this.load(resolution);
// We need to make sure side effects in the original entry point are
// respected even for `treeshake.moduleSideEffects: false`. "moduleSideEffects"
// is a writable property on ModuleInfo.
moduleInfo.moduleSideEffects = true;
// It is important that the new entry does not start with `\0` and has the same
// directory as the original one to not mess up relative external import generation.
// Also keeping the name and just adding a "?query" to the end ensures that
// `preserveModules` will generate the original entry name for this entry.
return `${resolution.id}${PROXY_SUFFIX}`;
}
return null;
},
load: {
filter: { id: [exactRegex(POLYFILL_ID), /\?proxy$/] },
handler(id) {
if (id === POLYFILL_ID) {
// Replace with actual polyfill
return "console.log('polyfill');";
}
if (id.endsWith(PROXY_SUFFIX)) {
const entryId = id.slice(0, -PROXY_SUFFIX.length);
// We know ModuleInfo.exports is reliable because we awaited this.load in resolveId
const { exports } = this.getModuleInfo(entryId);
let code =
`import ${JSON.stringify(POLYFILL_ID)};` + `export * from ${JSON.stringify(entryId)};`;
// Namespace reexports do not reexport default, so we need special handling here
if (exports.includes('default')) {
code += `export { default } from ${JSON.stringify(entryId)};`;
}
return code;
}
return null;
},
},
};
}
```
:::
###### kind
`"import-statement"` | `"dynamic-import"` | `"require-call"` | `"import-rule"` | `"url-token"` | `"new-url"` | `"hot-accept"`
The kind of import being resolved.
* `import-statement`: `import { foo } from './lib.js';`
* `dynamic-import`: `import('./lib.js')`
* `require-call`: `require('./lib.js')`
* `import-rule`: `@import 'bg-color.css'` (experimental)
* `url-token`: `url('./icon.png')` (experimental)
* `new-url`: `new URL('./worker.js', import.meta.url)` (experimental)
* `hot-accept`: `import.meta.hot.accept('./lib.js', () => {})` (experimental)
#### Returns
`undefined` | `null` | `string` | `false` | `void` | [`PartialResolvedId`](Interface.PartialResolvedId.md)
***
### transform
* **Type**: (`this`, `code`, `id`, `meta`) => `undefined` | `null` | `string` | `void` | `Omit`<[`SourceDescription`](Interface.SourceDescription.md), `"code"`> & { `code?`: `string` | [`RolldownMagicString`](Interface.RolldownMagicString.md); }
* **Kind**: `async`, `sequential`
Can be used to transform individual modules.
Note that it's possible to return only properties and no code transformations.
You can use [`this.getModuleInfo()`](Interface.PluginContext.md#getmoduleinfo) to find out the previous values of `meta`, `moduleSideEffects` inside this hook.
::: warning Changing `moduleType`
When you change the [type of the module](/in-depth/module-types) by returning [`moduleType`](/reference/Interface.SourceDescription#moduletype) property, the module is not thrown back to the beginning of the plugin chain. This means the `transform` hooks of the plugins that already saw this module will not be called with the new `moduleType`. For this reason, it is recommended to place the plugins that change the `moduleType` at the beginning of the plugin list.
If you need to let all the plugins be called, you can create a [virtual module](/apis/plugin-api#virtual-modules) with a different `moduleType` instead of changing the `moduleType` directly in the `transform` hook.
:::
#### Parameters
##### this
[`TransformPluginContext`](Interface.TransformPluginContext.md)
##### code
`string`
##### id
`string`
##### meta
`BindingTransformHookExtraArgs` & { `ast?`: `Program`; `magicString?`: [`RolldownMagicString`](Interface.RolldownMagicString.md); `moduleType`: [`ModuleType`](TypeAlias.ModuleType.md); }
#### Returns
`undefined` | `null` | `string` | `void` | `Omit`<[`SourceDescription`](Interface.SourceDescription.md), `"code"`> & { `code?`: `string` | [`RolldownMagicString`](Interface.RolldownMagicString.md); }
***
### watchChange
* **Type**: (`this`, `id`, `event`) => `void`
* **Kind**: `async`, `parallel`
Notifies a plugin whenever Rolldown has detected a change to a monitored file in watch mode.
If a build is currently running, this hook is called once the build finished.
It will be called once for every file that changed.
This hook cannot be used by output plugins.
If you need to be notified immediately when a file changed, you can use the [`watch.onInvalidate`](Interface.WatcherOptions.md#oninvalidate) option.
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### id
`string`
##### event
###### event
`ChangeEvent`
#### Returns
`void`
## Output Generation Hooks
### augmentChunkHash
* **Type**: (`this`, `chunk`) => `string` | `void`
* **Kind**: `sync`, `sequential`
Can be used to augment the hash of individual chunks. Called for each Rolldown output chunk.
Returning a falsy value will not modify the hash.
Truthy values will be used as an additional source for hash calculation.
#### Example
The following plugin will invalidate the hash of chunk foo with the current timestamp:
```js
function augmentWithDatePlugin() {
return {
name: 'augment-with-date',
augmentChunkHash(chunkInfo) {
if (chunkInfo.name === 'foo') {
return Date.now().toString();
}
},
};
}
```
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### chunk
[`RenderedChunk`](Interface.RenderedChunk.md)
#### Returns
`string` | `void`
***
### closeBundle
* **Type**: (`this`, `error?`) => `void`
* **Kind**: `async`, `parallel`
Can be used to clean up any external service that may be running.
Rolldown's CLI will make sure this hook is called after each run, but it is the responsibility
of users of the JavaScript API to manually call
[`bundle.close()`](Interface.RolldownBuild.md#close) once they are done generating bundles.
For that reason, any plugin relying on this feature should carefully mention this in
its documentation.
If a plugin wants to retain resources across builds in watch mode, they can check for
[`this.meta.watchMode`](Interface.PluginContextMeta.md#watchmode) in this hook and perform
the necessary cleanup for watch mode in closeWatcher.
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### error?
`Error`
An error that occurred during build or the buildEnd hook, if any.
#### Returns
`void`
***
### generateBundle
* **Type**: (`this`, `outputOptions`, `bundle`, `isWrite`) => `void`
* **Kind**: `async`, `sequential`
Called at the end of [`bundle.generate()`](Interface.RolldownBuild.md#generate) or
immediately before the files are written in
[`bundle.write()`](Interface.RolldownBuild.md#write).
To modify the files after they have been written, use the [`writeBundle`](#writebundle) hook.
You can prevent files from being emitted by deleting them from the bundle object in this hook. To emit additional files, use the [`this.emitFile`](/reference/Interface.PluginContext#emitfile) function.
::: danger
Do not directly add assets to the bundle. This will not work as expected as Rolldown will ignore those assets. This is [not recommended in Rollup](https://rollupjs.org/plugin-development/#generatebundle) as well.
Instead, always use [`this.emitFile`](/reference/Interface.PluginContext#emitfile).
:::
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### outputOptions
[`NormalizedOutputOptions`](Interface.NormalizedOutputOptions.md)
##### bundle
[`OutputBundle`](Interface.OutputBundle.md)
Provides the full list of files being written or generated along with their details.
##### isWrite
`boolean`
#### Returns
`void`
***
### renderChunk
* **Type**: (`this`, `code`, `chunk`, `outputOptions`, `meta`) => `string` | [`RolldownMagicString`](Interface.RolldownMagicString.md) | `undefined` | `null` | `void` | { `code`: `string` | [`RolldownMagicString`](Interface.RolldownMagicString.md); `map?`: SourceMapInput | undefined; }
* **Kind**: `async`, `sequential`
Can be used to transform individual chunks. Called for each Rolldown output chunk file.
Returning null will apply no transformations. If you change code in this hook and want to support source maps, you need to return a map describing your changes, see [Source Code Transformations section](/apis/plugin-api/transformations#source-code-transformations).
`chunk` is mutable and changes applied in this hook will propagate to other plugins and
to the generated bundle.
That means if you add or remove imports or exports in this hook, you should update
[`imports`](Interface.RenderedChunk.md#imports), RenderedChunk.importedBindings | importedBindings and/or [`exports`](Interface.RenderedChunk.md#exports) accordingly.
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### code
`string`
##### chunk
[`RenderedChunk`](Interface.RenderedChunk.md)
##### outputOptions
[`NormalizedOutputOptions`](Interface.NormalizedOutputOptions.md)
##### meta
`RenderedChunkMeta`
#### Returns
`string` | [`RolldownMagicString`](Interface.RolldownMagicString.md) | `undefined` | `null` | `void` | { `code`: `string` | [`RolldownMagicString`](Interface.RolldownMagicString.md); `map?`: SourceMapInput | undefined; }
***
### renderError
* **Type**: (`this`, `error`) => `void`
* **Kind**: `async`, `parallel`
Called when Rolldown encounters an error during
[`bundle.generate()`](Interface.RolldownBuild.md#generate) or
[`bundle.write()`](Interface.RolldownBuild.md#write).
To get notified when generation completes successfully, use the
[`generateBundle`](#generatebundle) hook.
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### error
`Error`
The error that occurred during the build. Normally [`BundleError`](TypeAlias.BundleError.md)
#### Returns
`void`
***
### renderStart
* **Type**: (`this`, `outputOptions`, `inputOptions`) => `void`
* **Kind**: `async`, `parallel`
Called initially each time [`bundle.generate()`](Interface.RolldownBuild.md#generate) or
[`bundle.write()`](Interface.RolldownBuild.md#write) is called.
To get notified when generation has completed, use the [`generateBundle`](#generatebundle) and
[`renderError`](#rendererror) hooks.
This is the recommended hook to use when you need access to the output options passed to
[`bundle.generate()`](Interface.RolldownBuild.md#generate) or
[`bundle.write()`](Interface.RolldownBuild.md#write) as it takes the transformations by all outputOptions hooks into account and also contains the right default values for unset options.
It also receives the input options passed to [`rolldown()`](Function.rolldown.md) so that
plugins that can be used as output plugins, i.e. plugins that only use generate phase hooks,
can get access to them.
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### outputOptions
[`NormalizedOutputOptions`](Interface.NormalizedOutputOptions.md)
##### inputOptions
[`NormalizedInputOptions`](Interface.NormalizedInputOptions.md)
#### Returns
`void`
***
### resolveFileUrl
* **Type**: (`this`, `args`) => `string` | `undefined` | `null` | `void`
Allows customizing how Rolldown resolves URLs of files that were emitted by plugins via [`this.emitFile`](/reference/Interface.PluginContext#emitfile). By default, Rolldown will generate code for `import.meta.ROLLDOWN_FILE_URL_referenceId` that resolves the emitted file relative to `import.meta.url`. This generates correct absolute URLs for the `esm` format, and for the `cjs` format on the `node` platform where `import.meta.url` is [polyfilled](/in-depth/non-esm-output-formats#well-known-import-meta-properties). For the `iife` and `umd` formats, `import.meta.url` is not available and the generated code will not work — Rolldown emits a warning in that case. To support these formats, this hook needs to be implemented to return code that does not rely on `import.meta.url`. See [File URLs](/apis/plugin-api/file-urls) for more details and an example.
This hook can be used to customize the behavior of `import.meta.ROLLDOWN_FILE_URL_referenceId`.
The returned string must be a single JavaScript expression. Also the returned expression must be side-effect free. If the URL is not used in the code, Rolldown will remove it.
Rolldown additionally accepts `import.meta.ROLLDOWN_FILE_URL_referenceId_urlId`, where `urlId` is an arbitrary identifier of your choosing. It is passed to this hook as `args.urlId`, letting a single plugin resolve the same emitted file differently depending on the reference. The `urlId` API is experimental and may change in minor versions. The `urlId` is not available on the Rollup-compatible `ROLLUP_FILE_URL_` alias. Use only ASCII identifier characters in a `urlId`: letters, digits, `_`, and `$`.
::: tip `import.meta.url` in the returned string
If the returned string contains `import.meta.url`, it will be rewritten for non-ESM formats similarly to [when `import.meta.url` is used in the code directly](/in-depth/non-esm-output-formats#well-known-import-meta-properties). Unlike Rolldown, Rollup outputs `import.meta.url` as-is.
:::
#### Example
The following plugin will always resolve all files relative to the current document:
```js
function resolveToDocumentPlugin() {
return {
name: 'resolve-to-document',
resolveFileUrl({ fileName }) {
return `new URL(${JSON.stringify(fileName)}, document.baseURI).href`;
},
};
}
```
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### args
[`ResolveFileUrlArgs`](Interface.ResolveFileUrlArgs.md)
#### Returns
`string` | `undefined` | `null` | `void`
***
### writeBundle
* **Type**: (`this`, `outputOptions`, `bundle`) => `void`
* **Kind**: `async`, `parallel`
Called only at the end of [`bundle.write()`](Interface.RolldownBuild.md#write) once
all files have been written.
#### Parameters
##### this
[`PluginContext`](Interface.PluginContext.md)
##### outputOptions
[`NormalizedOutputOptions`](Interface.NormalizedOutputOptions.md)
##### bundle
[`OutputBundle`](Interface.OutputBundle.md)
Provides the full list of files being written or generated along with their details.
#### Returns
`void`
---
---
url: /reference/TypeAlias.GeneralHookFilter.md
---
# Type Alias: GeneralHookFilter\
* **Type**: `MaybeArray`<`Value`> | { `exclude?`: `MaybeArray`<`Value`>; `include?`: `MaybeArray`<`Value`>; }
## Type Parameters
### Value
`Value` = `StringOrRegExp`
---
---
url: /reference/Interface.HookFilter.md
---
# Interface: HookFilter
A filter to be used to do a pre-test to determine whether the hook should be called.
See [Plugin Hook Filters page](/apis/plugin-api/hook-filters) for more details.
## Properties
### code?
* **Type**: [`GeneralHookFilter`](TypeAlias.GeneralHookFilter.md)<`string` | `RegExp`>
* **Optional**
A filter based on the module's code.
Only available for [`transform`](Interface.Plugin.md#transform) hook.
***
### id?
* **Type**: [`GeneralHookFilter`](TypeAlias.GeneralHookFilter.md)<`string` | `RegExp`>
* **Optional**
A filter based on the module `id`.
If the value is a string, it is treated as a glob pattern.
The string type is not available for [`resolveId`](Interface.Plugin.md#resolveid) hook.
If the value is a regular expression, it is tested after the `id`'s path separators are normalized to forward slashes (`/`).
This keeps the filter portable across operating systems without requiring the regular expression to match both `/` and \`\`.
#### Examples
Include all `id`s that contain `node_modules` in the path.
```js
{ id: '**'+'/node_modules/**' }
```
Include all `id`s that contain `node_modules` or `src` in the path.
```js
{ id: ['**'+'/node_modules/**', '**'+'/src/**'] }
```
Include all `id`s that start with `http`
```js
{ id: /^http/ }
```
Exclude all `id`s that contain `node_modules` in the path.
```js
{ id: { exclude: '**'+'/node_modules/**' } }
```
Formal pattern to define includes and excludes.
```js
{ id : {
include: ['**'+'/foo/**', /bar/],
exclude: ['**'+'/baz/**', /qux/]
}}
```
***
### moduleType?
* **Type**: [`ModuleTypeFilter`](TypeAlias.ModuleTypeFilter.md)
* **Optional**
A filter based on the module's `moduleType`.
Only available for [`transform`](Interface.Plugin.md#transform) hook.
---
---
url: /reference/TypeAlias.HookFilterExtension.md
---
# Type Alias: HookFilterExtension\
* **Type**: `K` *extends* `"transform"` ? { `filter?`: [`HookFilter`](Interface.HookFilter.md) | [`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md)\[]; } : `K` *extends* `"load"` ? { `filter?`: `Pick`<[`HookFilter`](Interface.HookFilter.md), `"id"`> | [`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md)\[]; } : `K` *extends* `"resolveId"` ? { `filter?`: { `id?`: [`GeneralHookFilter`](TypeAlias.GeneralHookFilter.md)<`RegExp`>; } | [`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md)\[]; } : `K` *extends* `"renderChunk"` ? { `filter?`: `Pick`<[`HookFilter`](Interface.HookFilter.md), `"code"`> | [`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md)\[]; } : { }
## Type Parameters
### K
`K` *extends* keyof [`FunctionPluginHooks`](Interface.FunctionPluginHooks.md)
---
---
url: /reference/TypeAlias.ImportKind.md
---
# Type Alias: ImportKind
* **Type**: `BindingHookResolveIdExtraArgs`\[`"kind"`]
---
---
url: /reference/TypeAlias.InternalModuleFormat.md
---
# Type Alias: InternalModuleFormat
* **Type**: `"es"` | `"cjs"` | `"iife"` | `"umd"`
A normalized version of [`ModuleFormat`](TypeAlias.ModuleFormat.md).
---
---
url: /reference/TypeAlias.LoadResult.md
---
# Type Alias: LoadResult
* **Type**: `NullValue` | `string` | [`SourceDescription`](Interface.SourceDescription.md)
---
---
url: /reference/Interface.MinimalPluginContext.md
---
# Interface: MinimalPluginContext
## Extended by
* [`PluginContext`](Interface.PluginContext.md)
## Properties
### meta
* **Type**: [`PluginContextMeta`](Interface.PluginContextMeta.md)
An object containing potentially useful metadata.
## Logging Methods
### debug
* **Type**: (`log`) => `void`
Generate a `"debug"` level log.
[`code`](Interface.RolldownError.md#code) will be set to `"PLUGIN_LOG"` by Rolldown.
Make sure to add a distinctive [`pluginCode`](Interface.RolldownError.md#plugincode) to
those logs for easy filtering.
These logs are only processed if the [`logLevel`](/reference/InputOptions.logLevel) option is explicitly set to `"debug"`, otherwise it does nothing. Therefore, it is encouraged to add helpful debug logs to plugins as that can help spot issues while they will be efficiently muted by default.
::: tip Lazily Compute
If you need to do expensive computations to generate the log, make sure to use the function form so that these computations are only performed if the log is actually processed.
```js
function plugin() {
return {
name: 'test',
transform(code, id) {
this.debug(
() => `transforming ${id},\n` + `module contains, ${code.split('\n').length} lines`,
);
},
};
}
```
:::
#### Parameters
##### log
`string` | [`RolldownLog`](Interface.RolldownLog.md) | (() => `string` | [`RolldownLog`](Interface.RolldownLog.md))
The log object or message.
The string argument is equivalent to passing an object with only the
[`message`](Interface.RolldownError.md#message) property.
#### Returns
`void`
***
### error
* **Type**: (`e`) => `never`
Similar to [`this.warn`](#warn), except that it will also abort
the bundling process with an error.
If an Error instance is passed, it will be used as-is, otherwise a new Error
instance will be created with the given error message and all additional
provided properties.
In all hooks except the [`onLog`](Interface.Plugin.md#onlog) hook, the error will
be augmented with [`code: "PLUGIN_ERROR"`](Interface.RolldownError.md#code) and
[`plugin: plugin.name`](Interface.RolldownError.md#plugin) properties.
If a `code` property already exists and the code does not start with `PLUGIN_`,
it will be renamed to [`pluginCode`](Interface.RolldownError.md#plugincode).
#### Parameters
##### e
`string` | [`RolldownError`](Interface.RolldownError.md)
#### Returns
`never`
***
### info
* **Type**: (`log`) => `void`
Generate a `"info"` level log.
[`code`](Interface.RolldownError.md#code) will be set to `"PLUGIN_LOG"` by Rolldown.
As these logs are displayed by default, use them for information that is not a warning
but makes sense to display to all users on every build.
If the [`logLevel`](/reference/InputOptions.logLevel) option is set to `"warn"` or `"silent"`, this method will do nothing.
#### Parameters
##### log
`string` | [`RolldownLog`](Interface.RolldownLog.md) | (() => `string` | [`RolldownLog`](Interface.RolldownLog.md))
The log object or message.
The string argument is equivalent to passing an object with only the
[`message`](Interface.RolldownError.md#message) property.
#### Returns
`void`
***
### warn
* **Type**: (`log`) => `void`
Generate a `"warn"` level log.
Just like internally generated warnings, these logs will be first passed to and
filtered by plugin [`onLog`](Interface.Plugin.md#onlog) hooks before they are forwarded
to custom [`onLog`](Interface.InputOptions.md#onlog) or
[`onwarn`](Interface.InputOptions.md#onwarn) handlers or printed to the console.
We encourage you to use objects with a [`pluginCode`](Interface.RolldownError.md#plugincode)
property as that will allow users to easily filter for those logs in an `onLog` handler.
If you need to add additional information, you can use the [`meta`](/reference/Interface.RolldownLog#meta) property. If the log contains a [`code`](/reference/Interface.RolldownLog#code) and does not yet have a [`pluginCode`](/reference/Interface.RolldownLog#plugincode) property, it will be renamed to [`pluginCode`](/reference/Interface.RolldownLog#plugincode) as plugin warnings always get a code of `PLUGIN_WARNING` added by Rolldown.
If the logLevel option is set to `"silent"`, this method will do nothing.
::: tip Lazily Compute
If you need to do expensive computations to generate the log, make sure to use the function form so that these computations are only performed if the log is actually processed.
:::
#### Parameters
##### log
`string` | [`RolldownLog`](Interface.RolldownLog.md) | (() => `string` | [`RolldownLog`](Interface.RolldownLog.md))
The log object or message.
The string argument is equivalent to passing an object with only the
[`message`](Interface.RolldownError.md#message) property.
#### Returns
`void`
---
---
url: /reference/Interface.ModuleInfo.md
---
# Interface: ModuleInfo
## Extends
* [`ModuleOptions`](Interface.ModuleOptions.md)
## Properties
### code
* **Type**: `string` | `null`
The source code of the module.
`null` if external or not yet available.
***
### description?
* **Type**: `string`
* **Optional**
A short, human-readable description of the module.
This is useful for virtual modules, whose ids (e.g.
`\0vite/modulepreload-polyfill.js`) do not convey their purpose on their own.
#### Example
```js
function polyfillPlugin() {
return {
name: 'vite:modulepreload-polyfill',
load: {
filter: { id: /^\0vite/modulepreload-polyfill\.js$/ },
handler(id) {
return {
code: '',
description: 'A polyfill for `link` tag with `rel="modulepreload"`',
};
}
},
};
}
```
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`description`](Interface.ModuleOptions.md#description)
***
### dynamicallyImportedIds
* **Type**: `string`\[]
The module ids dynamically imported by this module.
***
### dynamicImporters
* **Type**: `string`\[]
The ids of all modules that dynamically import this module.
***
### exports
* **Type**: `string`\[]
All exported variables
***
### id
* **Type**: `string`
The id of the module for convenience
***
### importedIds
* **Type**: `string`\[]
The module ids statically imported by this module.
***
### importers
* **Type**: `string`\[]
The ids of all modules that statically import this module.
***
### inputFormat
* **Type**: `"es"` | `"cjs"` | `"unknown"`
* **Experimental**
The detected format of the module, based on both its syntax and module definition
metadata (such as `package.json` `type` and file extensions like `.mjs`/`.cjs`/`.mts`/`.cts`).
* "esm" for ES modules (has `import`/`export` statements or is defined as ESM by module metadata)
* "cjs" for CommonJS modules (uses `module.exports`, `exports`, top-level `return`, or is defined as CommonJS by module metadata)
* "unknown" when the format could not be determined from either syntax or module definition metadata
***
### invalidate?
* **Type**: `boolean`
* **Optional**
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`invalidate`](Interface.ModuleOptions.md#invalidate)
***
### isEntry
* **Type**: `boolean`
Whether this module is a user- or plugin-defined entry point.
***
### meta
* **Type**: [`CustomPluginOptions`](Interface.CustomPluginOptions.md)
See [Custom module meta-data section](/apis/plugin-api/inter-plugin-communication#custom-module-meta-data) for more details.
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`meta`](Interface.ModuleOptions.md#meta)
***
### moduleSideEffects
* **Type**: `ModuleSideEffects`
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`moduleSideEffects`](Interface.ModuleOptions.md#modulesideeffects)
***
### packageJsonPath?
* **Type**: `string`
* **Optional**
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`packageJsonPath`](Interface.ModuleOptions.md#packagejsonpath)
---
---
url: /reference/Interface.ModuleOptions.md
---
# Interface: ModuleOptions
## Extended by
* [`ModuleInfo`](Interface.ModuleInfo.md)
* [`ResolvedId`](Interface.ResolvedId.md)
## Properties
### description?
* **Type**: `string`
* **Optional**
A short, human-readable description of the module.
This is useful for virtual modules, whose ids (e.g.
`\0vite/modulepreload-polyfill.js`) do not convey their purpose on their own.
#### Example
```js
function polyfillPlugin() {
return {
name: 'vite:modulepreload-polyfill',
load: {
filter: { id: /^\0vite/modulepreload-polyfill\.js$/ },
handler(id) {
return {
code: '',
description: 'A polyfill for `link` tag with `rel="modulepreload"`',
};
}
},
};
}
```
***
### invalidate?
* **Type**: `boolean`
* **Optional**
***
### meta
* **Type**: [`CustomPluginOptions`](Interface.CustomPluginOptions.md)
See [Custom module meta-data section](/apis/plugin-api/inter-plugin-communication#custom-module-meta-data) for more details.
***
### moduleSideEffects
* **Type**: `ModuleSideEffects`
***
### packageJsonPath?
* **Type**: `string`
* **Optional**
---
---
url: /reference/TypeAlias.ModuleType.md
---
# Type Alias: ModuleType
* **Type**: `"js"` | `"jsx"` | `"ts"` | `"tsx"` | `"json"` | `"text"` | `"base64"` | `"dataurl"` | `"binary"` | `"empty"` | `string` & { }
---
---
url: /reference/TypeAlias.ModuleTypeFilter.md
---
# Type Alias: ModuleTypeFilter
* **Type**: [`ModuleType`](TypeAlias.ModuleType.md)\[] | `FormalModuleTypeFilter`
---
---
url: /reference/Interface.NormalizedInputOptions.md
---
# Interface: NormalizedInputOptions
## Properties
### context
* **Type**: `string`
#### See
[`context`](Interface.InputOptions.md#context)
***
### cwd
* **Type**: `string`
#### See
[`cwd`](Interface.InputOptions.md#cwd)
***
### input
* **Type**: `string`\[] | `Record`<`string`, `string`>
#### See
[`input`](Interface.InputOptions.md#input)
***
### platform
* **Type**: `"node"` | `"browser"` | `"neutral"` | `undefined`
#### See
[`platform`](Interface.InputOptions.md#platform)
***
### plugins
* **Type**: [`RolldownPlugin`](TypeAlias.RolldownPlugin.md)\[]
#### See
[`plugins`](Interface.InputOptions.md#plugins)
***
### shimMissingExports
* **Type**: `boolean`
#### See
[`shimMissingExports`](Interface.InputOptions.md#shimmissingexports)
---
---
url: /reference/Interface.NormalizedOutputOptions.md
---
# Interface: NormalizedOutputOptions
## Properties
### assetFileNames
* **Type**: `string` | ((`chunkInfo`) => `string`)
#### See
[`assetFileNames`](Interface.OutputOptions.md#assetfilenames)
***
### banner
* **Type**: (`chunk`) => `string` | `Promise`<`string`>
#### Parameters
##### chunk
[`RenderedChunk`](Interface.RenderedChunk.md)
#### Returns
`string` | `Promise`<`string`>
#### See
[`banner`](Interface.OutputOptions.md#banner)
***
### chunkFileNames
* **Type**: `string` | ((`chunkInfo`) => `string`)
#### See
[`chunkFileNames`](Interface.OutputOptions.md#chunkfilenames)
***
### codeSplitting
* **Type**: `boolean`
#### See
[`codeSplitting`](Interface.OutputOptions.md#codesplitting)
***
### comments
* **Type**: `Required`<[`CommentsOptions`](Interface.CommentsOptions.md)>
#### See
[`comments`](Interface.OutputOptions.md#comments)
***
### dir
* **Type**: `string` | `undefined`
#### See
[`dir`](Interface.OutputOptions.md#dir)
***
### dynamicImportInCjs
* **Type**: `boolean`
#### See
[`dynamicImportInCjs`](Interface.OutputOptions.md#dynamicimportincjs)
***
### entryFileNames
* **Type**: `string` | ((`chunkInfo`) => `string`)
#### See
[`entryFileNames`](Interface.OutputOptions.md#entryfilenames)
***
### esModule
* **Type**: `boolean` | `"if-default-prop"`
#### See
[`esModule`](Interface.OutputOptions.md#esmodule)
***
### exports
* **Type**: `NonNullable`<`"auto"` | `"named"` | `"default"` | `"none"` | `undefined`>
#### See
[`exports`](Interface.OutputOptions.md#exports)
***
### extend
* **Type**: `boolean`
#### See
[`extend`](Interface.OutputOptions.md#extend)
***
### externalLiveBindings
* **Type**: `boolean`
#### See
[`externalLiveBindings`](Interface.OutputOptions.md#externallivebindings)
***
### file
* **Type**: `string` | `undefined`
#### See
[`file`](Interface.OutputOptions.md#file)
***
### footer
* **Type**: (`chunk`) => `string` | `Promise`<`string`>
#### Parameters
##### chunk
[`RenderedChunk`](Interface.RenderedChunk.md)
#### Returns
`string` | `Promise`<`string`>
#### See
[`footer`](Interface.OutputOptions.md#footer)
***
### format
* **Type**: [`InternalModuleFormat`](TypeAlias.InternalModuleFormat.md)
#### See
[`format`](Interface.OutputOptions.md#format)
***
### globals
* **Type**: `Record`<`string`, `string`> | ((`name`) => `string`)
#### See
[`globals`](Interface.OutputOptions.md#globals)
***
### hashCharacters
* **Type**: `"base64"` | `"base36"` | `"hex"`
#### See
[`hashCharacters`](Interface.OutputOptions.md#hashcharacters)
***
### ~~inlineDynamicImports~~
* **Type**: `boolean`
#### Deprecated
Use `codeSplitting` instead.
***
### intro
* **Type**: (`chunk`) => `string` | `Promise`<`string`>
#### Parameters
##### chunk
[`RenderedChunk`](Interface.RenderedChunk.md)
#### Returns
`string` | `Promise`<`string`>
#### See
[`intro`](Interface.OutputOptions.md#intro)
***
### ~~legalComments~~
* **Type**: `"none"` | `"inline"`
#### Deprecated
Use `comments.legal` instead.
#### See
[`legalComments`](Interface.OutputOptions.md#legalcomments)
***
### minify
* **Type**: `false` | [`MinifyOptions`](TypeAlias.MinifyOptions.md) | `"dce-only"`
#### See
[`minify`](Interface.OutputOptions.md#minify)
***
### minifyInternalExports?
* **Type**: `boolean`
* **Optional**
#### See
[`minifyInternalExports`](Interface.OutputOptions.md#minifyinternalexports)
***
### name
* **Type**: `string` | `undefined`
#### See
[`name`](Interface.OutputOptions.md#name)
***
### outro
* **Type**: (`chunk`) => `string` | `Promise`<`string`>
#### Parameters
##### chunk
[`RenderedChunk`](Interface.RenderedChunk.md)
#### Returns
`string` | `Promise`<`string`>
#### See
[`outro`](Interface.OutputOptions.md#outro)
***
### paths
* **Type**: `Record`<`string`, `string`> | `PathsFunction` | `undefined`
#### See
[`paths`](Interface.OutputOptions.md#paths)
***
### plugins
* **Type**: [`RolldownPlugin`](TypeAlias.RolldownPlugin.md)\[]
#### See
[`plugins`](Interface.OutputOptions.md#plugins)
***
### polyfillRequire
* **Type**: `boolean`
#### See
[`polyfillRequire`](Interface.OutputOptions.md#polyfillrequire)
***
### postBanner
* **Type**: (`chunk`) => `string` | `Promise`<`string`>
#### Parameters
##### chunk
[`RenderedChunk`](Interface.RenderedChunk.md)
#### Returns
`string` | `Promise`<`string`>
#### See
[`postBanner`](Interface.OutputOptions.md#postbanner)
***
### postFooter
* **Type**: (`chunk`) => `string` | `Promise`<`string`>
#### Parameters
##### chunk
[`RenderedChunk`](Interface.RenderedChunk.md)
#### Returns
`string` | `Promise`<`string`>
#### See
[`postFooter`](Interface.OutputOptions.md#postfooter)
***
### preserveModules
* **Type**: `boolean`
#### See
[`preserveModules`](Interface.OutputOptions.md#preservemodules)
***
### preserveModulesRoot?
* **Type**: `string`
* **Optional**
#### See
[`preserveModulesRoot`](Interface.OutputOptions.md#preservemodulesroot)
***
### sourcemap
* **Type**: `boolean` | `"inline"` | `"hidden"`
#### See
[`sourcemap`](Interface.OutputOptions.md#sourcemap)
***
### sourcemapBaseUrl
* **Type**: `string` | `undefined`
#### See
[`sourcemapBaseUrl`](Interface.OutputOptions.md#sourcemapbaseurl)
***
### sourcemapDebugIds
* **Type**: `boolean`
#### See
[`sourcemapDebugIds`](Interface.OutputOptions.md#sourcemapdebugids)
***
### sourcemapExcludeSources
* **Type**: `boolean`
#### See
[`sourcemapExcludeSources`](Interface.OutputOptions.md#sourcemapexcludesources)
***
### sourcemapFileNames
* **Type**: `string` | ((`chunkInfo`) => `string`) | `undefined`
#### See
[`sourcemapFileNames`](Interface.OutputOptions.md#sourcemapfilenames)
***
### sourcemapIgnoreList
* **Type**: `boolean` | `string` | `RegExp` | ((`relativeSourcePath`, `sourcemapPath`) => `boolean`) | `undefined`
#### Union Members
`boolean`
***
`string` | `RegExp`
***
##### Function
(`relativeSourcePath`, `sourcemapPath`) => `boolean`
###### Parameters
###### relativeSourcePath
`string`
The relative path from the generated `.map` file to the corresponding source file.
###### sourcemapPath
`string`
The fully resolved path of the generated sourcemap file.
###### Returns
`boolean`
***
`undefined`
#### See
[`sourcemapIgnoreList`](Interface.OutputOptions.md#sourcemapignorelist)
***
### sourcemapPathTransform
* **Type**: ((`relativeSourcePath`, `sourcemapPath`) => `string`) | `undefined`
#### Union Members
##### Function
(`relativeSourcePath`, `sourcemapPath`) => `string`
###### Parameters
###### relativeSourcePath
`string`
The relative path from the generated `.map` file to the corresponding source file.
###### sourcemapPath
`string`
The fully resolved path of the generated sourcemap file.
###### Returns
`string`
***
`undefined`
#### See
[`sourcemapPathTransform`](Interface.OutputOptions.md#sourcemappathtransform)
***
### topLevelVar?
* **Type**: `boolean`
* **Optional**
#### See
[`topLevelVar`](Interface.OutputOptions.md#toplevelvar)
***
### virtualDirname
* **Type**: `string`
#### See
[`virtualDirname`](Interface.OutputOptions.md#virtualdirname)
---
---
url: /reference/TypeAlias.ObjectHook.md
---
# Type Alias: ObjectHook\
* **Type**: `T` | { `handler`: `T`; } & { `order?`: `PluginOrder`; } & `O`
A hook in a function or an object form with additional properties.
## Type Parameters
### T
`T`
The type of the hook function.
### O
`O` = { }
Additional properties that are specific to some hooks.
## Additional Properties
### order
* Type: `"pre" | "post" | null`
If there are several plugins implementing this hook, either run this plugin first (`"pre"`), last (`"post"`), or in the user-specified position (no value or `null`).
If several plugins use `"pre"` or `"post"`, Rolldown runs them in the user-specified order. This option can be used for all plugin hooks.
#### Example
```js
export default function resolveFirst() {
return {
name: 'resolve-first',
resolveId: {
order: 'pre',
handler(source) {
if (source === 'external') {
return { id: source, external: true };
}
return null;
},
},
};
}
```
### filter
* Type: [`HookFilter`](/reference/Interface.HookFilter) | `TopLevelFilterExpression`\[] (depends on hook)
Run this plugin hook only when the specified filter returns true. This property is only available for [`resolveId`](/reference/Interface.Plugin#resolveid), [`load`](/reference/Interface.Plugin#load), [`transform`](/reference/Interface.Plugin#transform) hooks.
#### Example
```js
export default function jsxAdditionalTransform() {
return {
name: 'jsxAdditionalTransform',
transform: {
filter: {
id: '*.jsx',
code: ' here
},
},
};
}
```
### ~~sequential~~
* Type: `boolean`
#### Deprecated
This option is only for Rollup plugin compatibility. Hooks always work as `sequential: true`.
---
---
url: /reference/Interface.OutputAsset.md
---
# Interface: OutputAsset
The information about an asset in the generated bundle.
## Extends
* `ExternalMemoryHandle`
## Properties
### fileName
* **Type**: `string`
The file name of this asset.
***
### ~~name~~
* **Type**: `string` | `undefined`
#### Deprecated
Use [`names`](#names) instead.
***
### names
* **Type**: `string`\[]
***
### ~~originalFileName~~
* **Type**: `string` | `null`
#### Deprecated
Use [`originalFileNames`](#originalfilenames) instead.
***
### originalFileNames
* **Type**: `string`\[]
The list of the absolute paths to the original file of this asset.
***
### source
* **Type**: `string` | `Uint8Array`<`ArrayBufferLike`>
The content of this asset.
***
### type
* **Type**: `"asset"`
---
---
url: /reference/Interface.OutputBundle.md
---
# Interface: OutputBundle
## Indexable
> \[`fileName`: `string`]: [`OutputAsset`](Interface.OutputAsset.md) | [`OutputChunk`](Interface.OutputChunk.md)
---
---
url: /reference/Interface.OutputChunk.md
---
# Interface: OutputChunk
The information about a chunk in the generated bundle.
## Extends
* `ExternalMemoryHandle`
## Properties
### code
* **Type**: `string`
The generated code of this chunk.
***
### dynamicImports
* **Type**: `string`\[]
External modules imported dynamically by this chunk.
***
### exports
* **Type**: `string`\[]
Exported variable names from this chunk.
***
### facadeModuleId
* **Type**: `string` | `null`
The id of a module that this chunk corresponds to.
***
### fileName
* **Type**: `string`
The file name of this chunk.
***
### imports
* **Type**: `string`\[]
External modules imported statically by this chunk.
***
### isDynamicEntry
* **Type**: `boolean`
Whether this chunk is a dynamic entry point.
***
### isEntry
* **Type**: `boolean`
Whether this chunk is a static entry point.
***
### map
* **Type**: [`SourceMap`](Interface.SourceMap.md) | `null`
The source map of this chunk if present.
***
### moduleIds
* **Type**: `string`\[]
***
### modules
* **Type**: {\[`id`: `string`]: [`RenderedModule`](Interface.RenderedModule.md); }
Information about the modules included in this chunk.
#### Index Signature
\[`id`: `string`]: [`RenderedModule`](Interface.RenderedModule.md)
***
### name
* **Type**: `string`
The name of this chunk, which is used in naming patterns.
***
### preliminaryFileName
* **Type**: `string`
The preliminary file name of this chunk with hash placeholders.
***
### sourcemapFileName
* **Type**: `string` | `null`
***
### type
* **Type**: `"chunk"`
---
---
url: /reference/Interface.PartialResolvedId.md
---
# Interface: PartialResolvedId
## Extends
* `SpecifiedModuleOptions`.`Partial`<[`PartialNull`](TypeAlias.PartialNull.md)<[`ModuleOptions`](Interface.ModuleOptions.md)>>
## Properties
### description?
* **Type**: `string` | `null`
* **Optional**
A short, human-readable description of the module.
This is useful for virtual modules, whose ids (e.g.
`\0vite/modulepreload-polyfill.js`) do not convey their purpose on their own.
#### Example
```js
function polyfillPlugin() {
return {
name: 'vite:modulepreload-polyfill',
load: {
filter: { id: /^\0vite/modulepreload-polyfill\.js$/ },
handler(id) {
return {
code: '',
description: 'A polyfill for `link` tag with `rel="modulepreload"`',
};
}
},
};
}
```
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`description`](Interface.ModuleOptions.md#description)
***
### external?
* **Type**: `boolean` | `"absolute"` | `"relative"`
* **Optional**
Whether this id should be treated as external.
Relative external ids, i.e. ids starting with `./` or `../`, will not be internally
converted to an absolute id and converted back to a relative id in the output,
but are instead included in the output unchanged.
If you want relative ids to be re-normalized and deduplicated instead, return
an absolute file system location as id and choose `external: "relative"`.
* If `true`, absolute ids will be converted to relative ids based on the user's choice for the [`makeAbsoluteExternalsRelative`](Interface.InputOptions.md#makeabsoluteexternalsrelative) option.
* If `'relative'`, absolute ids will always be converted to relative ids.
* If `'absolute'`, absolute ids will always be kept as absolute ids.
***
### id
* **Type**: `string`
***
### invalidate?
* **Type**: `boolean` | `null`
* **Optional**
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`invalidate`](Interface.ModuleOptions.md#invalidate)
***
### meta?
* **Type**: [`CustomPluginOptions`](Interface.CustomPluginOptions.md) | `null`
* **Optional**
See [Custom module meta-data section](/apis/plugin-api/inter-plugin-communication#custom-module-meta-data) for more details.
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`meta`](Interface.ModuleOptions.md#meta)
***
### moduleSideEffects?
* **Type**: `ModuleSideEffects`
* **Optional**
Indicates whether the module has side effects to Rolldown.
* If `false` is set and no other module imports anything from this module, then this module will not be included in the bundle even if the module would have side effects.
* If `true` is set, Rolldown will use its default algorithm to include all statements in the module that has side effects.
* If `"no-treeshake"` is set, treeshaking will be disabled for this module, and this module will be included in one of the chunks even if it is empty.
The precedence of this option is as follows (highest to lowest):
1. [`transform`](Interface.Plugin.md#transform) hook's returned `moduleSideEffects` option
2. [`load`](Interface.Plugin.md#load) hook's returned `moduleSideEffects` option
3. [`resolveId`](Interface.Plugin.md#resolveid) hook's returned `moduleSideEffects` option
4. [`treeshake.moduleSideEffects`](TypeAlias.TreeshakingOptions.md#modulesideeffects) option
5. `sideEffects` field in the `package.json` file
6. `true` (default)
#### Inherited from
`SpecifiedModuleOptions.moduleSideEffects`
***
### packageJsonPath?
* **Type**: `string` | `null`
* **Optional**
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`packageJsonPath`](Interface.ModuleOptions.md#packagejsonpath)
---
---
url: /reference/Interface.PluginContextMeta.md
---
# Interface: PluginContextMeta
## Properties
### rolldownVersion
* **Type**: `string`
The currently running version of Rolldown.
#### Example
```ts
`'1.0.0'`
```
***
### rollupVersion
* **Type**: `string`
A property for Rollup compatibility. A dummy value is set by Rolldown.
#### Example
```ts
`'4.23.0'`
```
***
### watchMode
* **Type**: `boolean`
Whether Rolldown was started via [`rolldown.watch()`](Function.watch.md) or
from the command line with `--watch`.
---
---
url: /reference/Interface.PluginContextResolveOptions.md
---
# Interface: PluginContextResolveOptions
## Properties
### custom?
* **Type**: [`CustomPluginOptions`](Interface.CustomPluginOptions.md)
* **Optional**
Plugin-specific options.
See [Custom resolver options section](/apis/plugin-api/inter-plugin-communication#custom-resolver-options) for more details.
***
### isEntry?
* **Type**: `boolean`
* **Optional**
The value for [`isEntry`](Interface.ResolveIdExtraOptions.md#isentry) passed to
[`resolveId`](Interface.Plugin.md#resolveid) hooks.
#### Default
`false` if there's an importer, `true` otherwise.
***
### kind?
* **Type**: `"import-statement"` | `"dynamic-import"` | `"require-call"` | `"import-rule"` | `"url-token"` | `"new-url"` | `"hot-accept"`
* **Optional**
The value for [`kind`](Interface.ResolveIdExtraOptions.md#kind) passed to
[`resolveId`](Interface.Plugin.md#resolveid) hooks.
***
### skipSelf?
* **Type**: `boolean`
* **Optional**
Whether the [`resolveId`](Interface.Plugin.md#resolveid) hook of the plugin from
which [`this.resolve`](Interface.PluginContext.md#resolve) is called will be skipped
when resolving.
When other plugins themselves also call `this.resolve` in their `resolveId` hooks with the exact same `source` and `importer` while handling the original `this.resolve` call, then the `resolveId` hook of the original plugin will be skipped for those calls as well. The rationale here is that the plugin already stated that it "does not know" how to resolve this particular combination of source and importer at this point in time. If you do not want this behavior, set `skipSelf` to `false` and implement your own infinite loop prevention mechanism if necessary.
#### Default
```ts
true
```
---
---
url: /reference/Interface.PluginMeta.md
---
# Interface: PluginMeta
Descriptive metadata a plugin can expose about itself.
Set it via the [`meta`](Interface.Plugin.md#meta) property of the plugin object.
## Properties
### description?
* **Type**: `string`
* **Optional**
A short, human-readable description of what the plugin does.
***
### packageName?
* **Type**: `string`
* **Optional**
The name of the npm package the plugin ships in, e.g. `@vitejs/plugin-vue`.
***
### version?
* **Type**: `string`
* **Optional**
The version of the npm package the plugin ships in, e.g. `5.0.0`. The
`version` field of that package's `package.json`.
---
---
url: /reference/Interface.PreRenderedAsset.md
---
# Interface: PreRenderedAsset
## Properties
### ~~name?~~
* **Type**: `string`
* **Optional**
#### Deprecated
Use [`names`](#names) instead.
***
### names
* **Type**: `string`\[]
***
### ~~originalFileName?~~
* **Type**: `string`
* **Optional**
#### Deprecated
Use [`originalFileNames`](#originalfilenames) instead.
***
### originalFileNames
* **Type**: `string`\[]
The list of the absolute paths to the original file of this asset.
***
### source
* **Type**: `string` | `Uint8Array`<`ArrayBufferLike`>
The content of this asset.
***
### type
* **Type**: `"asset"`
---
---
url: /reference/Interface.RenderedChunk.md
---
# Interface: RenderedChunk
The information about the chunk being rendered.
Unlike [OutputChunk](Interface.OutputChunk.md), `code` and `map` are not set as the chunk has not been rendered yet.
All referenced chunk file names in each property that would contain hashes will contain hash placeholders instead.
## Extends
* `Omit`<`BindingRenderedChunk`, `"modules"`>
## Properties
### dynamicImports
* **Type**: `string`\[]
External modules imported dynamically by this chunk.
#### Overrides
`Omit.dynamicImports`
***
### exports
* **Type**: `string`\[]
Exported variable names from this chunk.
#### Overrides
`Omit.exports`
***
### facadeModuleId
* **Type**: `string` | `null`
The id of a module that this chunk corresponds to.
#### Overrides
`Omit.facadeModuleId`
***
### fileName
* **Type**: `string`
The preliminary file name of this chunk with hash placeholders.
#### Overrides
`Omit.fileName`
***
### imports
* **Type**: `string`\[]
External modules imported statically by this chunk.
#### Overrides
`Omit.imports`
***
### isDynamicEntry
* **Type**: `boolean`
Whether this chunk is a dynamic entry point.
#### Overrides
`Omit.isDynamicEntry`
***
### isEntry
* **Type**: `boolean`
Whether this chunk is a static entry point.
#### Overrides
`Omit.isEntry`
***
### moduleIds
* **Type**: `string`\[]
The list of ids of modules included in this chunk.
#### Overrides
`Omit.moduleIds`
***
### modules
* **Type**: {\[`id`: `string`]: [`RenderedModule`](Interface.RenderedModule.md); }
Information about the modules included in this chunk.
#### Index Signature
\[`id`: `string`]: [`RenderedModule`](Interface.RenderedModule.md)
***
### name
* **Type**: `string`
The name of this chunk, which is used in naming patterns.
#### Overrides
`Omit.name`
***
### type
* **Type**: `"chunk"`
---
---
url: /reference/Interface.RenderedModule.md
---
# Interface: RenderedModule
## Properties
### code
* **Type**: `string` | `null`
The rendered code of this module.
The unused variables and functions are removed.
***
### renderedExports
* **Type**: `string`\[]
The list of exported names from this module.
The names that are not used are not included.
***
### renderedLength
* **Type**: `number`
The length of the rendered code of this module.
---
---
url: /reference/Interface.ResolvedId.md
---
# Interface: ResolvedId
## Extends
* [`ModuleOptions`](Interface.ModuleOptions.md)
## Properties
### description?
* **Type**: `string`
* **Optional**
A short, human-readable description of the module.
This is useful for virtual modules, whose ids (e.g.
`\0vite/modulepreload-polyfill.js`) do not convey their purpose on their own.
#### Example
```js
function polyfillPlugin() {
return {
name: 'vite:modulepreload-polyfill',
load: {
filter: { id: /^\0vite/modulepreload-polyfill\.js$/ },
handler(id) {
return {
code: '',
description: 'A polyfill for `link` tag with `rel="modulepreload"`',
};
}
},
};
}
```
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`description`](Interface.ModuleOptions.md#description)
***
### external
* **Type**: `boolean` | `"absolute"`
***
### id
* **Type**: `string`
***
### invalidate?
* **Type**: `boolean`
* **Optional**
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`invalidate`](Interface.ModuleOptions.md#invalidate)
***
### meta
* **Type**: [`CustomPluginOptions`](Interface.CustomPluginOptions.md)
See [Custom module meta-data section](/apis/plugin-api/inter-plugin-communication#custom-module-meta-data) for more details.
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`meta`](Interface.ModuleOptions.md#meta)
***
### moduleSideEffects
* **Type**: `ModuleSideEffects`
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`moduleSideEffects`](Interface.ModuleOptions.md#modulesideeffects)
***
### packageJsonPath?
* **Type**: `string`
* **Optional**
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`packageJsonPath`](Interface.ModuleOptions.md#packagejsonpath)
---
---
url: /reference/Interface.ResolveFileUrlArgs.md
---
# Interface: ResolveFileUrlArgs
Argument passed to the [`resolveFileUrl`](Interface.FunctionPluginHooks.md#resolvefileurl) hook.
## Properties
### chunkId
* **Type**: `string`
The preliminary filename of the chunk containing the reference with hash placeholders.
Similar to [`chunk.fileName`](Interface.RenderedChunk.md#filename).
***
### fileName
* **Type**: `string`
The filename of the emitted file, relative to the output directory.
***
### format
* **Type**: [`InternalModuleFormat`](TypeAlias.InternalModuleFormat.md)
The rendered output format.
***
### moduleId
* **Type**: `string`
The id of the original module this file was referenced by
using the `import.meta.ROLLDOWN_FILE_URL_*` reference.
***
### referenceId
* **Type**: `string`
The reference id of this file.
***
### relativePath
* **Type**: `string`
The path of the emitted file, relative to the chunk the file is referenced from.
This path will contain no leading `./`, but may contain a leading `../`.
***
### urlId?
* **Type**: `string`
* **Optional**
* **Experimental**
The `urlId` of an `import.meta.ROLLDOWN_FILE_URL__` reference,
or `undefined` when the reference has no `urlId`.
This is a rolldown-specific extension: the Rollup-compatible
`import.meta.ROLLUP_FILE_URL_` form never carries a `urlId`.
This API may change in minor versions.
---
---
url: /reference/TypeAlias.ResolveIdResult.md
---
# Type Alias: ResolveIdResult
* **Type**: `string` | `NullValue` | `false` | [`PartialResolvedId`](Interface.PartialResolvedId.md)
---
---
url: /reference/Interface.RolldownDirectoryEntry.md
---
# Interface: RolldownDirectoryEntry
## Properties
### name
* **Type**: `string`
## Methods
### isDirectory()
* **Type**: () => `boolean`
#### Returns
`boolean`
***
### isFile()
* **Type**: () => `boolean`
#### Returns
`boolean`
***
### isSymbolicLink()
* **Type**: () => `boolean`
#### Returns
`boolean`
---
---
url: /reference/Interface.RolldownError.md
---
# Interface: RolldownError
## Extends
* [`RolldownLog`](Interface.RolldownLog.md)
## Properties
### binding?
* **Type**: `string`
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`binding`](Interface.RolldownLog.md#binding)
***
### cause?
* **Type**: `unknown`
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`cause`](Interface.RolldownLog.md#cause)
***
### code?
* **Type**: `string`
* **Optional**
The log code for this log object.
#### Example
```ts
'PLUGIN_ERROR'
```
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`code`](Interface.RolldownLog.md#code)
***
### exporter?
* **Type**: `string`
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`exporter`](Interface.RolldownLog.md#exporter)
***
### frame?
* **Type**: `string`
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`frame`](Interface.RolldownLog.md#frame)
***
### hook?
* **Type**: `string`
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`hook`](Interface.RolldownLog.md#hook)
***
### id?
* **Type**: `string`
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`id`](Interface.RolldownLog.md#id)
***
### ids?
* **Type**: `string`\[]
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`ids`](Interface.RolldownLog.md#ids)
***
### loc?
* **Type**: object with the properties below
* **Optional**
#### column
* **Type**: `number`
#### file?
* **Type**: `string`
* **Optional**
#### line
* **Type**: `number`
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`loc`](Interface.RolldownLog.md#loc)
***
### message
* **Type**: `string`
The message for this log object.
#### Example
```ts
'The "transform" hook used by the output plugin "rolldown-plugin-foo" is a build time hook and will not be run for that plugin. Either this plugin cannot be used as an output plugin, or it should have an option to configure it as an output plugin.'
```
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`message`](Interface.RolldownLog.md#message)
***
### meta?
* **Type**: `any`
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`meta`](Interface.RolldownLog.md#meta)
***
### name?
* **Type**: `string`
* **Optional**
***
### names?
* **Type**: `string`\[]
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`names`](Interface.RolldownLog.md#names)
***
### plugin?
* **Type**: `string`
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`plugin`](Interface.RolldownLog.md#plugin)
***
### pluginCode?
* **Type**: `unknown`
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`pluginCode`](Interface.RolldownLog.md#plugincode)
***
### pos?
* **Type**: `number`
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`pos`](Interface.RolldownLog.md#pos)
***
### reexporter?
* **Type**: `string`
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`reexporter`](Interface.RolldownLog.md#reexporter)
***
### stack?
* **Type**: `string`
* **Optional**
#### Overrides
[`RolldownLog`](Interface.RolldownLog.md).[`stack`](Interface.RolldownLog.md#stack)
***
### url?
* **Type**: `string`
* **Optional**
#### Inherited from
[`RolldownLog`](Interface.RolldownLog.md).[`url`](Interface.RolldownLog.md#url)
***
### watchFiles?
* **Type**: `string`\[]
* **Optional**
---
---
url: /reference/Interface.RolldownFileStats.md
---
# Interface: RolldownFileStats
## Properties
### atime
* **Type**: `Date`
***
### birthtime
* **Type**: `Date`
***
### ctime
* **Type**: `Date`
***
### mtime
* **Type**: `Date`
***
### size
* **Type**: `number`
## Methods
### isDirectory()
* **Type**: () => `boolean`
#### Returns
`boolean`
***
### isFile()
* **Type**: () => `boolean`
#### Returns
`boolean`
***
### isSymbolicLink()
* **Type**: () => `boolean`
#### Returns
`boolean`
---
---
url: /reference/Interface.RolldownFsModule.md
---
# Interface: RolldownFsModule
## Methods
### appendFile()
* **Type**: (`path`: `string`, `data`: `string` | `Uint8Array`<`ArrayBufferLike`>, `options?`: { `encoding?`: [`BufferEncoding`](TypeAlias.BufferEncoding.md) | `null`; `flag?`: `string` | `number`; `mode?`: `string` | `number`; }) => `Promise`<`void`>
#### Parameters
##### path
`string`
##### data
`string` | `Uint8Array`<`ArrayBufferLike`>
##### options?
###### encoding?
[`BufferEncoding`](TypeAlias.BufferEncoding.md) | `null`
###### flag?
`string` | `number`
###### mode?
`string` | `number`
#### Returns
`Promise`<`void`>
***
### copyFile()
* **Type**: (`source`: `string`, `destination`: `string`, `mode?`: `string` | `number`) => `Promise`<`void`>
#### Parameters
##### source
`string`
##### destination
`string`
##### mode?
`string` | `number`
#### Returns
`Promise`<`void`>
***
### lstat()
* **Type**: (`path`: `string`) => `Promise`<[`RolldownFileStats`](Interface.RolldownFileStats.md)>
#### Parameters
##### path
`string`
#### Returns
`Promise`<[`RolldownFileStats`](Interface.RolldownFileStats.md)>
***
### mkdir()
* **Type**: (`path`: `string`, `options?`: { `mode?`: `string` | `number`; `recursive?`: `boolean`; }) => `Promise`<`void`>
#### Parameters
##### path
`string`
##### options?
###### mode?
`string` | `number`
###### recursive?
`boolean`
#### Returns
`Promise`<`void`>
***
### mkdtemp()
* **Type**: (`prefix`: `string`) => `Promise`<`string`>
#### Parameters
##### prefix
`string`
#### Returns
`Promise`<`string`>
***
### readdir()
#### Call Signature
* **Type**: (`path`: `string`, `options?`: { `withFileTypes?`: `false`; }) => `Promise`<`string`\[]>
##### Parameters
###### path
`string`
###### options?
###### withFileTypes?
`false`
##### Returns
`Promise`<`string`\[]>
#### Call Signature
* **Type**: (`path`: `string`, `options?`: { `withFileTypes`: `true`; }) => `Promise`<[`RolldownDirectoryEntry`](Interface.RolldownDirectoryEntry.md)\[]>
##### Parameters
###### path
`string`
###### options?
###### withFileTypes
`true`
##### Returns
`Promise`<[`RolldownDirectoryEntry`](Interface.RolldownDirectoryEntry.md)\[]>
***
### readFile()
#### Call Signature
* **Type**: (`path`: `string`, `options?`: { `encoding?`: `null`; `flag?`: `string` | `number`; `signal?`: `AbortSignal`; }) => `Promise`<`Uint8Array`<`ArrayBufferLike`>>
##### Parameters
###### path
`string`
###### options?
###### encoding?
`null`
###### flag?
`string` | `number`
###### signal?
`AbortSignal`
##### Returns
`Promise`<`Uint8Array`<`ArrayBufferLike`>>
#### Call Signature
* **Type**: (`path`: `string`, `options?`: { `encoding`: [`BufferEncoding`](TypeAlias.BufferEncoding.md); `flag?`: `string` | `number`; `signal?`: `AbortSignal`; }) => `Promise`<`string`>
##### Parameters
###### path
`string`
###### options?
###### encoding
[`BufferEncoding`](TypeAlias.BufferEncoding.md)
###### flag?
`string` | `number`
###### signal?
`AbortSignal`
##### Returns
`Promise`<`string`>
***
### realpath()
* **Type**: (`path`: `string`) => `Promise`<`string`>
#### Parameters
##### path
`string`
#### Returns
`Promise`<`string`>
***
### rename()
* **Type**: (`oldPath`: `string`, `newPath`: `string`) => `Promise`<`void`>
#### Parameters
##### oldPath
`string`
##### newPath
`string`
#### Returns
`Promise`<`void`>
***
### rmdir()
* **Type**: (`path`: `string`, `options?`: { `recursive?`: `boolean`; }) => `Promise`<`void`>
#### Parameters
##### path
`string`
##### options?
###### recursive?
`boolean`
#### Returns
`Promise`<`void`>
***
### stat()
* **Type**: (`path`: `string`) => `Promise`<[`RolldownFileStats`](Interface.RolldownFileStats.md)>
#### Parameters
##### path
`string`
#### Returns
`Promise`<[`RolldownFileStats`](Interface.RolldownFileStats.md)>
***
### unlink()
* **Type**: (`path`: `string`) => `Promise`<`void`>
#### Parameters
##### path
`string`
#### Returns
`Promise`<`void`>
***
### writeFile()
* **Type**: (`path`: `string`, `data`: `string` | `Uint8Array`<`ArrayBufferLike`>, `options?`: { `encoding?`: [`BufferEncoding`](TypeAlias.BufferEncoding.md) | `null`; `flag?`: `string` | `number`; `mode?`: `string` | `number`; }) => `Promise`<`void`>
#### Parameters
##### path
`string`
##### data
`string` | `Uint8Array`<`ArrayBufferLike`>
##### options?
###### encoding?
[`BufferEncoding`](TypeAlias.BufferEncoding.md) | `null`
###### flag?
`string` | `number`
###### mode?
`string` | `number`
#### Returns
`Promise`<`void`>
---
---
url: /reference/Interface.SourceDescription.md
---
# Interface: SourceDescription
## Extends
* `SpecifiedModuleOptions`.`Partial`<[`PartialNull`](TypeAlias.PartialNull.md)<[`ModuleOptions`](Interface.ModuleOptions.md)>>
## Properties
### code
* **Type**: `string`
***
### description?
* **Type**: `string` | `null`
* **Optional**
A short, human-readable description of the module.
This is useful for virtual modules, whose ids (e.g.
`\0vite/modulepreload-polyfill.js`) do not convey their purpose on their own.
#### Example
```js
function polyfillPlugin() {
return {
name: 'vite:modulepreload-polyfill',
load: {
filter: { id: /^\0vite/modulepreload-polyfill\.js$/ },
handler(id) {
return {
code: '',
description: 'A polyfill for `link` tag with `rel="modulepreload"`',
};
}
},
};
}
```
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`description`](Interface.ModuleOptions.md#description)
***
### invalidate?
* **Type**: `boolean` | `null`
* **Optional**
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`invalidate`](Interface.ModuleOptions.md#invalidate)
***
### map?
* **Type**: `null` | `string` | [`ExistingRawSourceMap`](Interface.ExistingRawSourceMap.md)
* **Optional**
The source map for the transformation.
If the transformation does not move code, you can preserve existing sourcemaps by setting this to `null`.
See [Source Code Transformations section](/apis/plugin-api/transformations#source-code-transformations) for more details.
***
### meta?
* **Type**: [`CustomPluginOptions`](Interface.CustomPluginOptions.md) | `null`
* **Optional**
See [Custom module meta-data section](/apis/plugin-api/inter-plugin-communication#custom-module-meta-data) for more details.
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`meta`](Interface.ModuleOptions.md#meta)
***
### moduleSideEffects?
* **Type**: `ModuleSideEffects`
* **Optional**
Indicates whether the module has side effects to Rolldown.
* If `false` is set and no other module imports anything from this module, then this module will not be included in the bundle even if the module would have side effects.
* If `true` is set, Rolldown will use its default algorithm to include all statements in the module that has side effects.
* If `"no-treeshake"` is set, treeshaking will be disabled for this module, and this module will be included in one of the chunks even if it is empty.
The precedence of this option is as follows (highest to lowest):
1. [`transform`](Interface.Plugin.md#transform) hook's returned `moduleSideEffects` option
2. [`load`](Interface.Plugin.md#load) hook's returned `moduleSideEffects` option
3. [`resolveId`](Interface.Plugin.md#resolveid) hook's returned `moduleSideEffects` option
4. [`treeshake.moduleSideEffects`](TypeAlias.TreeshakingOptions.md#modulesideeffects) option
5. `sideEffects` field in the `package.json` file
6. `true` (default)
#### Inherited from
`SpecifiedModuleOptions.moduleSideEffects`
***
### moduleType?
* **Type**: [`ModuleType`](TypeAlias.ModuleType.md)
* **Optional**
***
### packageJsonPath?
* **Type**: `string` | `null`
* **Optional**
#### Inherited from
[`ModuleOptions`](Interface.ModuleOptions.md).[`packageJsonPath`](Interface.ModuleOptions.md#packagejsonpath)
---
---
url: /reference/Interface.SourceMap.md
---
# Interface: SourceMap
## Properties
### debugId?
* **Type**: `string`
* **Optional**
***
### file
* **Type**: `string`
***
### mappings
* **Type**: `string`
***
### names
* **Type**: `string`\[]
***
### sources
* **Type**: `string`\[]
***
### sourcesContent
* **Type**: `string`\[]
***
### version
* **Type**: `number`
***
### x\_google\_ignoreList?
* **Type**: `number`\[]
* **Optional**
## Methods
### toString()
* **Type**: () => `string`
#### Returns
`string`
***
### toUrl()
* **Type**: () => `string`
#### Returns
`string`
---
---
url: /reference/TypeAlias.SourceMapInput.md
---
# Type Alias: SourceMapInput
* **Type**: [`ExistingRawSourceMap`](Interface.ExistingRawSourceMap.md) | `string` | `null`
---
---
url: /reference/Interface.TransformPluginContext.md
---
# Interface: TransformPluginContext
## Extends
* [`PluginContext`](Interface.PluginContext.md)
## Properties
### fs
* **Type**: [`RolldownFsModule`](Interface.RolldownFsModule.md)
Provides abstract access to the file system.
#### Inherited from
[`PluginContext`](Interface.PluginContext.md).[`fs`](Interface.PluginContext.md#fs)
***
### meta
* **Type**: [`PluginContextMeta`](Interface.PluginContextMeta.md)
An object containing potentially useful metadata.
#### Inherited from
[`PluginContext`](Interface.PluginContext.md).[`meta`](Interface.PluginContext.md#meta)
## Methods
### getModuleInfo
* **Type**: (`moduleId`) => [`ModuleInfo`](Interface.ModuleInfo.md) | `null`
Get additional information about the module in question.
During the build, this object represents currently available information about the module which may be inaccurate before the [`buildEnd`](/reference/Interface.Plugin#buildend) hook:
* [`id`](/reference/Interface.ModuleInfo#id) will never change.
* [`code`](/reference/Interface.ModuleInfo#code), [`exports`](/reference/Interface.ModuleInfo#exports) are only available after parsing, i.e. in the [`moduleParsed`](/reference/Interface.Plugin#moduleparsed) hook or after awaiting [`this.load`](/reference/Interface.PluginContext#load). At that point, they will no longer change.
* [`isEntry`](/reference/Interface.ModuleInfo#isentry) is `true`, it will no longer change. It is however possible for modules to become entry points after they are parsed, either via [`this.emitFile`](/reference/Interface.PluginContext#emitfile) or because a plugin inspects a potential entry point via [`this.load`](/reference/Interface.PluginContext#load) in the [`resolveId`](/reference/Interface.Plugin#resolveid) hook when resolving an entry point. Therefore, it is not recommended relying on this flag in the [`transform`](/reference/Interface.Plugin#transform) hook. It will no longer change after [`buildEnd`](/reference/Interface.Plugin#buildend).
* [`importers`](/reference/Interface.ModuleInfo#importers) and [`dynamicImporters`](/reference/Interface.ModuleInfo#dynamicimporters) will start as empty arrays, which receive additional entries as new importers and are discovered. They will no longer change after [`buildEnd`](/reference/Interface.Plugin#buildend).
* [`importedIds`](/reference/Interface.ModuleInfo#importedids) and [`dynamicallyImportedIds`](/reference/Interface.ModuleInfo#dynamicallyimportedids) are available when a module has been parsed and its dependencies have been resolved. This is the case in the [`moduleParsed`](/reference/Interface.Plugin#moduleparsed) hook or after awaiting [`this.load`](/reference/Interface.PluginContext#load) with the `resolveDependencies` flag. At that point, they will no longer change.
* [`meta`](/reference/Interface.ModuleInfo#meta) and [`moduleSideEffects`](/reference/Interface.ModuleInfo#modulesideeffects) can be changed by [`load`](/reference/Interface.PluginContext#load) and [`transform`](/reference/Interface.Plugin#transform) hooks. Moreover, while most properties are read-only, these properties are writable and changes will be picked up if they occur before the [`buildEnd`](/reference/Interface.Plugin#buildend) hook is triggered. meta itself should not be overwritten, but it is ok to mutate its properties at any time to store meta information about a module. The advantage of doing this instead of keeping state in a plugin is that meta is persisted to and restored from the cache if it is used, e.g. when using watch mode from the CLI.
#### Parameters
##### moduleId
`string`
#### Returns
[`ModuleInfo`](Interface.ModuleInfo.md) | `null`
Module information for that module. `null` if the module could not be found.
#### Inherited from
[`PluginContext`](Interface.PluginContext.md).[`getModuleInfo`](Interface.PluginContext.md#getmoduleinfo)
***
### addWatchFile()
* **Type**: (`id`: `string`) => `void`
Adds additional files to be monitored in watch mode so that changes to these files will trigger rebuilds.
Note that when emitting assets that correspond to an existing file, it is recommended to set the [`originalFileName`](/reference/Interface.EmittedAsset#originalfilename) property in the [`this.emitFile`](/reference/Interface.PluginContext#emitfile) call instead as that will not only watch the file but also make the connection transparent to other plugins.
Note: Usually in watch mode to improve rebuild speed, the transform hook will only be triggered for a given module if its contents actually changed. Using `this.addWatchFile` from within the transform hook will make sure the transform hook is also reevaluated for this module if the watched file changes.
In general, it is recommended to use `this.addWatchFile` from within the hook that depends on the watched file.
#### Parameters
##### id
`string`
The path to be monitored.
This can be an absolute path to a file or directory or a path relative to the current working directory.
#### Returns
`void`
#### Inherited from
[`PluginContext`](Interface.PluginContext.md).[`addWatchFile`](Interface.PluginContext.md#addwatchfile)
***
### emitFile()
* **Type**: (`file`: [`EmittedAsset`](Interface.EmittedAsset.md) | [`EmittedChunk`](Interface.EmittedChunk.md) | [`EmittedPrebuiltChunk`](Interface.EmittedPrebuiltChunk.md)) => `string`
Emits a new file that is included in the build output.
You can emit chunks, prebuilt chunks or assets.
#### In-depth (`type: 'chunk'`)
If the `type` is `'chunk'`, this emits a new chunk with the given module `id` as entry point. This will not result in duplicate modules in the graph, instead if necessary, existing chunks will be split or a facade chunk with reexports will be created. Chunks with a specified [`fileName`](/reference/Interface.EmittedChunk#filename) will always generate separate chunks while other emitted chunks may be deduplicated with existing chunks even if the name does not match. If such a chunk is not deduplicated, the [`output.chunkFileNames`](/reference/OutputOptions.chunkFileNames) pattern will be used.
You can reference the URL of an emitted file in any code returned by a [`load`](/reference/Interface.Plugin#load) or [`transform`](/reference/Interface.Plugin#transform) plugin hook via `import.meta.ROLLDOWN_FILE_URL_referenceId` (returns a string). See [File URLs](/apis/plugin-api/file-urls) for more details and an example.
You can use [`this.getFileName(referenceId)`](/reference/Interface.PluginContext#getfilename) to determine the file name as soon as it is available. If the file name is not set explicitly, then:
* asset file names are available starting with the [`renderStart`](/reference/Interface.Plugin#renderstart) hook. For assets that are emitted later, the file name will be available immediately after emitting the asset.
* chunk file names that do not contain a hash are available as soon as chunks are created after the [`renderStart`](/reference/Interface.Plugin#renderstart) hook.
* if a chunk file name would contain a hash, using [`getFileName`](/reference/Interface.PluginContext#getfilename) in any hook before [`generateBundle`](/reference/Interface.Plugin#generatebundle) will return a name containing a placeholder instead of the actual name. If you use this file name or parts of it in a chunk you transform in [`renderChunk`](/reference/Interface.Plugin#renderchunk), Rolldown will replace the placeholder with the actual hash before [`generateBundle`](/reference/Interface.Plugin#generatebundle), making sure the hash reflects the actual content of the final generated chunk including all referenced file hashes.
#### In-depth (`type: 'prebuilt-chunk'`)
If the `type` is `'prebuilt-chunk'`, this emits a chunk with fixed contents provided by the [`code`](/reference/Interface.EmittedPrebuiltChunk#code) property.
To reference a prebuilt chunk in imports, we need to mark the "module" as external in the [`resolveId`](/reference/Interface.Plugin#resolveid) hook as prebuilt chunks are not part of the module graph. Instead, they behave like assets with chunk meta-data:
```js
function emitPrebuiltChunkPlugin() {
return {
name: 'emit-prebuilt-chunk',
resolveId: {
filter: { id: /^\.\/my-prebuilt-chunk\.js$/ },
handler(source) {
return {
id: source,
external: true,
};
},
},
buildStart() {
this.emitFile({
type: 'prebuilt-chunk',
fileName: 'my-prebuilt-chunk.js',
code: 'export const foo = "foo"',
exports: ['foo'],
});
},
};
}
```
Then you can reference the prebuilt chunk in your code by `import { foo } from './my-prebuilt-chunk.js';`.
#### In-depth (`type: 'asset'`)
If the `type` is `'asset'`, this emits an arbitrary new file with the given source as content. Assets with a specified [`fileName`](/reference/Interface.EmittedAsset#filename) will always generate separate files while other emitted assets may be deduplicated with existing assets if they have the same source even if the name does not match. If an asset without a [`fileName`](/reference/Interface.EmittedAsset#filename) is not deduplicated, the [`output.assetFileNames`](/reference/OutputOptions.assetFileNames) pattern will be used.
#### Parameters
##### file
[`EmittedAsset`](Interface.EmittedAsset.md) | [`EmittedChunk`](Interface.EmittedChunk.md) | [`EmittedPrebuiltChunk`](Interface.EmittedPrebuiltChunk.md)
#### Returns
`string`
A `referenceId` for the emitted file that can be used in various places to reference the emitted file.
#### Inherited from
[`PluginContext`](Interface.PluginContext.md).[`emitFile`](Interface.PluginContext.md#emitfile)
***
### getCombinedSourcemap()
* **Type**: () => [`SourceMap`](Interface.SourceMap.md)
Get the combined source maps of all previous plugins.
#### Returns
[`SourceMap`](Interface.SourceMap.md)
***
### getFileName()
* **Type**: (`referenceId`: `string`) => `string`
Get the file name of a chunk or asset that has been emitted via
[`this.emitFile`](Interface.PluginContext.md#emitfile).
#### Parameters
##### referenceId
`string`
#### Returns
`string`
The file name of the emitted file. Relative to [`output.dir`](Interface.OutputOptions.md#dir).
#### Inherited from
[`PluginContext`](Interface.PluginContext.md).[`getFileName`](Interface.PluginContext.md#getfilename)
***
### getModuleIds()
* **Type**: () => `IterableIterator`<`string`>
Get all module ids in the current module graph.
#### Returns
`IterableIterator`<`string`>
An iterator of module ids. It can be iterated via
```js
for (const moduleId of this.getModuleIds()) {
// ...
}
```
or converted into an array via `Array.from(this.getModuleIds())`.
#### Inherited from
[`PluginContext`](Interface.PluginContext.md).[`getModuleIds`](Interface.PluginContext.md#getmoduleids)
***
### load()
* **Type**: (`options`: { `id`: `string`; `resolveDependencies?`: `boolean`; } & `Partial`<[`PartialNull`](TypeAlias.PartialNull.md)<[`ModuleOptions`](Interface.ModuleOptions.md)>>) => `Promise`<[`ModuleInfo`](Interface.ModuleInfo.md)>
Loads and parses the module corresponding to the given id, attaching additional
meta information to the module if provided. This will trigger the same
[`load`](Interface.Plugin.md#load), [`transform`](Interface.Plugin.md#transform) and
[`moduleParsed`](Interface.Plugin.md#moduleparsed) hooks as if the module was imported
by another module.
This allows you to inspect the final content of modules before deciding how to resolve them in the [`resolveId`](/reference/Interface.Plugin#resolveid) hook and e.g. resolve to a proxy module instead. If the module becomes part of the graph later, there is no additional overhead from using this context function as the module will not be parsed again. The signature allows you to directly pass the return value of [`this.resolve`](/reference/Interface.PluginContext#resolve) to this function as long as it is neither `null` nor external.
The returned Promise will resolve once the module has been fully transformed and parsed but before any imports have been resolved. That means that the resulting [`ModuleInfo`](/reference/Interface.ModuleInfo) will have empty [`importedIds`](/reference/Interface.ModuleInfo#importedids) and [`dynamicallyImportedIds`](/reference/Interface.ModuleInfo#dynamicallyimportedids). This helps to avoid deadlock situations when awaiting `this.load` in a [`resolveId`](/reference/Interface.Plugin#resolveid) hook. If you are interested in [`importedIds`](/reference/Interface.ModuleInfo#importedids) and [`dynamicallyImportedIds`](/reference/Interface.ModuleInfo#dynamicallyimportedids), you can either implement a [`moduleParsed`](/reference/Interface.Plugin#moduleparsed) hook or pass the `resolveDependencies` flag, which will make the Promise returned by `this.load` wait until all dependency ids have been resolved.
Note that with regard to the `meta` and `moduleSideEffects` options, the same restrictions apply as for the [`resolveId`](/reference/Interface.Plugin#resolveid) hook: Their values only have an effect if the module has not been loaded yet. Thus, it is very important to use [`this.resolve`](/reference/Interface.PluginContext#resolve) first to find out if any plugins want to set special values for these options in their [`resolveId`](/reference/Interface.Plugin#resolveid) hook, and pass these options on to `this.load` if appropriate. The example below showcases how this can be handled to add a proxy module for modules containing a special code comment. Note the special handling for re-exporting the default export:
```js
export default function addProxyPlugin() {
return {
async resolveId(source, importer, options) {
if (importer?.endsWith('?proxy')) {
// Do not proxy ids used in proxies
return null;
}
// We make sure to pass on any resolveId options to
// this.resolve to get the module id
const resolution = await this.resolve(source, importer, options);
// We can only pre-load existing and non-external ids
if (resolution && !resolution.external) {
// we pass on the entire resolution information
const moduleInfo = await this.load(resolution);
if (moduleInfo.code.includes('/* use proxy */')) {
return `${resolution.id}?proxy`;
}
}
// As we already fully resolved the module, there is no reason
// to resolve it again
return resolution;
},
load: {
filter: { id: /\?proxy$/ },
handler(id) {
const importee = id.slice(0, -'?proxy'.length);
// Note that namespace reexports do not reexport default exports
let code =
`console.log('proxy for ${importee}'); ` + `export * from ${JSON.stringify(importee)};`;
// We know that while resolving the proxy, importee was
// already fully loaded and parsed, so we can rely on `exports`
if (this.getModuleInfo(importee).exports.includes('default')) {
code += `export { default } from ${JSON.stringify(importee)};`;
}
return code;
},
},
};
}
```
If the module was already loaded, `this.load` will just wait for the parsing to complete and then return its module information. If the module was not yet imported by another module, it will not automatically trigger loading other modules imported by this module. Instead, static and dynamic dependencies will only be loaded once this module has actually been imported at least once.
::: warning Deadlocks caused by awaiting `this.load` in cyclic dependencies
While it is safe to use `this.load` in a [`resolveId`](/reference/Interface.Plugin#resolveid) hook, you should be very careful when awaiting it in a [`load`](/reference/Interface.Plugin#load) or [`transform`](/reference/Interface.Plugin#transform) hook. If there are cyclic dependencies in the module graph, this can easily lead to a deadlock, so any plugin needs to manually take care to avoid waiting for `this.load` inside the [`load`](/reference/Interface.Plugin#load) or [`transform`](/reference/Interface.Plugin#transform) of the any module that is in a cycle with the loaded module.
:::
#### Parameters
##### options
{ `id`: `string`; `resolveDependencies?`: `boolean`; } & `Partial`<[`PartialNull`](TypeAlias.PartialNull.md)<[`ModuleOptions`](Interface.ModuleOptions.md)>>
#### Returns
`Promise`<[`ModuleInfo`](Interface.ModuleInfo.md)>
#### Inherited from
[`PluginContext`](Interface.PluginContext.md).[`load`](Interface.PluginContext.md#load)
***
### parse()
* **Type**: (`input`: `string`, `options?`: `ParserOptions` | `null`) => `Program`
Use Rolldown's internal parser to parse code to an [ESTree-compatible](https://github.com/estree/estree) AST.
#### Parameters
##### input
`string`
##### options?
`ParserOptions` | `null`
#### Returns
`Program`
#### Inherited from
[`PluginContext`](Interface.PluginContext.md).[`parse`](Interface.PluginContext.md#parse)
***
### resolve()
* **Type**: (`source`: `string`, `importer?`: `string`, `options?`: [`PluginContextResolveOptions`](Interface.PluginContextResolveOptions.md)) => `Promise`<[`ResolvedId`](Interface.ResolvedId.md) | `null`>
Resolve imports to module ids (i.e. file names) using the same plugins that Rolldown uses,
and determine if an import should be external.
When calling this function from a [`resolveId`](Interface.Plugin.md#resolveid) hook, you should
always check if it makes sense for you to pass along the
[options](Interface.PluginContextResolveOptions.md).
#### Parameters
##### source
`string`
##### importer?
`string`
##### options?
[`PluginContextResolveOptions`](Interface.PluginContextResolveOptions.md)
#### Returns
`Promise`<[`ResolvedId`](Interface.ResolvedId.md) | `null`>
If `Promise` is returned, the import could not be resolved by Rolldown or any plugin
but was not explicitly marked as external by the user.
If an absolute external id is returned that should remain absolute in the output either
via the
[`makeAbsoluteExternalsRelative`](Interface.InputOptions.md#makeabsoluteexternalsrelative)
option or by explicit plugin choice in the [`resolveId`](Interface.Plugin.md#resolveid) hook,
`external` will be `"absolute"` instead of `true`.
#### Inherited from
[`PluginContext`](Interface.PluginContext.md).[`resolve`](Interface.PluginContext.md#resolve)
## Logging Methods
### debug
* **Type**: (`log`, `pos?`) => `void`
Same as [`PluginContext.debug`](Interface.MinimalPluginContext.md#debug), but a `position` param can be supplied.
#### Parameters
##### log
`string` | [`RolldownLog`](Interface.RolldownLog.md) | (() => `string` | [`RolldownLog`](Interface.RolldownLog.md))
##### pos?
`number` | { `column`: `number`; `line`: `number`; }
A character index or file location which will be used to augment the log with
[`pos`](Interface.RolldownError.md#pos), [`loc`](Interface.RolldownError.md#loc) and
[`frame`](Interface.RolldownError.md#frame).
#### Returns
`void`
#### Overrides
[`PluginContext`](Interface.PluginContext.md).[`debug`](Interface.PluginContext.md#debug)
***
### info
* **Type**: (`log`, `pos?`) => `void`
Same as [`PluginContext.info`](Interface.MinimalPluginContext.md#info), but a `position` param can be supplied.
#### Parameters
##### log
`string` | [`RolldownLog`](Interface.RolldownLog.md) | (() => `string` | [`RolldownLog`](Interface.RolldownLog.md))
##### pos?
`number` | { `column`: `number`; `line`: `number`; }
A character index or file location which will be used to augment the log with
[`pos`](Interface.RolldownError.md#pos), [`loc`](Interface.RolldownError.md#loc) and
[`frame`](Interface.RolldownError.md#frame).
#### Returns
`void`
#### Overrides
[`PluginContext`](Interface.PluginContext.md).[`info`](Interface.PluginContext.md#info)
***
### warn
* **Type**: (`log`, `pos?`) => `void`
Same as [`PluginContext.warn`](Interface.MinimalPluginContext.md#warn), but a `position` param can be supplied.
#### Parameters
##### log
`string` | [`RolldownLog`](Interface.RolldownLog.md) | (() => `string` | [`RolldownLog`](Interface.RolldownLog.md))
##### pos?
`number` | { `column`: `number`; `line`: `number`; }
A character index or file location which will be used to augment the log with
[`pos`](Interface.RolldownError.md#pos), [`loc`](Interface.RolldownError.md#loc) and
[`frame`](Interface.RolldownError.md#frame).
#### Returns
`void`
#### Overrides
[`PluginContext`](Interface.PluginContext.md).[`warn`](Interface.PluginContext.md#warn)
***
### error()
* **Type**: (`e`: `string` | [`RolldownError`](Interface.RolldownError.md), `pos?`: `number` | { `column`: `number`; `line`: `number`; }) => `never`
Same as [`PluginContext.error`](Interface.MinimalPluginContext.md#error), but the `id` of the current module will
also be added and a `position` param can be supplied.
#### Parameters
##### e
`string` | [`RolldownError`](Interface.RolldownError.md)
##### pos?
`number` | { `column`: `number`; `line`: `number`; }
A character index or file location which will be used to augment the log with
[`pos`](Interface.RolldownError.md#pos), [`loc`](Interface.RolldownError.md#loc) and
[`frame`](Interface.RolldownError.md#frame).
#### Returns
`never`
#### Overrides
`PluginContext.error`
---
---
url: /reference/TypeAlias.TransformResult.md
---
# Type Alias: TransformResult
* **Type**: `NullValue` | `string` | `Omit`<[`SourceDescription`](Interface.SourceDescription.md), `"code"`> & { `code?`: `string` | [`RolldownMagicString`](Interface.RolldownMagicString.md); }
---
---
url: /reference/TypeAlias.AdvancedChunksGroup.md
---
# ~~Type Alias: AdvancedChunksGroup~~
* **Type**: [`CodeSplittingGroup`](TypeAlias.CodeSplittingGroup.md)
Alias for [`CodeSplittingGroup`](TypeAlias.CodeSplittingGroup.md). Use this type for the `codeSplitting.groups` option.
## Deprecated
Please use [`CodeSplittingGroup`](TypeAlias.CodeSplittingGroup.md) instead.
---
---
url: /reference/TypeAlias.AdvancedChunksOptions.md
---
# ~~Type Alias: AdvancedChunksOptions~~
* **Type**: [`CodeSplittingOptions`](TypeAlias.CodeSplittingOptions.md)
Alias for [`CodeSplittingOptions`](TypeAlias.CodeSplittingOptions.md). Use this type for the `codeSplitting` option.
## Deprecated
Please use [`CodeSplittingOptions`](TypeAlias.CodeSplittingOptions.md) instead.
---
---
url: /reference/TypeAlias.BuiltinModuleTag.md
---
# Type Alias: BuiltinModuleTag
* **Type**: `"$initial"`
Built-in module tag names computed by rolldown.
* `'$initial'` — the module is statically imported by at least one user-defined entry point, or is part of its static dependency chain.
---
---
url: /reference/Interface.ChunkingContext.md
---
# Interface: ChunkingContext
## Methods
### getModuleInfo()
* **Type**: (`moduleId`: `string`) => [`ModuleInfo`](Interface.ModuleInfo.md) | `null`
#### Parameters
##### moduleId
`string`
#### Returns
[`ModuleInfo`](Interface.ModuleInfo.md) | `null`
---
---
url: /reference/TypeAlias.CodeSplittingGroup.md
---
# Type Alias: CodeSplittingGroup
* **Type**: { `entriesAware?`: `boolean`; `entriesAwareMergeThreshold?`: `number`; `includeDependenciesRecursively?`: `boolean`; `maxModuleSize?`: `number`; `maxSize?`: `number`; `minModuleSize?`: `number`; `minShareCount?`: `number`; `minSize?`: `number`; `name`: `string` | [`CodeSplittingNameFunction`](TypeAlias.CodeSplittingNameFunction.md); `priority?`: `number`; `tags?`: [`BuiltinModuleTag`](TypeAlias.BuiltinModuleTag.md)\[]; `test?`: `StringOrRegExp` | ((`id`) => `boolean` | `void` | `undefined`); }
## Properties
### entriesAware?
* **Type**: `boolean`
* **Optional**
When `false` (default), all matching modules are merged into a single chunk.
Every entry that uses any of these modules must load the entire chunk — even
modules it doesn't need.
When `true`, matching modules are grouped by which entries actually import them.
Modules shared by the same set of entries go into the same chunk, while modules
shared by a different set go into a separate chunk. This way, each entry only
loads the code it actually uses.
Example: entries A, B, C all match a `"vendor"` group.
* `moduleX` is used by A, B, C
* `moduleY` is used by A, B only
With `entriesAware: false` → one `vendor.js` chunk with both modules; C loads `moduleY` unnecessarily.
With `entriesAware: true` → `vendor.js` (moduleX, loaded by all) + `vendor2.js` (moduleY, loaded by A and B only).
#### Default
```ts
false
```
***
### entriesAwareMergeThreshold?
* **Type**: `number`
* **Optional**
Size threshold in bytes for merging small `entriesAware` subgroups into the
closest neighboring subgroup.
This option only works when [`entriesAware`](#entriesaware)
is `true`. Set to `0` to disable subgroup merging.
#### Default
```ts
0
```
***
### includeDependenciesRecursively?
* **Type**: `boolean`
* **Optional**
Whether to include captured modules' dependencies.
Enabling this option reduces the chance of generating circular chunks.
If you want to disable this behavior, it's recommended to both set
* [`preserveEntrySignatures`](Interface.InputOptions.md#preserveentrysignatures): `false | 'allow-extension'`
* [`strictExecutionOrder`](Interface.OutputOptions.md#strictexecutionorder): `true`
to avoid generating invalid chunks.
#### Default
```ts
true
```
***
### maxModuleSize?
* **Type**: `number`
* **Optional**
Controls whether a module can only be captured if its size in bytes is smaller than or equal to this value.
#### Default
```ts
Infinity
```
***
### maxSize?
* **Type**: `number`
* **Optional**
If the accumulated size in bytes of the captured modules by this group is larger than this value, this group will be split into multiple groups that each has size close to this value.
#### Default
```ts
Infinity
```
***
### minModuleSize?
* **Type**: `number`
* **Optional**
Controls whether a module can only be captured if its size in bytes is larger than or equal to this value.
#### Default
```ts
0
```
***
### minShareCount?
* **Type**: `number`
* **Optional**
Controls if a module should be captured based on how many entry chunks reference it.
#### Default
```ts
1
```
***
### minSize?
* **Type**: `number`
* **Optional**
Minimum size in bytes of the desired chunk. If the accumulated size of the captured modules by this group is smaller than this value, it will be ignored. Modules in this group will fall back to the `automatic chunking` if they are not captured by any other group.
#### Default
```ts
0
```
***
### name
* **Type**: `string` | [`CodeSplittingNameFunction`](TypeAlias.CodeSplittingNameFunction.md)
Name of the group. It will be also used as the name of the chunk and replace the `[name]` placeholder in the [`output.chunkFileNames`](Interface.OutputOptions.md#chunkfilenames) option.
For example,
```js
import { defineConfig } from 'rolldown';
export default defineConfig({
output: {
codeSplitting: {
groups: [
{
name: 'libs',
test: /node_modules/,
},
],
},
},
});
```
will create a chunk named `libs-[hash].js` in the end.
It's ok to have the same name for different groups. Rolldown will deduplicate the chunk names if necessary.
#### Dynamic `name()`
If `name` is a function, it will be called with the module id as the argument. The function should return a string or `null`. If it returns `null`, the module will be ignored by this group.
Notice, each returned new name will be treated as a separate group.
For example,
```js
import { defineConfig } from 'rolldown';
export default defineConfig({
output: {
codeSplitting: {
groups: [
{
name: (moduleId) => moduleId.includes('node_modules') ? 'libs' : 'app',
minSize: 100 * 1024,
},
],
},
},
});
```
:::warning
Constraints like `minSize`, `maxSize`, etc. are applied separately for different names returned by the function.
:::
***
### priority?
* **Type**: `number`
* **Optional**
Priority of the group. Group with higher priority will be chosen first to match modules and create chunks. When converting the group to a chunk, modules of that group will be removed from other groups.
If two groups have the same priority, the group whose index is smaller will be chosen.
#### Example
```js
import { defineConfig } from 'rolldown';
export default defineConfig({
output: {
codeSplitting: {
groups: [
{
name: 'react',
test: /node_modules[\\/]react/,
priority: 2,
},
{
name: 'other-libs',
test: /node_modules/,
priority: 1,
},
],
},
},
});
```
#### Default
```ts
0
```
***
### tags?
* **Type**: [`BuiltinModuleTag`](TypeAlias.BuiltinModuleTag.md)\[]
* **Optional**
Filter modules by tags. Only modules that have **all** specified tags
are captured by this group. Combines with `test` and other filters —
a module must match all criteria.
Built-in tags: `'$initial'` (module is statically imported by a user-defined entry or part of its dependency chain).
#### See
[Manual Code Splitting](/in-depth/manual-code-splitting)
#### Example
```js
{ name: 'initial-deps', tags: ['$initial'], maxSize: 1048576 }
```
***
### test?
* **Type**: `StringOrRegExp` | ((`id`) => `boolean` | `void` | `undefined`)
* **Optional**
Controls which modules are captured in this group.
* If `test` is a string, the module whose id contains the string will be captured.
* If `test` is a regular expression, the module whose id matches the regular expression will be captured.
* If `test` is a function, modules for which `test(id)` returns `true` will be captured.
* If `test` is empty, any module will be considered as matched.
:::warning
When using regular expression, it's recommended to use `[\\/]` to match the path separator instead of `/` to avoid potential issues on Windows.
* ✅ Recommended: `/node_modules[\\/]react/`
* ❌ Not recommended: `/node_modules/react/`
:::
---
---
url: /reference/TypeAlias.CodeSplittingNameFunction.md
---
# Type Alias: CodeSplittingNameFunction
* **Type**: (`moduleId`, `ctx`) => `string` | `NullValue`
## Parameters
### moduleId
`string`
### ctx
#### getModuleInfo
## Returns
`string` | `NullValue`
---
---
url: /reference/Function.defineConfig.md
---
# Function: defineConfig()
## Call Signature
* **Type**: (`config`: [`RolldownOptions`](Interface.RolldownOptions.md)) => [`RolldownOptions`](Interface.RolldownOptions.md)
A helper to define a rolldown configuration with type hints.
### Parameters
#### config
[`RolldownOptions`](Interface.RolldownOptions.md)
### Returns
[`RolldownOptions`](Interface.RolldownOptions.md)
### Example
```js [rolldown.config.js]
import { defineConfig } from 'rolldown';
export default defineConfig({
input: 'src/main.js',
output: {
file: 'bundle.js',
},
});
```
## Call Signature
* **Type**: (`config`: [`RolldownOptions`](Interface.RolldownOptions.md)\[]) => [`RolldownOptions`](Interface.RolldownOptions.md)\[]
A helper to define a rolldown configuration with type hints.
### Parameters
#### config
[`RolldownOptions`](Interface.RolldownOptions.md)\[]
### Returns
[`RolldownOptions`](Interface.RolldownOptions.md)\[]
### Example
```js [rolldown.config.js]
import { defineConfig } from 'rolldown';
export default defineConfig({
input: 'src/main.js',
output: {
file: 'bundle.js',
},
});
```
## Call Signature
* **Type**: (`config`: [`RolldownOptionsFunction`](TypeAlias.RolldownOptionsFunction.md)) => [`RolldownOptionsFunction`](TypeAlias.RolldownOptionsFunction.md)
A helper to define a rolldown configuration with type hints.
### Parameters
#### config
[`RolldownOptionsFunction`](TypeAlias.RolldownOptionsFunction.md)
### Returns
[`RolldownOptionsFunction`](TypeAlias.RolldownOptionsFunction.md)
### Example
```js [rolldown.config.js]
import { defineConfig } from 'rolldown';
export default defineConfig({
input: 'src/main.js',
output: {
file: 'bundle.js',
},
});
```
## Call Signature
* **Type**: (`config`: [`ConfigExport`](TypeAlias.ConfigExport.md)) => [`ConfigExport`](TypeAlias.ConfigExport.md)
A helper to define a rolldown configuration with type hints.
### Parameters
#### config
[`ConfigExport`](TypeAlias.ConfigExport.md)
### Returns
[`ConfigExport`](TypeAlias.ConfigExport.md)
### Example
```js [rolldown.config.js]
import { defineConfig } from 'rolldown';
export default defineConfig({
input: 'src/main.js',
output: {
file: 'bundle.js',
},
});
```
---
---
url: /reference/TypeAlias.ConfigExport.md
---
# Type Alias: ConfigExport
* **Type**: [`RolldownOptions`](Interface.RolldownOptions.md) | [`RolldownOptions`](Interface.RolldownOptions.md)\[] | [`RolldownOptionsFunction`](TypeAlias.RolldownOptionsFunction.md)
Type for `default export` of `rolldown.config.js` file.
---
---
url: /reference/Variable.getLogFilter.md
---
# Variable: getLogFilter
* **Exported from**: `rolldown/getLogFilter`
* **Type**: [`GetLogFilter`](TypeAlias.GetLogFilter.md)
A helper function to generate log filters using the same syntax as the CLI.
## Example
```ts
import { defineConfig } from 'rolldown';
import { getLogFilter } from 'rolldown/getLogFilter';
const logFilter = getLogFilter(['code:FOO', 'code:BAR']);
export default defineConfig({
input: 'main.js',
onLog(level, log, handler) {
if (logFilter(log)) {
handler(level, log);
}
}
});
```
---
---
url: /reference/TypeAlias.GetLogFilter.md
---
# Type Alias: GetLogFilter
* **Exported from**: `rolldown/getLogFilter`
* **Type**: (`filters`) => (`log`) => `boolean`
## Parameters
### filters
`string`\[]
A list of log filters to apply
## Returns
A function that tests whether a log should be output
(`log`) => `boolean`
---
---
url: /reference/Function.loadConfig.md
---
# Function: loadConfig()
* **Exported from**: `rolldown/config`
* **Type**: (`configPath`: `string`, `options`: `LoadConfigOptions`) => `Promise`<[`ConfigExport`](TypeAlias.ConfigExport.md)>
Load config from a file in a way that Rolldown does.
## Parameters
### configPath
`string`
The path to the config file. If empty, it will look for `rolldown.config` with supported extensions in the current working directory.
### options?
`LoadConfigOptions` = `{}`
Loading options. `configLoader` selects `'bundle'` (default) or `'native'`.
## Returns
`Promise`<[`ConfigExport`](TypeAlias.ConfigExport.md)>
The loaded config export
---
---
url: /reference/TypeAlias.RolldownOptionsFunction.md
---
# Type Alias: RolldownOptionsFunction
* **Type**: (`commandLineArguments`) => `MaybePromise`<[`RolldownOptions`](Interface.RolldownOptions.md) | [`RolldownOptions`](Interface.RolldownOptions.md)\[]>
## Parameters
### commandLineArguments
`Record`<`string`, `any`>
## Returns
`MaybePromise`<[`RolldownOptions`](Interface.RolldownOptions.md) | [`RolldownOptions`](Interface.RolldownOptions.md)\[]>
---
---
url: /reference/Function.withFilter.md
---
# Function: withFilter()
* **Exported from**: `rolldown/filter`
* **Type**: (`pluginOption`: `T`, `filterObject`: `OverrideFilterObject` | `OverrideFilterObject`\[]) => `T`
A helper function to add plugin hook filters to a plugin or an array of plugins.
## Type Parameters
### A
`A`
### T
`T` *extends* [`RolldownPluginOption`](TypeAlias.RolldownPluginOption.md)<`A`>
## Parameters
### pluginOption
`T`
### filterObject
`OverrideFilterObject` | `OverrideFilterObject`\[]
## Returns
`T`
## Example
```ts
import yaml from '@rollup/plugin-yaml';
import { defineConfig } from 'rolldown';
import { withFilter } from 'rolldown/filter';
export default defineConfig({
plugins: [
// Run the transform hook of the `yaml` plugin
// only for modules which end in `.yaml`
withFilter(
yaml({}),
{ transform: { id: /\.yaml$/ } },
),
],
});
```
---
---
url: /reference/Function.esmExternalRequirePlugin.md
---
# Function: esmExternalRequirePlugin()
* **Exported from**: `rolldown/plugins`
* **Type**: (`config?`: `BindingEsmExternalRequirePluginConfig`) => `BuiltinPlugin`
A plugin that converts CommonJS require() calls for external dependencies into ESM import statements.
## Parameters
### config?
`BindingEsmExternalRequirePluginConfig`
## Returns
`BuiltinPlugin`
## See
https://rolldown.rs/builtin-plugins/esm-external-require
---
---
url: /reference/Function.replacePlugin.md
---
# Function: replacePlugin()
* **Exported from**: `rolldown/plugins`
* **Type**: (`values`: `Record`<`string`, `string`>, `options`: `Omit`<`BindingReplacePluginConfig`, `"values"`>) => `BuiltinPlugin`
Replaces targeted strings in files while bundling.
## Parameters
### values?
`Record`<`string`, `string`> = `{}`
### options?
`Omit`<`BindingReplacePluginConfig`, `"values"`> = `{}`
## Returns
`BuiltinPlugin`
## Examples
**Basic usage**
```js
replacePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
__buildVersion: 15
})
```
**With options**
```js
replacePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
__buildVersion: 15
}, {
preventAssignment: false,
})
```
## See
https://rolldown.rs/builtin-plugins/replace
---
---
url: /reference/Function.minify.md
---
# Function: minify()
* **Exported from**: `rolldown/utils`
* **Type**: (`filename`: `string`, `sourceText`: `string`, `options?`: [`MinifyOptions`](Interface.MinifyOptions.md) | `null`) => `Promise`<[`MinifyResult`](Interface.MinifyResult.md)>
* **Experimental**
Minify asynchronously.
Note: This function can be slower than [`minifySync`](Function.minifySync.md) due to the overhead of spawning a thread.
## Parameters
### filename
`string`
### sourceText
`string`
### options?
[`MinifyOptions`](Interface.MinifyOptions.md) | `null`
## Returns
`Promise`<[`MinifyResult`](Interface.MinifyResult.md)>
---
---
url: /reference/Function.parse.md
---
# Function: parse()
* **Exported from**: `rolldown/utils`
* **Type**: (`filename`: `string`, `sourceText`: `string`, `options?`: [`ParserOptions`](Interface.ParserOptions.md) | `null`) => `Promise`<[`ParseResult`](Interface.ParseResult.md)>
Parse JS/TS source asynchronously on a separate thread.
Note that not all of the workload can happen on a separate thread.
Parsing on Rust side does happen in a separate thread, but deserialization of the AST to JS objects
has to happen on current thread. This synchronous deserialization work typically outweighs
the asynchronous parsing by a factor of between 3 and 20.
i.e. the majority of the workload cannot be parallelized by using this method.
Generally [`parseSync`](Function.parseSync.md) is preferable to use as it does not have the overhead of spawning a thread.
If you need to parallelize parsing multiple files, it is recommended to use worker threads.
## Parameters
### filename
`string`
### sourceText
`string`
### options?
[`ParserOptions`](Interface.ParserOptions.md) | `null`
## Returns
`Promise`<[`ParseResult`](Interface.ParseResult.md)>
---
---
url: /reference/Function.transform.md
---
# Function: transform()
* **Exported from**: `rolldown/utils`
* **Type**: (`filename`: `string`, `sourceText`: `string`, `options?`: [`TransformOptions`](Interface.TransformOptions-1.md) | `null`, `cache?`: [`TsconfigCache`](Class.TsconfigCache.md) | `null`) => `Promise`<[`TransformResult`](TypeAlias.TransformResult-1.md)>
* **Experimental**
Transpile a JavaScript or TypeScript into a target ECMAScript version, asynchronously.
Note: This function can be slower than `transformSync` due to the overhead of spawning a thread.
## Parameters
### filename
`string`
The name of the file being transformed. If this is a
relative path, consider setting the [`TransformOptions#cwd`](Interface.TransformOptions-1.md#cwd) option.
### sourceText
`string`
The source code to transform.
### options?
[`TransformOptions`](Interface.TransformOptions-1.md) | `null`
The transform options including tsconfig and inputMap. See [`TransformOptions`](Interface.TransformOptions-1.md) for more information.
### cache?
[`TsconfigCache`](Class.TsconfigCache.md) | `null`
Optional tsconfig cache for reusing resolved tsconfig across multiple transforms.
Only used when `options.tsconfig` is `true`.
## Returns
`Promise`<[`TransformResult`](TypeAlias.TransformResult-1.md)>
a promise that resolves to an object containing the transformed code,
source maps, and any errors that occurred during parsing or transformation.
---
---
url: /reference/Class.Visitor.md
---
# Class: Visitor
Visitor class for traversing AST.
## Example
```ts
import { Visitor } from 'rolldown/utils';
import { parseSync } from 'rolldown/utils';
const result = parseSync(...);
const visitor = new Visitor({
VariableDeclaration(path) {
// Do something with the variable declaration
},
"VariableDeclaration:exit"(path) {
// Do something after visiting the variable declaration
}
});
visitor.visit(result.program);
```
## Constructors
### Constructor
* **Type**: (`visitor`: `VisitorObject`) => `Visitor`
* **Experimental**
#### Parameters
##### visitor
`VisitorObject`
#### Returns
`Visitor`
## Methods
### visit()
* **Type**: (`program`: `Program`) => `void`
* **Experimental**
#### Parameters
##### program
`Program`
#### Returns
`void`
---
---
url: /reference/Interface.MinifyOptions.md
---
# Interface: MinifyOptions
Options for minification.
## Extends
* `MinifyOptions`
## Properties
### codegen?
* **Type**: `boolean` | `CodegenOptions`
* **Optional**
#### Inherited from
`OriginalMinifyOptions.codegen`
***
### compress?
* **Type**: `boolean` | `CompressOptions`
* **Optional**
#### Inherited from
`OriginalMinifyOptions.compress`
***
### inputMap?
* **Type**: `SourceMap`
* **Optional**
***
### mangle?
* **Type**: `boolean` | `MangleOptions`
* **Optional**
#### Inherited from
`OriginalMinifyOptions.mangle`
***
### module?
* **Type**: `boolean`
* **Optional**
Use when minifying an ES module.
#### Inherited from
`OriginalMinifyOptions.module`
***
### sourcemap?
* **Type**: `boolean`
* **Optional**
#### Inherited from
`OriginalMinifyOptions.sourcemap`
---
---
url: /reference/Interface.MinifyResult.md
---
# Interface: MinifyResult
The result of minification.
## Extends
* `MinifyResult`
## Properties
### code
* **Type**: `string`
#### Inherited from
`OriginalMinifyResult.code`
***
### errors
* **Type**: `OxcError`\[]
#### Inherited from
`OriginalMinifyResult.errors`
***
### legalComments
* **Type**: `string`\[]
Legal comments extracted from the source code.
Only populated when `codegen.legalComments` is `"linked"` or `"external"`.
#### Inherited from
`OriginalMinifyResult.legalComments`
***
### map?
* **Type**: `SourceMap`
* **Optional**
#### Inherited from
`OriginalMinifyResult.map`
---
---
url: /reference/Function.minifySync.md
---
# Function: minifySync()
* **Exported from**: `rolldown/utils`
* **Type**: (`filename`: `string`, `sourceText`: `string`, `options?`: [`MinifyOptions`](Interface.MinifyOptions.md) | `null`) => [`MinifyResult`](Interface.MinifyResult.md)
* **Experimental**
Minify synchronously.
## Parameters
### filename
`string`
### sourceText
`string`
### options?
[`MinifyOptions`](Interface.MinifyOptions.md) | `null`
## Returns
[`MinifyResult`](Interface.MinifyResult.md)
---
---
url: /reference/Function.parseAst.md
---
# Function: parseAst()
* **Exported from**: `rolldown/parseAst`
* **Type**: (`sourceText`: `string`, `options?`: `ParserOptions` | `null`, `filename?`: `string`) => `Program`
Parse code synchronously and return the AST.
This function is similar to Rollup's `parseAst` function.
Prefer using [`parseSync`](Function.parseSync.md) instead of this function as it has more information in the return value.
## Parameters
### sourceText
`string`
### options?
`ParserOptions` | `null`
### filename?
`string`
## Returns
`Program`
---
---
url: /reference/Function.parseAstAsync.md
---
# Function: parseAstAsync()
* **Exported from**: `rolldown/parseAst`
* **Type**: (`sourceText`: `string`, `options?`: `ParserOptions` | `null`, `filename?`: `string`) => `Promise`<`Program`>
Parse code asynchronously and return the AST.
This function is similar to Rollup's `parseAstAsync` function.
Prefer using parseAsync instead of this function as it has more information in the return value.
## Parameters
### sourceText
`string`
### options?
`ParserOptions` | `null`
### filename?
`string`
## Returns
`Promise`<`Program`>
---
---
url: /reference/Interface.ParseResult.md
---
# Interface: ParseResult
Result of parsing a code
## Extends
* `ParseResult`
## Accessors
### comments
#### Get Signature
* **Type**: () => `Comment`\[]
##### Returns
`Comment`\[]
#### Inherited from
`BindingParseResult.comments`
***
### errors
#### Get Signature
* **Type**: () => `OxcError`\[]
##### Returns
`OxcError`\[]
#### Inherited from
`BindingParseResult.errors`
***
### module
#### Get Signature
* **Type**: () => `EcmaScriptModule`
##### Returns
`EcmaScriptModule`
#### Inherited from
`BindingParseResult.module`
***
### program
#### Get Signature
* **Type**: () => `Program`
##### Returns
`Program`
#### Inherited from
`BindingParseResult.program`
---
---
url: /reference/Interface.ParserOptions.md
---
# Interface: ParserOptions
Options for parsing a code
## Extends
* `ParserOptions`
## Properties
### astType?
* **Type**: `"js"` | `"ts"`
* **Optional**
Return an AST which includes TypeScript-related properties, or excludes them.
`'js'` is default for JS / JSX files.
`'ts'` is default for TS / TSX files.
The type of the file is determined from `lang` option, or extension of provided `filename`.
#### Inherited from
`BindingParserOptions.astType`
***
### lang?
* **Type**: `"js"` | `"jsx"` | `"ts"` | `"tsx"` | `"dts"`
* **Optional**
Treat the source text as `js`, `jsx`, `ts`, `tsx` or `dts`.
#### Inherited from
`BindingParserOptions.lang`
***
### preserveParens?
* **Type**: `boolean`
* **Optional**
Emit `ParenthesizedExpression` and `TSParenthesizedType` in AST.
If this option is true, parenthesized expressions are represented by
(non-standard) `ParenthesizedExpression` and `TSParenthesizedType` nodes that
have a single `expression` property containing the expression inside parentheses.
#### Default
```ts
true
```
#### Inherited from
`BindingParserOptions.preserveParens`
***
### range?
* **Type**: `boolean`
* **Optional**
Controls whether the `range` property is included on AST nodes.
The `range` property is a `[number, number]` which indicates the start/end offsets
of the node in the file contents.
#### Default
```ts
false
```
#### Inherited from
`BindingParserOptions.range`
***
### showSemanticErrors?
* **Type**: `boolean`
* **Optional**
Produce semantic errors with an additional AST pass.
Semantic errors depend on symbols and scopes, where the parser does not construct.
This adds a small performance overhead.
#### Default
```ts
false
```
#### Inherited from
`BindingParserOptions.showSemanticErrors`
***
### sourceType?
* **Type**: `"module"` | `"commonjs"` | `"script"` | `"unambiguous"`
* **Optional**
Treat the source text as `script` or `module` code.
#### Inherited from
`BindingParserOptions.sourceType`
---
---
url: /reference/Function.parseSync.md
---
# Function: parseSync()
* **Exported from**: `rolldown/utils`
* **Type**: (`filename`: `string`, `sourceText`: `string`, `options?`: [`ParserOptions`](Interface.ParserOptions.md) | `null`) => [`ParseResult`](Interface.ParseResult.md)
Parse JS/TS source synchronously on current thread.
This is generally preferable over [`parse`](Function.parse.md) (async) as it does not have the overhead
of spawning a thread, and the majority of the workload cannot be parallelized anyway
(see [`parse`](Function.parse.md) documentation for details).
If you need to parallelize parsing multiple files, it is recommended to use worker threads
with `parseSync` rather than using [`parse`](Function.parse.md).
## Parameters
### filename
`string`
### sourceText
`string`
### options?
[`ParserOptions`](Interface.ParserOptions.md) | `null`
## Returns
[`ParseResult`](Interface.ParseResult.md)
---
---
url: /reference/TypeAlias.TransformResult-1.md
---
# Type Alias: TransformResult
* **Exported from**: `rolldown/utils`
* **Type**: `Omit`<`BindingEnhancedTransformResult`, `"errors"` | `"warnings"`> & { `errors`: `Error`\[]; `warnings`: [`RolldownLog`](Interface.RolldownLog.md)\[]; }
Result of transforming a code.
## Type Declaration
### errors
* **Type**: `Error`\[]
### warnings
* **Type**: [`RolldownLog`](Interface.RolldownLog.md)\[]
---
---
url: /reference/Function.transformSync.md
---
# Function: transformSync()
* **Exported from**: `rolldown/utils`
* **Type**: (`filename`: `string`, `sourceText`: `string`, `options?`: [`TransformOptions`](Interface.TransformOptions-1.md) | `null`, `cache?`: [`TsconfigCache`](Class.TsconfigCache.md) | `null`) => [`TransformResult`](TypeAlias.TransformResult-1.md)
* **Experimental**
Transpile a JavaScript or TypeScript into a target ECMAScript version.
## Parameters
### filename
`string`
The name of the file being transformed. If this is a
relative path, consider setting the [`TransformOptions#cwd`](Interface.TransformOptions-1.md#cwd) option.
### sourceText
`string`
The source code to transform.
### options?
[`TransformOptions`](Interface.TransformOptions-1.md) | `null`
The transform options including tsconfig and inputMap. See [`TransformOptions`](Interface.TransformOptions-1.md) for more information.
### cache?
[`TsconfigCache`](Class.TsconfigCache.md) | `null`
Optional tsconfig cache for reusing resolved tsconfig across multiple transforms.
Only used when `options.tsconfig` is `true`.
## Returns
[`TransformResult`](TypeAlias.TransformResult-1.md)
an object containing the transformed code, source maps, and any errors
that occurred during parsing or transformation.
---
---
url: /reference/Class.TsconfigCache.md
---
# Class: TsconfigCache
Cache for tsconfig resolution to avoid redundant file system operations.
The cache stores resolved tsconfig configurations keyed by their file paths.
When transforming multiple files in the same project, tsconfig lookups are
deduplicated, improving performance.
## Extends
* `TsconfigCache`
## Constructors
### Constructor
* **Type**: () => `TsconfigCache`
* **Experimental**
#### Returns
`TsconfigCache`
#### Overrides
`OriginalTsconfigCache.constructor`
## Methods
### clear()
* **Type**: () => `void`
* **Experimental**
Clear the cache.
Call this when tsconfig files have changed to ensure fresh resolution.
#### Returns
`void`
#### Inherited from
`OriginalTsconfigCache.clear`
***
### size()
* **Type**: () => `number`
* **Experimental**
Get the number of cached entries.
#### Returns
`number`
#### Inherited from
`OriginalTsconfigCache.size`
---
---
url: /reference/Interface.TsconfigCompilerOptions.md
---
# Interface: TsconfigCompilerOptions
TypeScript compiler options for inline tsconfig configuration.
## Properties
### emitDecoratorMetadata?
* **Type**: `boolean`
* **Optional**
Enables decorator metadata emission.
***
### experimentalDecorators?
* **Type**: `boolean`
* **Optional**
Enables experimental decorators.
***
### ~~importsNotUsedAsValues?~~
* **Type**: `"error"` | `"preserve"` | `"remove"`
* **Optional**
#### Deprecated
Use verbatimModuleSyntax instead.
***
### jsx?
* **Type**: `"react"` | `"react-jsx"` | `"preserve"` | `"react-jsxdev"` | `"react-native"`
* **Optional**
Specifies the JSX factory function to use.
***
### jsxFactory?
* **Type**: `string`
* **Optional**
Specifies the JSX factory function.
***
### jsxFragmentFactory?
* **Type**: `string`
* **Optional**
Specifies the JSX fragment factory function.
***
### jsxImportSource?
* **Type**: `string`
* **Optional**
Specifies the module specifier for JSX imports.
***
### ~~preserveValueImports?~~
* **Type**: `boolean`
* **Optional**
#### Deprecated
Use verbatimModuleSyntax instead.
***
### strict?
* **Type**: `boolean`
* **Optional**
Enables all strict type-checking options. Used as the fallback for `strictNullChecks`.
***
### strictNullChecks?
* **Type**: `boolean`
* **Optional**
Enables strict null checks. Controls whether `null`/`undefined` are elided from
nullable-union `design:type` decorator metadata.
***
### target?
* **Type**: `string`
* **Optional**
The ECMAScript target version.
***
### useDefineForClassFields?
* **Type**: `boolean`
* **Optional**
Configures how class fields are emitted.
***
### verbatimModuleSyntax?
* **Type**: `boolean`
* **Optional**
Preserves module structure of imports/exports.
---
---
url: /reference/Interface.TsconfigRawOptions.md
---
# Interface: TsconfigRawOptions
Raw tsconfig options for inline configuration.
## Properties
### compilerOptions?
* **Type**: [`TsconfigCompilerOptions`](Interface.TsconfigCompilerOptions.md)
* **Optional**
TypeScript compiler options.
---
---
url: /reference/TypeAlias.VisitorObject.md
---
# Type Alias: VisitorObject
* **Exported from**: `rolldown/utils`
* **Type**: `OriginalVisitorObject`
Visitor object for traversing AST.
---
---
url: /reference/TypeAlias.AddonFunction.md
---
# Type Alias: AddonFunction
* **Type**: (`chunk`) => `string` | `Promise`<`string`>
## Parameters
### chunk
[`RenderedChunk`](Interface.RenderedChunk.md)
## Returns
`string` | `Promise`<`string`>
---
---
url: /reference/Function.and.md
---
# Function: and()
* **Exported from**: `rolldown/filter`
* **Type**: (`args`: [`FilterExpression`](TypeAlias.FilterExpression.md)\[]) => `And`
## Parameters
### args
...[`FilterExpression`](TypeAlias.FilterExpression.md)\[]
## Returns
`And`
---
---
url: /reference/TypeAlias.BundleError.md
---
# Type Alias: BundleError
* **Type**: `Error` & { `errors?`: [`RolldownError`](Interface.RolldownError.md)\[]; }
The error type that is thrown by Rolldown for the whole build.
## Type Declaration
### errors?
* **Type**: [`RolldownError`](Interface.RolldownError.md)\[]
* **Optional**
The individual errors that happened during the build.
This property is a getter to avoid unnecessary expansion of error details when the error is logged.
---
---
url: /reference/TypeAlias.ChunkFileNamesFunction.md
---
# Type Alias: ChunkFileNamesFunction
* **Type**: (`chunkInfo`) => `string`
## Parameters
### chunkInfo
[`PreRenderedChunk`](Interface.PreRenderedChunk.md)
## Returns
`string`
---
---
url: /reference/Interface.ChunkOptimizationOptions.md
---
# Interface: ChunkOptimizationOptions
## Properties
### avoidRedundantChunkLoads?
* **Type**: `boolean`
* **Optional**
Avoid emitting redundant chunk loads for dynamic entries.
This pass can reduce dynamic-entry dependent chunks when the shared modules
are guaranteed to be loaded by every importer of that dynamic entry.
#### Default
```ts
true
```
***
### mergeCommonChunks?
* **Type**: `boolean`
* **Optional**
Merge common chunks into existing entry chunks when it is safe.
This can reduce the number of emitted chunks by moving shared/common modules
into an entry chunk that already depends on them. Rolldown only applies the
merge when it does not create a circular chunk dependency or change strict
entry export signatures. This pass also covers safe empty-facade cleanup.
#### Default
```ts
true
```
---
---
url: /reference/Function.code.md
---
# Function: code()
* **Exported from**: `rolldown/filter`
* **Type**: (`pattern`: `StringOrRegExp`) => `Code`
## Parameters
### pattern
`StringOrRegExp`
## Returns
`Code`
---
---
url: /reference/Function.exactRegex.md
---
# Function: exactRegex()
* **Exported from**: `rolldown/filter`
* **Type**: (`str`: `string`, `flags?`: `string`) => `RegExp`
Constructs a RegExp that matches the exact string specified.
This is useful for plugin hook filters.
## Parameters
### str
`string`
the string to match.
### flags?
`string`
flags for the RegExp.
## Returns
`RegExp`
## Example
```ts
import { exactRegex } from '@rolldown/pluginutils';
const plugin = {
name: 'plugin',
resolveId: {
filter: { id: exactRegex('foo') },
handler(id) {} // will only be called for `foo`
}
}
```
---
---
url: /reference/Function.exclude.md
---
# Function: exclude()
* **Exported from**: `rolldown/filter`
* **Type**: (`expr`: [`FilterExpression`](TypeAlias.FilterExpression.md)) => `Exclude`
## Parameters
### expr
[`FilterExpression`](TypeAlias.FilterExpression.md)
## Returns
`Exclude`
---
---
url: /reference/Function.exprInterpreter.md
---
# Function: exprInterpreter()
* **Exported from**: `rolldown/filter`
* **Type**: (`expr`: [`FilterExpression`](TypeAlias.FilterExpression.md), `code?`: `string`, `id?`: `string`, `moduleType?`: `PluginModuleType`, `importerId?`: `string`, `ctx?`: `InterpreterCtx`) => `boolean`
## Parameters
### expr
[`FilterExpression`](TypeAlias.FilterExpression.md)
### code?
`string`
### id?
`string`
### moduleType?
`PluginModuleType`
### importerId?
`string`
### ctx?
`InterpreterCtx`
## Returns
`boolean`
---
---
url: /reference/TypeAlias.ExternalOption.md
---
# Type Alias: ExternalOption
* **Type**: `StringOrRegExp` | `StringOrRegExp`\[] | [`ExternalOptionFunction`](TypeAlias.ExternalOptionFunction.md)
---
---
url: /reference/TypeAlias.ExternalOptionFunction.md
---
# Type Alias: ExternalOptionFunction
* **Type**: (`id`, `parentId`, `isResolved`) => `NullValue`<`boolean`>
## Parameters
### id
`string`
The id of the module being checked.
### parentId
`string` | `undefined`
The id of the module importing the id being checked.
### isResolved
`boolean`
Whether the id has been resolved.
## Returns
`NullValue`<`boolean`>
Whether the module should be treated as external.
---
---
url: /reference/TypeAlias.FilterExpression.md
---
# Type Alias: FilterExpression
* **Exported from**: `rolldown/filter`
* **Type**: `And` | `Or` | `Not` | `Id` | `ImporterId` | `ModuleType` | `Code` | `Query`
---
---
url: /reference/TypeAlias.FilterExpressionKind.md
---
# Type Alias: FilterExpressionKind
* **Exported from**: `rolldown/filter`
* **Type**: [`FilterExpression`](TypeAlias.FilterExpression.md)\[`"kind"`]
---
---
url: /reference/Function.filterVitePlugins.md
---
# Function: filterVitePlugins()
* **Exported from**: `rolldown/filter`
* **Type**: (`plugins`: `false` | `T` | `T`\[] | `null` | `undefined`) => `T`\[]
Filters out Vite plugins that have `apply: 'serve'` set.
Since Rolldown operates in build mode, plugins marked with `apply: 'serve'`
are intended only for Vite's dev server and should be excluded from the build process.
## Type Parameters
### T
`T` = `any`
## Parameters
### plugins
`false` | `T` | `T`\[] | `null` | `undefined`
Array of plugins (can include nested arrays)
## Returns
`T`\[]
Filtered array with serve-only plugins removed
## Example
```ts
import { defineConfig } from 'rolldown';
import { filterVitePlugins } from '@rolldown/pluginutils';
import viteReact from '@vitejs/plugin-react';
export default defineConfig({
plugins: filterVitePlugins([
viteReact(),
{
name: 'dev-only',
apply: 'serve', // This will be filtered out
// ...
}
])
});
```
---
---
url: /reference/TypeAlias.GeneratedCodePreset.md
---
# Type Alias: GeneratedCodePreset
* **Type**: `"es5"` | `"es2015"`
---
---
url: /reference/TypeAlias.GetModuleInfo.md
---
# Type Alias: GetModuleInfo
* **Type**: (`moduleId`) => [`ModuleInfo`](Interface.ModuleInfo.md) | `null`
## Parameters
### moduleId
`string`
## Returns
[`ModuleInfo`](Interface.ModuleInfo.md) | `null`
---
---
url: /reference/TypeAlias.GlobalsFunction.md
---
# Type Alias: GlobalsFunction
* **Type**: (`name`) => `string`
## Parameters
### name
`string`
## Returns
`string`
---
---
url: /reference/Function.id.md
---
# Function: id()
* **Exported from**: `rolldown/filter`
* **Type**: (`pattern`: `StringOrRegExp`, `params?`: `IdParams`) => `Id`
## Parameters
### pattern
`StringOrRegExp`
### params?
`IdParams`
## Returns
`Id`
---
---
url: /reference/Function.importerId.md
---
# Function: importerId()
* **Exported from**: `rolldown/filter`
* **Type**: (`pattern`: `StringOrRegExp`, `params?`: `IdParams`) => `ImporterId`
## Parameters
### pattern
`StringOrRegExp`
### params?
`IdParams`
## Returns
`ImporterId`
---
---
url: /reference/Function.include.md
---
# Function: include()
* **Exported from**: `rolldown/filter`
* **Type**: (`expr`: [`FilterExpression`](TypeAlias.FilterExpression.md)) => `Include`
## Parameters
### expr
[`FilterExpression`](TypeAlias.FilterExpression.md)
## Returns
`Include`
---
---
url: /reference/TypeAlias.InputOption.md
---
# Type Alias: InputOption
* **Type**: `string` | `string`\[] | `Record`<`string`, `string`>
---
---
url: /reference/Function.interpreter.md
---
# Function: interpreter()
* **Exported from**: `rolldown/filter`
* **Type**: (`exprs`: [`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md) | [`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md)\[], `code?`: `string`, `id?`: `string`, `moduleType?`: `PluginModuleType`, `importerId?`: `string`) => `boolean`
## Parameters
### exprs
[`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md) | [`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md)\[]
### code?
`string`
### id?
`string`
### moduleType?
`PluginModuleType`
### importerId?
`string`
## Returns
`boolean`
---
---
url: /reference/Function.interpreterImpl.md
---
# Function: interpreterImpl()
* **Exported from**: `rolldown/filter`
* **Type**: (`expr`: [`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md)\[], `code?`: `string`, `id?`: `string`, `moduleType?`: `PluginModuleType`, `importerId?`: `string`, `ctx?`: `InterpreterCtx`) => `boolean`
## Parameters
### expr
[`TopLevelFilterExpression`](TypeAlias.TopLevelFilterExpression.md)\[]
### code?
`string`
### id?
`string`
### moduleType?
`PluginModuleType`
### importerId?
`string`
### ctx?
`InterpreterCtx`
## Returns
`boolean`
---
---
url: /reference/TypeAlias.LoggingFunction.md
---
# Type Alias: LoggingFunction
* **Type**: (`log`) => `void`
## Parameters
### log
[`RolldownLog`](Interface.RolldownLog.md) | `string` | (() => [`RolldownLog`](Interface.RolldownLog.md) | `string`)
## Returns
`void`
---
---
url: /reference/TypeAlias.LogLevel.md
---
# Type Alias: LogLevel
* **Type**: `"info"` | `"debug"` | `"warn"`
---
---
url: /reference/TypeAlias.LogLevelOption.md
---
# Type Alias: LogLevelOption
* **Type**: `"info"` | `"debug"` | `"warn"` | `"silent"`
---
---
url: /reference/TypeAlias.LogOrStringHandler.md
---
# Type Alias: LogOrStringHandler
* **Type**: (`level`, `log`) => `void`
## Parameters
### level
`"info"` | `"debug"` | `"warn"` | `"error"`
### log
`string` | [`RolldownLog`](Interface.RolldownLog.md)
## Returns
`void`
---
---
url: /reference/Function.makeIdFiltersToMatchWithQuery.md
---
# Function: makeIdFiltersToMatchWithQuery()
## Call Signature
* **Exported from**: `rolldown/filter`
* **Type**: (`input`: `T`) => `WidenString`<`T`>
Converts a id filter to match with an id with a query.
### Type Parameters
#### T
`T` *extends* `string` | `RegExp`
### Parameters
#### input
`T`
the id filters to convert.
### Returns
`WidenString`<`T`>
### Example
```ts
import { makeIdFiltersToMatchWithQuery } from '@rolldown/pluginutils';
const plugin = {
name: 'plugin',
transform: {
filter: { id: makeIdFiltersToMatchWithQuery(['**' + '/*.js', /\.ts$/]) },
// The handler will be called for IDs like:
// - foo.js
// - foo.js?foo
// - foo.txt?foo.js
// - foo.ts
// - foo.ts?foo
// - foo.txt?foo.ts
handler(code, id) {}
}
}
```
## Call Signature
* **Exported from**: `rolldown/filter`
* **Type**: (`input`: readonly `T`\[]) => `WidenString`<`T`>\[]
Converts a id filter to match with an id with a query.
### Type Parameters
#### T
`T` *extends* `string` | `RegExp`
### Parameters
#### input
readonly `T`\[]
the id filters to convert.
### Returns
`WidenString`<`T`>\[]
### Example
```ts
import { makeIdFiltersToMatchWithQuery } from '@rolldown/pluginutils';
const plugin = {
name: 'plugin',
transform: {
filter: { id: makeIdFiltersToMatchWithQuery(['**' + '/*.js', /\.ts$/]) },
// The handler will be called for IDs like:
// - foo.js
// - foo.js?foo
// - foo.txt?foo.js
// - foo.ts
// - foo.ts?foo
// - foo.txt?foo.ts
handler(code, id) {}
}
}
```
## Call Signature
* **Exported from**: `rolldown/filter`
* **Type**: (`input`: `string` | `RegExp` | readonly (`string` | `RegExp`)\[]) => `string` | `RegExp` | (`string` | `RegExp`)\[]
Converts a id filter to match with an id with a query.
### Parameters
#### input
`string` | `RegExp` | readonly (`string` | `RegExp`)\[]
the id filters to convert.
### Returns
`string` | `RegExp` | (`string` | `RegExp`)\[]
### Example
```ts
import { makeIdFiltersToMatchWithQuery } from '@rolldown/pluginutils';
const plugin = {
name: 'plugin',
transform: {
filter: { id: makeIdFiltersToMatchWithQuery(['**' + '/*.js', /\.ts$/]) },
// The handler will be called for IDs like:
// - foo.js
// - foo.js?foo
// - foo.txt?foo.js
// - foo.ts
// - foo.ts?foo
// - foo.txt?foo.ts
handler(code, id) {}
}
}
```
---
---
url: /reference/TypeAlias.MinifyOptions.md
---
# Type Alias: MinifyOptions
* **Type**: `Omit`<`BindingMinifyOptions`, `"module"` | `"sourcemap"`>
---
---
url: /reference/TypeAlias.ModuleFormat.md
---
# Type Alias: ModuleFormat
* **Type**: `"es"` | `"cjs"` | `"esm"` | `"module"` | `"commonjs"` | `"iife"` | `"umd"`
---
---
url: /reference/Function.moduleType.md
---
# Function: moduleType()
* **Exported from**: `rolldown/filter`
* **Type**: (`pattern`: `PluginModuleType`) => `ModuleType`
## Parameters
### pattern
`PluginModuleType`
## Returns
`ModuleType`
---
---
url: /reference/TypeAlias.ModuleTypes.md
---
# Type Alias: ModuleTypes
* **Type**: `Record`<`string`, `"js"` | `"jsx"` | `"ts"` | `"tsx"` | `"json"` | `"text"` | `"base64"` | `"dataurl"` | `"binary"` | `"empty"` | `"css"` | `"asset"` | `"copy"`>
---
---
url: /reference/Function.not.md
---
# Function: not()
* **Exported from**: `rolldown/filter`
* **Type**: (`expr`: [`FilterExpression`](TypeAlias.FilterExpression.md)) => `Not`
## Parameters
### expr
[`FilterExpression`](TypeAlias.FilterExpression.md)
## Returns
`Not`
---
---
url: /reference/Function.or.md
---
# Function: or()
* **Exported from**: `rolldown/filter`
* **Type**: (`args`: [`FilterExpression`](TypeAlias.FilterExpression.md)\[]) => `Or`
## Parameters
### args
...[`FilterExpression`](TypeAlias.FilterExpression.md)\[]
## Returns
`Or`
---
---
url: /reference/TypeAlias.PartialNull.md
---
# Type Alias: PartialNull\
* **Type**: { \[P in keyof T]: T\[P] | null }
## Type Parameters
### T
`T`
---
---
url: /reference/Function.prefixRegex.md
---
# Function: prefixRegex()
* **Exported from**: `rolldown/filter`
* **Type**: (`str`: `string`, `flags?`: `string`) => `RegExp`
Constructs a RegExp that matches a value that has the specified prefix.
This is useful for plugin hook filters.
## Parameters
### str
`string`
the string to match.
### flags?
`string`
flags for the RegExp.
## Returns
`RegExp`
## Example
```ts
import { prefixRegex } from '@rolldown/pluginutils';
const plugin = {
name: 'plugin',
resolveId: {
filter: { id: prefixRegex('foo') },
handler(id) {} // will only be called for IDs starting with `foo`
}
}
```
---
---
url: /reference/Interface.PreRenderedChunk.md
---
# Interface: PreRenderedChunk
## Properties
### exports
* **Type**: `string`\[]
Exported variable names from this chunk.
***
### facadeModuleId?
* **Type**: `string`
* **Optional**
The id of a module that this chunk corresponds to.
***
### isDynamicEntry
* **Type**: `boolean`
Whether this chunk is a dynamic entry point.
***
### isEntry
* **Type**: `boolean`
Whether this chunk is a static entry point.
***
### moduleIds
* **Type**: `string`\[]
The list of ids of modules included in this chunk.
***
### name
* **Type**: `string`
The name of this chunk, which is used in naming patterns.
---
---
url: /reference/Function.queries.md
---
# Function: queries()
* **Exported from**: `rolldown/filter`
* **Type**: (`queryFilter`: [`QueryFilterObject`](Interface.QueryFilterObject.md)) => `And`
convert a queryObject to FilterExpression like
```js
and(query(k1, v1), query(k2, v2))
```
## Parameters
### queryFilter
[`QueryFilterObject`](Interface.QueryFilterObject.md)
## Returns
`And`
a `And` FilterExpression
---
---
url: /reference/Function.query.md
---
# Function: query()
* **Exported from**: `rolldown/filter`
* **Type**: (`key`: `string`, `pattern`: `boolean` | `StringOrRegExp`) => `Query`
## Parameters
### key
`string`
### pattern
`boolean` | `StringOrRegExp`
## Returns
`Query`
---
---
url: /reference/Interface.QueryFilterObject.md
---
# Interface: QueryFilterObject
## Indexable
> \[`key`: `string`]: `boolean` | `StringOrRegExp`
---
---
url: /reference/Interface.ResolveIdExtraOptions.md
---
# Interface: ResolveIdExtraOptions
## Properties
### custom?
* **Type**: [`CustomPluginOptions`](Interface.CustomPluginOptions.md)
* **Optional**
Plugin-specific options.
See [Custom resolver options section](/apis/plugin-api/inter-plugin-communication#custom-resolver-options) for more details.
***
### isEntry
* **Type**: `boolean`
Whether this is resolution for an entry point.
::: details Define custom proxy modules for entry points
This can be used for instance as a mechanism to define custom proxy modules for entry points. The following plugin will proxy all entry points to inject a polyfill import.
```js
import { exactRegex } from '@rolldown/pluginutils';
// We prefix the polyfill id with \0 to tell other plugins not to try to load or
// transform it
const POLYFILL_ID = '\0polyfill';
const PROXY_SUFFIX = '?inject-polyfill-proxy';
function injectPolyfillPlugin() {
return {
name: 'inject-polyfill',
async resolveId(source, importer, options) {
if (source === POLYFILL_ID) {
// It is important that side effects are always respected for polyfills,
// otherwise using `treeshake.moduleSideEffects: false` may prevent the
// polyfill from being included.
return { id: POLYFILL_ID, moduleSideEffects: true };
}
if (options.isEntry) {
// Determine what the actual entry would have been.
const resolution = await this.resolve(source, importer, options);
// If it cannot be resolved or is external, just return it so that Rolldown
// can display an error
if (!resolution || resolution.external) return resolution;
// In the load hook of the proxy, we need to know if the entry has a
// default export. There, however, we no longer have the full "resolution"
// object that may contain meta-data from other plugins that is only added
// on first load. Therefore we trigger loading here.
const moduleInfo = await this.load(resolution);
// We need to make sure side effects in the original entry point are
// respected even for `treeshake.moduleSideEffects: false`. "moduleSideEffects"
// is a writable property on ModuleInfo.
moduleInfo.moduleSideEffects = true;
// It is important that the new entry does not start with `\0` and has the same
// directory as the original one to not mess up relative external import generation.
// Also keeping the name and just adding a "?query" to the end ensures that
// `preserveModules` will generate the original entry name for this entry.
return `${resolution.id}${PROXY_SUFFIX}`;
}
return null;
},
load: {
filter: { id: [exactRegex(POLYFILL_ID), /\?proxy$/] },
handler(id) {
if (id === POLYFILL_ID) {
// Replace with actual polyfill
return "console.log('polyfill');";
}
if (id.endsWith(PROXY_SUFFIX)) {
const entryId = id.slice(0, -PROXY_SUFFIX.length);
// We know ModuleInfo.exports is reliable because we awaited this.load in resolveId
const { exports } = this.getModuleInfo(entryId);
let code =
`import ${JSON.stringify(POLYFILL_ID)};` + `export * from ${JSON.stringify(entryId)};`;
// Namespace reexports do not reexport default, so we need special handling here
if (exports.includes('default')) {
code += `export { default } from ${JSON.stringify(entryId)};`;
}
return code;
}
return null;
},
},
};
}
```
:::
***
### kind
* **Type**: `"import-statement"` | `"dynamic-import"` | `"require-call"` | `"import-rule"` | `"url-token"` | `"new-url"` | `"hot-accept"`
The kind of import being resolved.
* `import-statement`: `import { foo } from './lib.js';`
* `dynamic-import`: `import('./lib.js')`
* `require-call`: `require('./lib.js')`
* `import-rule`: `@import 'bg-color.css'` (experimental)
* `url-token`: `url('./icon.png')` (experimental)
* `new-url`: `new URL('./worker.js', import.meta.url)` (experimental)
* `hot-accept`: `import.meta.hot.accept('./lib.js', () => {})` (experimental)
---
---
url: /reference/Interface.RolldownLog.md
---
# Interface: RolldownLog
## Extended by
* [`RolldownError`](Interface.RolldownError.md)
## Properties
### binding?
* **Type**: `string`
* **Optional**
***
### cause?
* **Type**: `unknown`
* **Optional**
***
### code?
* **Type**: `string`
* **Optional**
The log code for this log object.
#### Example
```ts
'PLUGIN_ERROR'
```
***
### exporter?
* **Type**: `string`
* **Optional**
***
### frame?
* **Type**: `string`
* **Optional**
***
### hook?
* **Type**: `string`
* **Optional**
***
### id?
* **Type**: `string`
* **Optional**
***
### ids?
* **Type**: `string`\[]
* **Optional**
***
### loc?
* **Type**: object with the properties below
* **Optional**
#### column
* **Type**: `number`
#### file?
* **Type**: `string`
* **Optional**
#### line
* **Type**: `number`
***
### message
* **Type**: `string`
The message for this log object.
#### Example
```ts
'The "transform" hook used by the output plugin "rolldown-plugin-foo" is a build time hook and will not be run for that plugin. Either this plugin cannot be used as an output plugin, or it should have an option to configure it as an output plugin.'
```
***
### meta?
* **Type**: `any`
* **Optional**
***
### names?
* **Type**: `string`\[]
* **Optional**
***
### plugin?
* **Type**: `string`
* **Optional**
***
### pluginCode?
* **Type**: `unknown`
* **Optional**
***
### pos?
* **Type**: `number`
* **Optional**
***
### reexporter?
* **Type**: `string`
* **Optional**
***
### stack?
* **Type**: `string`
* **Optional**
***
### url?
* **Type**: `string`
* **Optional**
---
---
url: /reference/TypeAlias.RolldownLogWithString.md
---
# Type Alias: RolldownLogWithString
* **Type**: [`RolldownLog`](Interface.RolldownLog.md) | `string`
---
---
url: /reference/Interface.RolldownMagicString.md
---
# Interface: RolldownMagicString
## Extends
* `BindingMagicString`
## Properties
### isRolldownMagicString
* **Type**: `true`
## Accessors
### filename
#### Get Signature
* **Type**: () => `string` | `null`
##### Returns
`string` | `null`
#### Inherited from
`NativeBindingMagicString.filename`
***
### ignoreList
#### Get Signature
* **Type**: () => `boolean`
##### Returns
`boolean`
#### Inherited from
`NativeBindingMagicString.ignoreList`
***
### indentExclusionRanges
#### Get Signature
* **Type**: () => `number`\[] | `number`\[]\[] | `null`
##### Returns
`number`\[] | `number`\[]\[] | `null`
#### Inherited from
`NativeBindingMagicString.indentExclusionRanges`
***
### offset
#### Get Signature
* **Type**: () => `number`
##### Returns
`number`
#### Set Signature
* **Type**: (`offset`: `number`) => `void`
##### Parameters
###### offset
`number`
##### Returns
`void`
#### Inherited from
`NativeBindingMagicString.offset`
***
### original
#### Get Signature
* **Type**: () => `string`
##### Returns
`string`
#### Inherited from
`NativeBindingMagicString.original`
## Methods
### append()
* **Type**: (`content`: `string`) => `this`
#### Parameters
##### content
`string`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.append`
***
### appendLeft()
* **Type**: (`index`: `number`, `content`: `string`) => `this`
#### Parameters
##### index
`number`
##### content
`string`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.appendLeft`
***
### appendRight()
* **Type**: (`index`: `number`, `content`: `string`) => `this`
#### Parameters
##### index
`number`
##### content
`string`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.appendRight`
***
### clone()
* **Type**: () => `BindingMagicString`
Returns a clone of the MagicString instance.
#### Returns
`BindingMagicString`
#### Inherited from
`NativeBindingMagicString.clone`
***
### generateDecodedMap()
* **Type**: (`options?`: `BindingSourceMapOptions` | `null`) => `BindingDecodedMap`
Generates a decoded source map for the transformations applied to this MagicString.
Returns a BindingDecodedMap object with mappings as an array of arrays.
#### Parameters
##### options?
`BindingSourceMapOptions` | `null`
#### Returns
`BindingDecodedMap`
#### Inherited from
`NativeBindingMagicString.generateDecodedMap`
***
### generateMap()
* **Type**: (`options?`: `BindingSourceMapOptions` | `null`) => `BindingSourceMap`
Generates a source map for the transformations applied to this MagicString.
Returns a BindingSourceMap object with version, file, sources, sourcesContent, names, mappings.
#### Parameters
##### options?
`BindingSourceMapOptions` | `null`
#### Returns
`BindingSourceMap`
#### Inherited from
`NativeBindingMagicString.generateMap`
***
### getIndentString()
* **Type**: () => `string`
Returns the guessed indentation string, or `\t` if none is found.
#### Returns
`string`
#### Inherited from
`NativeBindingMagicString.getIndentString`
***
### hasChanged()
* **Type**: () => `boolean`
#### Returns
`boolean`
#### Inherited from
`NativeBindingMagicString.hasChanged`
***
### indent()
* **Type**: (`indentor?`: `string` | `null`, `options?`: `BindingIndentOptions` | `null`) => `this`
#### Parameters
##### indentor?
`string` | `null`
##### options?
`BindingIndentOptions` | `null`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.indent`
***
### insert()
* **Type**: (`index`: `number`, `content`: `string`) => `void`
Deprecated method that throws an error directing users to use prependRight or appendLeft.
This matches the original magic-string API which deprecated this method.
#### Parameters
##### index
`number`
##### content
`string`
#### Returns
`void`
#### Inherited from
`NativeBindingMagicString.insert`
***
### isEmpty()
* **Type**: () => `boolean`
#### Returns
`boolean`
#### Inherited from
`NativeBindingMagicString.isEmpty`
***
### lastChar()
* **Type**: () => `string`
Returns the last character of the generated string, or an empty string if empty.
#### Returns
`string`
#### Inherited from
`NativeBindingMagicString.lastChar`
***
### lastLine()
* **Type**: () => `string`
Returns the content after the last newline in the generated string.
#### Returns
`string`
#### Inherited from
`NativeBindingMagicString.lastLine`
***
### length()
* **Type**: () => `number`
#### Returns
`number`
#### Inherited from
`NativeBindingMagicString.length`
***
### move()
* **Type**: (`start`: `number`, `end`: `number`, `index`: `number`) => `this`
Alias for `relocate` to match the original magic-string API.
Moves the characters from `start` to `end` to `index`.
Returns `this` for method chaining.
#### Parameters
##### start
`number`
##### end
`number`
##### index
`number`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.move`
***
### overwrite()
* **Type**: (`start`: `number`, `end`: `number`, `content`: `string`, `options?`: `BindingOverwriteOptions` | `null`) => `this`
#### Parameters
##### start
`number`
##### end
`number`
##### content
`string`
##### options?
`BindingOverwriteOptions` | `null`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.overwrite`
***
### prepend()
* **Type**: (`content`: `string`) => `this`
#### Parameters
##### content
`string`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.prepend`
***
### prependLeft()
* **Type**: (`index`: `number`, `content`: `string`) => `this`
#### Parameters
##### index
`number`
##### content
`string`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.prependLeft`
***
### prependRight()
* **Type**: (`index`: `number`, `content`: `string`) => `this`
#### Parameters
##### index
`number`
##### content
`string`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.prependRight`
***
### relocate()
* **Type**: (`start`: `number`, `end`: `number`, `to`: `number`) => `this`
#### Parameters
##### start
`number`
##### end
`number`
##### to
`number`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.relocate`
***
### remove()
* **Type**: (`start`: `number`, `end`: `number`) => `this`
#### Parameters
##### start
`number`
##### end
`number`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.remove`
***
### replace()
* **Type**: (`from`: `string` | `RegExp`, `to`: `string`) => `this`
Accepts a string or RegExp pattern. RegExp supports `$&`, `$$`, and `$N` substitutions.
#### Parameters
##### from
`string` | `RegExp`
##### to
`string`
#### Returns
`this`
#### Overrides
`NativeBindingMagicString.replace`
***
### replaceAll()
* **Type**: (`from`: `string` | `RegExp`, `to`: `string`) => `this`
Accepts a string or RegExp pattern. RegExp must have the global (`g`) flag.
#### Parameters
##### from
`string` | `RegExp`
##### to
`string`
#### Returns
`this`
#### Overrides
`NativeBindingMagicString.replaceAll`
***
### replaceRegex()
* **Type**: (`from`: `RegExp`, `to`: `string`) => `number`
Returns the UTF-16 offset past the last match, or -1 if no match was found.
The JS wrapper uses this to update `lastIndex` on the caller's RegExp.
Global/sticky behavior is derived from the regex's own flags.
#### Parameters
##### from
`RegExp`
##### to
`string`
#### Returns
`number`
#### Inherited from
`NativeBindingMagicString.replaceRegex`
***
### reset()
* **Type**: (`start`: `number`, `end`: `number`) => `this`
Resets the portion of the string from `start` to `end` to its original content.
This undoes any modifications made to that range.
Supports negative indices (counting from the end).
#### Parameters
##### start
`number`
##### end
`number`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.reset`
***
### slice()
* **Type**: (`start?`: `number` | `null`, `end?`: `number` | `null`) => `string`
Returns the content between the specified UTF-16 code unit positions (JS string indices).
Supports negative indices (counting from the end).
When an index falls in the middle of a surrogate pair, the lone surrogate is
included in the result (matching the original magic-string / JS behavior).
This is done by returning a UTF-16 encoded JS string via `napi_create_string_utf16`.
#### Parameters
##### start?
`number` | `null`
##### end?
`number` | `null`
#### Returns
`string`
#### Inherited from
`NativeBindingMagicString.slice`
***
### snip()
* **Type**: (`start`: `number`, `end`: `number`) => `BindingMagicString`
Returns a clone with content outside the specified range removed.
#### Parameters
##### start
`number`
##### end
`number`
#### Returns
`BindingMagicString`
#### Inherited from
`NativeBindingMagicString.snip`
***
### toString()
* **Type**: () => `string`
#### Returns
`string`
#### Inherited from
`NativeBindingMagicString.toString`
***
### trim()
* **Type**: (`charType?`: `string` | `null`) => `this`
Trims whitespace or specified characters from the start and end.
#### Parameters
##### charType?
`string` | `null`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.trim`
***
### trimEnd()
* **Type**: (`charType?`: `string` | `null`) => `this`
Trims whitespace or specified characters from the end.
#### Parameters
##### charType?
`string` | `null`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.trimEnd`
***
### trimLines()
* **Type**: () => `this`
Trims newlines from the start and end.
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.trimLines`
***
### trimStart()
* **Type**: (`charType?`: `string` | `null`) => `this`
Trims whitespace or specified characters from the start.
#### Parameters
##### charType?
`string` | `null`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.trimStart`
***
### update()
* **Type**: (`start`: `number`, `end`: `number`, `content`: `string`, `options?`: `BindingUpdateOptions` | `null`) => `this`
#### Parameters
##### start
`number`
##### end
`number`
##### content
`string`
##### options?
`BindingUpdateOptions` | `null`
#### Returns
`this`
#### Inherited from
`NativeBindingMagicString.update`
---
---
url: /reference/Variable.RolldownMagicString.md
---
# Variable: RolldownMagicString
* **Type**: `RolldownMagicStringConstructor`
* **Experimental**
A native MagicString implementation powered by Rust.
---
---
url: /reference/Interface.RolldownOptions.md
---
# Interface: RolldownOptions
## Extends
* [`InputOptions`](Interface.InputOptions.md)
## Properties
### checks?
* **Type**: [`ChecksOptions`](Interface.ChecksOptions.md)
* **Optional**
Controls which warnings are emitted during the build process. Each option can be set to `true` (emit warning) or `false` (suppress warning).
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`checks`](Interface.InputOptions.md#checks)
***
### context?
* **Type**: `string`
* **Optional**
The value of `this` at the top level of each module. **Normally, you don't need to set this option.**
#### Default
```ts
undefined
```
#### Example
**Set custom context**
```js
export default {
context: 'globalThis',
output: {
format: 'iife',
},
};
```
#### In-depth
The `context` option controls what `this` refers to in the top-level scope of the input modules.
In ES modules, the `this` value is `undefined` by specification. This option allows you to set a different value. For example, if your input modules expect `this` to be `window` like in non-ES module scripts, you can set `context` to `'window'`.
Note that if the input module is detected as CommonJS, Rolldown will use `exports` as the `this` value regardless of this option.
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`context`](Interface.InputOptions.md#context)
***
### cwd?
* **Type**: `string`
* **Optional**
The working directory to use when resolving relative paths in the configuration.
#### Default
```ts
process.cwd()
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`cwd`](Interface.InputOptions.md#cwd)
***
### devtools?
* **Type**: object with the properties below
* **Optional**
* **Experimental**
Devtools integration options.
When enabled, Rolldown writes JSON-lines devtools output under
`node_modules/.rolldown/{session_id}/`, resolved against [`cwd`](Interface.InputOptions.md#cwd).
Consumers can parse the output with `@rolldown/debug` after
`await bundle.close()` resolves.
#### sessionId?
* **Type**: `string`
* **Optional**
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`devtools`](Interface.InputOptions.md#devtools)
***
### experimental?
* **Type**: object with the properties below
* **Optional**
* **Experimental**
Experimental features that may change in future releases and can introduce behavior change without a major version bump.
#### attachDebugInfo?
* **Type**: `"none"` | `"simple"` | `"full"`
* **Optional**
Attach debug information to the output bundle.
Available modes:
* `none`: No debug information is attached.
* `simple`: Attach comments indicating which files the bundled code comes from. These comments could be removed by the minifier.
* `full`: Attach detailed debug information to the output bundle. These comments are using legal comment syntax, so they won't be removed by the minifier.
##### Default
'simple'
##### In-depth
Each chunk will include a comment explaining the reason why it was created:
| Reason | Format | Description |
| --------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| User-defined Entry | `User-defined Entry: [Entry-Module-Id: ] [Name: Some("")]` | Explicit entry point from build config |
| Dynamic Entry | `Dynamic Entry: [Entry-Module-Id: ] [Name: None]` | Chunk created from `import()` expression |
| Common Chunk | `Common Chunk: [Shared-By: , , ...]` | Shared modules extracted for multiple entries |
| Manual Code Splitting | `ManualCodeSplitting: [Group-Name: ]` | Chunk created by [`output.codeSplitting`](/reference/OutputOptions.codeSplitting) option |
| Preserve Modules | `Enabling Preserve Module: [User-defined: ] [Module-Id: ]` | Per-module chunk from [`output.preserveModules`](/reference/OutputOptions.preserveModules) option |
When rolldown optimized away empty facade chunks (entry chunks with no modules of their own), the target chunk will include `Eliminated Facade Chunk: [Chunk-Name: ] [Entry-Module-Id: ]`.
#### chunkImportMap?
* **Type**: `boolean` | { `baseUrl?`: `string`; `fileName?`: `string`; }
* **Optional**
Enables automatic generation of a chunk import map asset during build.
This map only includes chunks with hashed filenames, where keys are derived from the facade module
name or primary chunk name. It produces stable and unique hash-based filenames, effectively preventing
cascading cache invalidation caused by content hashes and maximizing browser cache reuse.
The output defaults to `importmap.json` unless overridden via `fileName`. A base URL prefix
(default `"/"`) can be applied to all paths. The resulting JSON is a valid import map and can be
directly injected into HTML via `/i,
``
);
fs.writeFileSync(htmlPath, html);
delete bundle['importmap.json'];
}
}
}
]
}
```
> \[!TIP]
> If you want to learn more, you can check out the example here: [examples/chunk-import-map](https://github.com/rolldown/rolldown/tree/main/examples/chunk-import-map)
##### Default
```ts
false
```
#### chunkModulesOrder?
* **Type**: `"exec-order"` | `"module-id"`
* **Optional**
Control which order should be used when rendering modules in a chunk.
Available options:
* `exec-order`: Almost equivalent to the topological order of the module graph, but specially handling when module graph has cycle.
* `module-id`: This is more friendly for gzip compression, especially for some javascript static asset lib (e.g. icon library)
> \[!NOTE]
> Try to sort the modules by their module id if possible (Since rolldown scope hoist all modules in the chunk, we only try to sort those modules by module id if we could ensure runtime behavior is correct after sorting).
##### Default
```ts
'exec-order'
```
#### chunkOptimization?
* **Type**: `boolean` | [`ChunkOptimizationOptions`](Interface.ChunkOptimizationOptions.md)
* **Optional**
Control chunk optimizations.
`true` enables both common-chunk merging and redundant dynamic chunk-load avoidance.
`false` disables all chunk optimizations. Use the object form to control
`mergeCommonChunks` and `avoidRedundantChunkLoads` separately.
These optimizations are automatically disabled when any module uses top-level await (TLA) or contains TLA dependencies,
as they could affect execution order guarantees.
##### Default
```ts
true
```
#### incrementalBuild?
* **Type**: `boolean`
* **Optional**
Enable incremental build support. Required to be used with `watch` mode.
##### Default
```ts
false
```
#### lazyBarrel?
* **Type**: `boolean`
* **Optional**
Control whether to enable lazy barrel optimization.
Lazy barrel optimization avoids compiling unused re-export modules in side-effect-free barrel modules,
significantly improving build performance for large codebases with many barrel modules.
This option is planned to be removed in the future. If you need to opt out, please open an issue
describing your use case so we can address it before the option is gone.
##### See
[Lazy Barrel Documentation](/in-depth/lazy-barrel-optimization)
##### Default
```ts
false
```
#### nativeMagicString?
* **Type**: `boolean`
* **Optional**
Use native Rust implementation of MagicString for source map generation.
[MagicString](https://github.com/rich-harris/magic-string) is a JavaScript library commonly used by bundlers
for string manipulation and source map generation. When enabled, rolldown will use a native Rust
implementation of MagicString instead of the JavaScript version, providing significantly better performance
during source map generation and code transformation.
**Benefits**
* **Improved Performance**: The native Rust implementation is typically faster than the JavaScript version,
especially for large codebases with extensive source maps.
* **Background Processing**: Source map generation is performed asynchronously in a background thread,
allowing the main bundling process to continue without blocking. This parallel processing can significantly
reduce overall build times when working with JavaScript transform hooks.
* **Better Integration**: Seamless integration with rolldown's native Rust architecture.
##### Example
```js
export default {
experimental: {
nativeMagicString: true
},
output: {
sourcemap: true
}
}
```
> \[!NOTE]
> This is an experimental feature. While it aims to provide identical behavior to the JavaScript
> implementation, there may be edge cases. Please report any discrepancies you encounter.
> For a complete working example, see [examples/native-magic-string](https://github.com/rolldown/rolldown/tree/main/examples/native-magic-string)
##### Default
```ts
false
```
#### resolveNewUrlToAsset?
* **Type**: `boolean`
* **Optional**
When enabled, `new URL()` calls will be transformed to a stable asset URL which includes the updated name and content hash.
It is necessary to pass `import.meta.url` as the second argument to the
`new URL` constructor, otherwise no transform will be applied.
:::warning
JavaScript and TypeScript files referenced via `new URL('./file.js', import.meta.url)` or `new URL('./file.ts', import.meta.url)` will **not** be transformed or bundled. The file will be copied as-is, meaning TypeScript files remain untransformed and dependencies are not resolved.
The expected behavior for JS/TS files is still being discussed and may
change in future releases. See [#7258](https://github.com/rolldown/rolldown/issues/7258) for more context.
:::
##### Example
```js
// main.js
const url = new URL('./styles.css', import.meta.url);
console.log(url);
// Example output after bundling WITHOUT the option (default)
const url = new URL('./styles.css', import.meta.url);
console.log(url);
// Example output after bundling WITH `experimental.resolveNewUrlToAsset` set to `true`
const url = new URL('assets/styles-CjdrdY7X.css', import.meta.url);
console.log(url);
```
##### Default
```ts
false
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`experimental`](Interface.InputOptions.md#experimental)
***
### external?
* **Type**: `string` | `RegExp` | (`string` | `RegExp`)\[] | [`ExternalOptionFunction`](TypeAlias.ExternalOptionFunction.md)
* **Optional**
Specifies which modules should be treated as external and not bundled. External modules will be left as import statements in the output.
When creating an `iife` or `umd` bundle, you will need to provide global variable names to replace your external imports via the [`output.globals`](/reference/OutputOptions.globals) option.
#### How Matching Works
The `external` option is checked **twice** during module resolution, against two different kinds of IDs:
1. **First check — raw import specifier** (e.g. `'lodash'`, `'./utils'`) is tested before any resolution happens, with `isResolved: false`. To mark `import "dependency"` as external, use `"dependency"` exactly as written in the import statement. If it matches, the module is immediately marked as external — **plugins and the internal resolver are skipped entirely**.
2. **Second check — resolved ID** (e.g. `'/project/node_modules/vue/dist/vue.runtime.esm-bundler.js'`) is tested after plugins and the internal resolver have run, with `isResolved: true`. If it matches, the module is marked as external.
The second check only runs if the first did not match. In both cases, [`makeAbsoluteExternalsRelative`](/reference/InputOptions.makeAbsoluteExternalsRelative) applies uniformly to determine whether absolute IDs are re-relativized in the output.
See the [External Modules guide](/in-depth/external-modules) for a detailed explanation of the full resolution flow and how the output path is determined.
#### Examples
##### String pattern
```js
export default {
external: 'react',
};
```
##### Regular expression
```js
export default {
external: /^react\//,
};
```
##### Array of patterns
```js
export default {
external: ['react', 'react-dom', /^lodash/],
};
```
##### Function
```js
import path from 'node:path';
export default {
external: (id) => {
return !id.startsWith('.') && !path.isAbsolute(id);
},
};
```
::: warning Performance Overhead
Using the function form has significant performance overhead because Rolldown is written in Rust and must call JavaScript functions from Rust for every module in your dependency graph.
Unless the logic relies on values other than `id`, it is recommended to use non-function values.
:::
#### Caveats
##### Avoid `/node_modules/` for npm packages
Because the pattern `/node_modules/` can only match on the **second check** (the resolved absolute path), the full resolved path like `/path/to/node_modules/vue/dist/vue.runtime.esm-bundler.js` ends up in the output verbatim. This makes the output non-portable.
Instead, match packages by name or use a pattern for bare module IDs:
```js
export default {
// Exact package names
external: ['vue', 'react', 'react-dom'],
// Package name patterns
external: [/^vue/, /^react/, /^@mui/],
// All bare module IDs (not starting with `.` or `/` or `C:\`)
external: /^[^./](?!:[/\\])/,
};
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`external`](Interface.InputOptions.md#external)
***
### input?
* **Type**: `string` | `string`\[] | `Record`<`string`, `string`>
* **Optional**
Defines entries and location(s) of entry modules for the bundle. Relative paths are resolved based on the [`cwd`](Interface.InputOptions.md#cwd) option.
#### Examples
##### Single entry
```js
export default defineConfig({
input: 'src/index.js',
});
```
##### Multiple entries
```js
export default defineConfig({
input: ['src/index.js', 'src/vendor.js'],
});
```
##### Named multiple entries
```js
export default defineConfig({
input: {
index: 'src/index.js',
utils: 'src/utils/index.js',
'components/Foo': 'src/components/Foo.js',
},
});
```
#### In-depth
`input` allows you to specify one or more [entries](/glossary/entry) with [names](/glossary/entry-name) for the bundling process.
When multiple entries are specified (either as an array or an object), Rolldown will create separate [entry chunks](/glossary/entry-chunk) for each entry. If a module is referenced from multiple entries, Rolldown will share the code of that module for those entries.
The generated chunk names will follow the [`output.chunkFileNames`](/reference/OutputOptions.chunkFileNames) option. When using the object form, the `[name]` portion of the file name will be the name of the object property while for the array form, it will be the file name of the entry point. Note that it is possible when using the object form to put entry points into different sub-folders by adding a `/` to the name.
If you want to convert a set of files to another format while maintaining the file structure and export signatures, the recommended way—instead of using [`output.preserveModules`](/reference/OutputOptions.preserveModules) that may tree-shake exports as well as emit virtual files created by plugins—is to turn every file into an entry point. You can do so dynamically e.g. via the [`tinyglobby`](https://github.com/SuperchupuDev/tinyglobby) package:
```js
import { defineConfig } from 'rolldown';
import { globSync } from 'tinyglobby';
import path from 'node:path';
export default defineConfig({
input: Object.fromEntries(
globSync('src/**/*.js').map((file) => [
// This removes `src/` as well as the file extension from each
// file, so e.g. src/nested/foo.js becomes nested/foo, and
// normalizes Windows backslashes to forward slashes.
path
.relative('src', file.slice(0, file.length - path.extname(file).length))
.split(path.sep)
.join('/'),
// This expands the relative paths to absolute paths, so e.g.
// src/nested/foo.js becomes /project/src/nested/foo.js
path.resolve(file),
]),
),
output: {
dir: 'dist',
format: 'esm',
},
});
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`input`](Interface.InputOptions.md#input)
***
### logLevel?
* **Type**: `"info"` | `"debug"` | `"warn"` | `"silent"`
* **Optional**
Controls the verbosity of console logging during the build.
The default logLevel of "info" means that info and warnings logs will be processed while debug logs will be swallowed, which means that they are neither passed to plugin [`onLog`](/reference/Interface.Plugin#onlog) hooks nor the [`onLog`](/reference/InputOptions.onLog) option or printed to the console.
#### Default
```ts
'info'
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`logLevel`](Interface.InputOptions.md#loglevel)
***
### makeAbsoluteExternalsRelative?
* **Type**: `false` | `true` | `"ifRelativeSource"`
* **Optional**
Determines if absolute external paths should be converted to relative paths in the output.
This does not only apply to paths that are absolute in the source but also to paths that are resolved to an absolute path by either a plugin or Rolldown core.
Despite the name, this option controls two things:
1. **Resolve-time normalization** — whether relative specifiers (e.g. `'./utils'`) are normalized to absolute paths internally for deduplication. Without normalization, `'./utils'` imported from different directories may collapse into one external module because they share the same raw string.
2. **Render-time output** — whether a resolved module ID (the absolute path after resolution) gets converted to a relative path in the output. It does not affect bare specifiers (e.g. `'lodash'`) or IDs that are already relative.
Both behaviors depend on the **original import specifier** (what you wrote in source code, e.g. `'./utils'`) vs the **resolved module ID** (the absolute path after resolution, e.g. `'/project/src/utils.js'`). See the [External Modules guide](/in-depth/external-modules) for how this fits into the full resolution flow.
#### Values
##### `"ifRelativeSource"` (default)
Only convert the resolved absolute ID to a relative path if the **original import specifier** was relative.
```js
// Original: relative specifier → converted to relative in output
import './lib/utils.js'; // → import './lib/utils.js'
// Original: absolute specifier → kept absolute in output
import '/project/lib/utils.js'; // → import '/project/lib/utils.js'
```
The idea: if you wrote a relative import, you probably want a relative import in the output. If you wrote an absolute import, you probably meant it to stay absolute.
##### `true`
Always convert resolved absolute IDs to relative paths:
```js
// Both become relative in output
import './lib/utils.js'; // → import './lib/utils.js'
import '/project/lib/utils.js'; // → import '../lib/utils.js'
```
When converting an absolute path to a relative path, Rolldown does *not* take the [`file`](/reference/OutputOptions.file) or [`dir`](/reference/OutputOptions.dir) options into account, because those may not be present e.g. for builds using the JavaScript API. Instead, it assumes that the root of the generated bundle is located at the common shared parent directory of all entry points.
If the output chunk is itself nested in a subdirectory by choosing e.g. `chunkFileNames: "chunks/[name].js"`, the relative path is adjusted accordingly.
##### `false`
Never convert. Resolved absolute IDs are kept as-is. Relative specifiers are also **not** normalized to absolute paths internally, which means two files importing `'./utils'` from different directories may be treated as the same external module.
```js
import './lib/utils.js'; // → import './lib/utils.js' (as-is)
import '/project/lib/utils.js'; // → import '/project/lib/utils.js' (as-is)
```
::: warning Deduplication issue with `false`
Setting `makeAbsoluteExternalsRelative: false` disables the normalization of relative specifiers. This means `'./utils'` imported from `src/a.js` and `'./utils'` imported from `src/b/c.js` may be treated as the same external module, even though they refer to different files. Use `false` only if you are certain all your external specifiers are already unique (e.g. bare package names).
:::
#### Example
Given `import '/project/lib/utils.js'` (absolute specifier) in an external module, with output at `dist/index.js`:
| `makeAbsoluteExternalsRelative` | Output path |
| ------------------------------- | ------------------------- |
| `true` | `'../lib/utils.js'` |
| `"ifRelativeSource"` (default) | `'/project/lib/utils.js'` |
| `false` | `'/project/lib/utils.js'` |
Given `import './lib/utils.js'` (relative specifier) with a flat output at `dist/index.js`:
| `makeAbsoluteExternalsRelative` | Output path |
| ------------------------------- | ------------------ |
| `true` | `'./lib/utils.js'` |
| `"ifRelativeSource"` (default) | `'./lib/utils.js'` |
| `false` | `'./lib/utils.js'` |
The same relative specifier with a nested chunk at `dist/chunks/index.js`:
| `makeAbsoluteExternalsRelative` | Output path |
| ------------------------------- | ------------------- |
| `true` | `'../lib/utils.js'` |
| `"ifRelativeSource"` (default) | `'../lib/utils.js'` |
| `false` | `'./lib/utils.js'` |
With `true` or `"ifRelativeSource"`, relative specifiers are normalized to absolute paths internally, then re-relativized from the output chunk's location — so the path adjusts correctly for nested chunks. With `false`, the raw specifier is kept as-is with no adjustment.
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`makeAbsoluteExternalsRelative`](Interface.InputOptions.md#makeabsoluteexternalsrelative)
***
### moduleTypes?
* **Type**: [`ModuleTypes`](TypeAlias.ModuleTypes.md)
* **Optional**
Maps file patterns to module types, controlling how files are processed.
This is conceptually similar to [esbuild's `loader`](https://esbuild.github.io/api/#loader) option, allowing you to specify how each file extensions should be handled.
See [the In-Depth Guide](/in-depth/module-types) for more details.
#### Example
```js
import { defineConfig } from 'rolldown'
export default defineConfig({
moduleTypes: {
'.frag': 'text',
}
})
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`moduleTypes`](Interface.InputOptions.md#moduletypes)
***
### onLog?
* **Type**: (`level`, `log`, `defaultHandler`) => `void`
* **Optional**
A function that intercepts log messages. If not supplied, logs are printed to the console.
This handler will not be invoked if logs are filtered out by the [`logLevel`](/reference/InputOptions.logLevel) option. I.e. by default, `"debug"` logs will be swallowed.
If the default handler is not invoked, the log will not be printed to the console. Moreover, you can change the log level by invoking the default handler with a different level. Using the additional level `"error"` will turn the log into a thrown error that has all properties of the log attached.
#### Parameters
##### level
`"info"` | `"debug"` | `"warn"`
##### log
[`RolldownLog`](Interface.RolldownLog.md)
##### defaultHandler
[`LogOrStringHandler`](TypeAlias.LogOrStringHandler.md)
#### Returns
`void`
#### Example
```js
export default defineConfig({
onLog(level, log, defaultHandler) {
if (log.code === 'CIRCULAR_DEPENDENCY') {
return; // Ignore circular dependency warnings
}
if (level === 'warn') {
defaultHandler('error', log); // turn other warnings into errors
} else {
defaultHandler(level, log); // otherwise, just print the log
}
}
})
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`onLog`](Interface.InputOptions.md#onlog)
***
### ~~onwarn?~~
* **Type**: (`warning`, `defaultHandler`) => `void`
* **Optional**
A function that will intercept warning messages.
If the default handler is invoked, the log will be handled as a warning. If both an `onLog` and `onwarn` handler are provided, the `onwarn` handler will only be invoked if `onLog` calls its default handler with a `level` of `"warn"`.
#### Parameters
##### warning
[`RolldownLog`](Interface.RolldownLog.md)
##### defaultHandler
(`warning`) => `void`
#### Returns
`void`
#### Deprecated
This is a legacy API. Consider using [`onLog`](Interface.InputOptions.md#onlog) instead for better control over all log types.
To migrate from `onwarn` to `onLog`, check the `level` parameter to filter for warnings:
```js
// Before: Using `onwarn`
export default {
onwarn(warning, defaultHandler) {
// Suppress certain warnings
if (warning.code === 'CIRCULAR_DEPENDENCY') return;
// Handle other warnings with default behavior
defaultHandler(warning);
},
};
```
```js
// After: Using `onLog`
export default {
onLog(level, log, defaultHandler) {
// Handle only warnings (same behavior as `onwarn`)
if (level === 'warn') {
// Suppress certain warnings
if (log.code === 'CIRCULAR_DEPENDENCY') return;
// Handle other warnings with default behavior
defaultHandler(level, log);
} else {
// Let other log levels pass through
defaultHandler(level, log);
}
},
};
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`onwarn`](Interface.InputOptions.md#onwarn)
***
### optimization?
* **Type**: [`OptimizationOptions`](TypeAlias.OptimizationOptions.md)
* **Optional**
Configure optimization features for the bundler.
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`optimization`](Interface.InputOptions.md#optimization)
***
### output?
* **Type**: [`OutputOptions`](Interface.OutputOptions.md) | [`OutputOptions`](Interface.OutputOptions.md)\[]
* **Optional**
***
### platform?
* **Type**: `"node"` | `"browser"` | `"neutral"`
* **Optional**
Expected platform where the code run.
When the platform is set to neutral:
* When bundling is enabled the default output format is set to esm, which uses the export syntax introduced with ECMAScript 2015 (i.e. ES6). You can change the output format if this default is not appropriate.
* The main fields setting is empty by default. If you want to use npm-style packages, you will likely have to configure this to be something else such as main for the standard main field used by node.
* The conditions setting does not automatically include any platform-specific values.
#### Default
* `'node'` if the format is `'cjs'`
* `'browser'` for other formats
#### Examples
##### Browser platform
```js
export default {
platform: 'browser',
output: {
format: 'esm',
},
};
```
##### Node.js platform
```js
export default {
platform: 'node',
output: {
format: 'cjs',
},
};
```
##### Platform-neutral
```js
export default {
platform: 'neutral',
output: {
format: 'esm',
},
};
```
#### In-depth
The platform setting provides sensible defaults for module resolution and environment-specific behavior, similar to esbuild's `platform` option.
##### `'node'`
Optimized for Node.js environments:
* **Conditions**: Includes `'node'`, `'import'`, `'require'` based on output format
* **Main fields**: `['main', 'module']`
* **Target**: Node.js runtime behavior
* **process.env handling**: Preserves `process.env.NODE_ENV` and other Node.js globals
##### `'browser'`
Optimized for browser environments:
* **Conditions**: Includes `'browser'`, `'import'`, `'module'`, `'default'`
* **Main fields**: `['browser', 'module', 'main']` - prefers browser-specific entry points
* **Target**: Browser runtime behavior
* **Built-ins**: Node.js built-in modules are not polyfilled by default
:::tip
For browser builds, you may want to use [rolldown-plugin-node-polyfills](https://github.com/rolldown/rolldown-plugin-node-polyfills) to polyfill Node.js built-ins if needed.
:::
##### `'neutral'`
Platform-agnostic configuration:
* **Default format**: Always `'esm'`
* **Conditions**: Only includes format-specific conditions, no platform-specific ones
* **Main fields**: Empty by default - relies on package.json `"exports"` field
* **Use cases**: Universal libraries that run in multiple environments
##### Difference from esbuild
Notable differences from esbuild's `platform` option:
* The default output format is always `'esm'` regardless of platform (in esbuild, Node.js defaults to `'cjs'`)
##### Choosing a Platform
**Use `'browser'`** when:
* Building for web applications
* Targeting modern browsers with ES modules support
* Need browser-specific package entry points
**Use `'node'`** when:
* Building server-side applications
* Creating CLI tools
* Need Node.js-specific features and modules
**Use `'neutral'`** when:
* Building universal libraries
* Want maximum portability
* Avoiding platform-specific assumptions
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`platform`](Interface.InputOptions.md#platform)
***
### plugins?
* **Type**: [`RolldownPluginOption`](TypeAlias.RolldownPluginOption.md)
* **Optional**
The list of plugins to use.
Falsy plugins will be ignored, which can be used to easily activate or deactivate plugins. Nested plugins will be flattened. Async plugins will be awaited and resolved.
See [Plugin API document](/apis/plugin-api) for more details about creating plugins.
#### Example
```js
import { defineConfig } from 'rolldown'
export default defineConfig({
plugins: [
examplePlugin1(),
// Conditional plugins
process.env.ENV1 && examplePlugin2(),
// Nested plugins arrays are flattened
[examplePlugin3(), examplePlugin4()],
]
})
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`plugins`](Interface.InputOptions.md#plugins)
***
### preserveEntrySignatures?
* **Type**: `false` | `"strict"` | `"allow-extension"` | `"exports-only"`
* **Optional**
Controls how entry chunk exports are preserved.
This determines whether Rolldown needs to create facade chunks (additional wrapper chunks) to maintain the exact export signatures of entry modules, or whether it can combine entry modules with other chunks for optimization.
#### Default
`'exports-only'`
#### Values
##### `'exports-only'`
Follows `'strict'` behavior for entry modules that have exports, but allows `'allow-extension'` behavior for entry modules without exports.
##### `'strict'`
Entry chunks will exactly match the exports of their corresponding entry modules. If additional internal bindings need to be exposed (for example, when modules are shared between chunks), Rolldown will create facade chunks to maintain the exact export signature.
**Use case:** This is the recommended setting for **libraries** where you need guaranteed, stable export signatures.
##### `'allow-extension'`
Entry chunks can expose all exports from the corresponding entry module, and may also include additional exports from other modules if they're bundled together. This allows more optimization opportunities but may expose internal implementation details.
##### `false`
Provides maximum flexibility. Entry chunks can be merged freely with other chunks regardless of export signatures. This can lead to better optimization but may change the exposed exports significantly.
**Use case:** This is the recommended setting for **application** where you don't need guaranteed, stable export signatures.
#### Understanding Facade Chunks
A facade chunk is a small wrapper chunk that Rolldown creates to preserve the exact export signature of an entry module when the actual implementation has been bundled into another chunk.
**Example scenario:**
If you have two entry points that share code, and `preserveEntrySignatures` is set to `'strict'`, Rolldown might:
1. Bundle the shared code into a common chunk
2. Create facade chunks for each entry point that re-export from the common chunk
3. This ensures each entry point maintains its exact original export signature
#### In-depth
##### Override per Entry Point
The `preserveEntrySignatures` option is a global setting. The only way to override it for individual entry chunks is to use the plugin API and emit those chunks via [`this.emitFile`](/reference/Interface.PluginContext#emitfile) instead of using the [`input`](/reference/InputOptions.input) option.
###### Practical Example: Mixed Library and Application Build
```js
// rolldown.config.js
export default {
preserveEntrySignatures: 'exports-only', // Default for most entries
plugins: [
{
name: 'custom-entries',
buildStart() {
// Library entry that needs strict signature preservation
this.emitFile({
type: 'chunk',
id: 'src/library/index.js',
fileName: 'library.js',
preserveEntrySignature: 'strict',
});
// Application entry that can be optimized
this.emitFile({
type: 'chunk',
id: 'src/app/main.js',
fileName: 'app.js',
preserveEntrySignature: false,
});
},
},
],
};
```
When using `this.emitFile` with type `'chunk'`, you can specify:
* **`preserveEntrySignature`**: Override the global setting
* `false`: Maximum optimization, merge chunks freely
* `'strict'`: Exact export signature preservation
* `'allow-extension'`: Allow additional exports from merged chunks
* `'exports-only'`: Strict only for modules with exports
* **`fileName`**: Custom output filename for the entry chunk
* **`id`**: Module ID or path to use as the entry point
##### When to Use Each Setting
* **`'strict'`**: Building libraries, need guaranteed export signatures
* **`'exports-only'`**: Most applications, balanced approach (default)
* **`'allow-extension'`**: Advanced optimizations, okay with exposing extra exports
* **`false`**: Maximum bundle size reduction, export signatures don't matter
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`preserveEntrySignatures`](Interface.InputOptions.md#preserveentrysignatures)
***
### resolve?
* **Type**: object with the properties below
* **Optional**
Options for built-in module resolution feature.
#### alias?
* **Type**: `Record`<`string`, `string` | `false` | `string`\[]>
* **Optional**
Substitute one package for another.
One use case for this feature is replacing a node-only package with a browser-friendly package in third-party code that you don't control.
##### Example
```js
resolve: {
alias: {
'@': '/src',
'utils': './src/utils',
}
}
```
> \[!WARNING]
> `resolve.alias` will not call [`resolveId`](/reference/Interface.Plugin#resolveid) hooks of other plugin.
> If you want to call `resolveId` hooks of other plugin, use `viteAliasPlugin` from `rolldown/experimental` instead.
> You could find more discussion in [this issue](https://github.com/rolldown/rolldown/issues/3615)
#### aliasFields?
* **Type**: `string`\[]\[]
* **Optional**
Fields in package.json to check for aliased paths.
This option is expected to be used for `browser` field support.
##### Default
* `[['browser']]` for `browser` platform
* `[]` for other platforms
#### conditionNames?
* **Type**: `string`\[]
* **Optional**
Condition names to use when resolving exports in package.json.
##### Default
Defaults based on platform and import kind:
* `browser` platform
* `["import", "browser", "default"]` for import statements
* `["require", "browser", "default"]` for require() calls
* `node` platform
* `["import", "node", "default"]` for import statements
* `["require", "node", "default"]` for require() calls
* `neutral` platform
* `["import", "default"]` for import statements
* `["require", "default"]` for require() calls
#### exportsFields?
* **Type**: `string`\[]\[]
* **Optional**
Fields in package.json to check for exports.
##### Default
`[['exports']]`
#### extensionAlias?
* **Type**: `Record`<`string`, `string`\[]>
* **Optional**
Map of extensions to alternative extensions.
With writing `import './foo.js'` in a file, you want to resolve it to `foo.ts` instead of `foo.js`.
You can achieve this by setting: `extensionAlias: { '.js': ['.ts', '.js'] }`.
#### extensions?
* **Type**: `string`\[]
* **Optional**
Extensions to try when resolving files. These are tried in order from first to last.
##### Default
`['.tsx', '.ts', '.jsx', '.js', '.json']`
#### mainFields?
* **Type**: `string`\[]
* **Optional**
Fields in package.json to check for entry points.
##### Default
Defaults based on platform:
* `node` platform: `['main', 'module']`
* `browser` platform: `['browser', 'module', 'main']`
* `neutral` platform: `[]`
#### mainFiles?
* **Type**: `string`\[]
* **Optional**
Filenames to try when resolving directories.
##### Default
```ts
['index']
```
#### modules?
* **Type**: `string`\[]
* **Optional**
Directories to search for modules.
##### Default
```ts
['node_modules']
```
#### symlinks?
* **Type**: `boolean`
* **Optional**
Whether to follow symlinks when resolving modules.
##### Default
```ts
true
```
#### ~~tsconfigFilename?~~
* **Type**: `string`
* **Optional**
##### Deprecated
Use the top-level [`tsconfig`](Interface.InputOptions.md#tsconfig) option instead.
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`resolve`](Interface.InputOptions.md#resolve)
***
### shimMissingExports?
* **Type**: `boolean`
* **Optional**
When `true`, creates shim variables for missing exports instead of throwing an error.
#### Default
false
#### Examples
##### Enable shimming
```js
export default {
shimMissingExports: true,
};
```
##### Example scenario
**module-a.js:**
```js
export { nonExistent } from './module-b.js';
```
**module-b.js:**
```js
// nonExistent is not actually exported here
export const something = 'value';
```
With `shimMissingExports: false` (default), this would throw an error. With `shimMissingExports: true`, Rolldown will create a shim variable:
```js
// Bundled output (simplified)
const nonExistent = undefined;
export { nonExistent, something };
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`shimMissingExports`](Interface.InputOptions.md#shimmissingexports)
***
### transform?
* **Type**: [`TransformOptions`](Interface.TransformOptions.md)
* **Optional**
Configure how the code is transformed. This process happens after the `transform` hook.
#### Example
**Enable legacy decorators**
```js
export default defineConfig({
transform: {
decorator: {
legacy: true,
},
},
})
```
Note that if you have correct `tsconfig.json` file, Rolldown will automatically detect and enable legacy decorators support.
#### In-depth
Rolldown uses Oxc under the hood for transformation.
While Oxc does not support lowering the latest decorators proposal yet, Rolldown is able to bundle them.
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`transform`](Interface.InputOptions.md#transform)
***
### treeshake?
* **Type**: `boolean` | [`TreeshakingOptions`](TypeAlias.TreeshakingOptions.md)
* **Optional**
Controls tree-shaking (dead code elimination).
See the [In-depth Dead Code Elimination Guide](/in-depth/dead-code-elimination) for more details.
When `false`, tree-shaking will be disabled.
When `true`, it is equivalent to setting each options to the default value.
#### Default
```ts
true
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`treeshake`](Interface.InputOptions.md#treeshake)
***
### tsconfig?
* **Type**: `string` | `boolean`
* **Optional**
Configures TypeScript configuration file resolution and usage.
#### Options
##### Auto-discovery mode (`true`)
When set to `true`, Rolldown enables auto-discovery mode. For each module, both the resolver and transformer search **upward** from the module's directory, starting at the nearest `tsconfig.json`. If it has `references`, Rolldown checks each referenced project's `files`/`include`/`exclude` and uses the first one that matches the file. If no reference matches, it checks the `tsconfig.json`'s own `files`/`include`/`exclude`. If the file matches neither, Rolldown continues upward to the next `tsconfig.json` and repeats. If no `tsconfig.json` matches the file, no config is applied (no `paths`/`baseUrl`), the same as TypeScript.
Whether an `include` glob matches a file depends on its extension: by default only TypeScript files (`.ts`/`.tsx`/`.mts`/`.cts`) match, plus `.js`/`.jsx`/`.mjs`/`.cjs` when `allowJs` is enabled. A glob that names an explicit extension (for example `src/**/*.vue`) matches that extension verbatim, so a non-TS file can pick up the project's `paths`/`baseUrl`. (`files` lists exact paths and matches them regardless of extension or `allowJs`)
If the tsconfig has `references`, Rolldown resolves them the way TypeScript does: a referenced project that includes the file **takes precedence over the root**, and the first matching reference wins. Each referenced project matches with its own `compilerOptions` (such as `allowJs`). If no referenced project includes the file, Rolldown falls back to the root's own `files`/`include`/`exclude`. A solution-style root (only `references` with an explicit empty `files`/`include`, as Vite scaffolds) has no file patterns of its own, so once none of its references match either, it does **not** own the file, and discovery continues in the parent directories as described above.
```js
export default {
tsconfig: true,
};
```
##### Explicit path (`string`)
Specifies the path to a specific TypeScript configuration file. You may provide a relative path (resolved relative to `cwd`) or an absolute path.
If the tsconfig has `references`, this mode behaves like auto-discovery mode for reference resolution.
```js
export default {
tsconfig: './tsconfig.json',
};
```
```js
export default {
tsconfig: '/absolute/path/to/tsconfig.json',
};
```
:::tip
Rolldown respects `references` and `include`/`exclude` patterns in tsconfig, while esbuild does not. If you need esbuild-compatible behavior, specify a tsconfig without `references`. You can use [`extends`](https://www.typescriptlang.org/tsconfig/#extends) to share the options between the two.
:::
#### What's used from tsconfig
When a tsconfig is resolved, Rolldown uses different parts for different purposes:
##### Resolver
Uses the following for module path mapping:
* `compilerOptions.paths`: Path mapping for module resolution
* `compilerOptions.baseUrl`: Base directory for path resolution
##### Transformer
Uses select compiler options including:
* `jsx`: JSX transformation mode
* `experimentalDecorators`: Enable decorator support
* `emitDecoratorMetadata`: Emit decorator metadata
* `strictNullChecks` (falling back to `strict`): Controls whether `null`/`undefined` are elided from nullable-union `design:type` decorator metadata, and only applies when `emitDecoratorMetadata` is enabled. When neither is set it defaults to enabled, matching TypeScript 6.0+ (where `strict` is on by default)
* `verbatimModuleSyntax`: Module syntax preservation
* `useDefineForClassFields`: Class field semantics
* And other TypeScript-specific options
##### Example
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"]
}
}
}
```
With this configuration:
* JSX will use React's automatic runtime
* Path aliases like `@/utils` will resolve to `src/utils`
#### Priority
Top-level `transform` options always take precedence over tsconfig settings:
```js
export default {
tsconfig: './tsconfig.json', // Has jsx: 'react-jsx'
transform: {
jsx: {
mode: 'classic', // This takes precedence
},
},
};
```
:::tip
For TypeScript projects, it's recommended to use `tsconfig: true` for auto-discovery or specify an explicit path to ensure consistent compilation behavior and enable path mapping.
:::
#### Default
```ts
true
```
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`tsconfig`](Interface.InputOptions.md#tsconfig)
***
### watch?
* **Type**: `false` | [`WatcherOptions`](Interface.WatcherOptions.md)
* **Optional**
* **Experimental**
Watch mode related options.
These options only take effect when running with the [`--watch`](/apis/cli#w-watch) flag, or using [`watch()`](Function.watch.md) API.
Rolldown uses the following APIs to watch for changes by default:
* Linux, Android: `inotify`
* macOS: `FSEvents`
* Windows: `ReadDirectoryChangesW`
* BSD descendants (e.g. FreeBSD): `kqueue`
* Other: None (polling)
There are some limitations for each API. If you need to work around them, you can use [`watcher.usePolling`](/reference/Interface.WatcherFileWatcherOptions#usepolling) to force Rolldown to use polling instead of the native API.
::: warning Using on Windows Subsystem for Linux (WSL) 2
When running Rolldown on WSL2, file system watching does not work when a file is edited by Windows applications (non-WSL2 process). This is due to [a WSL2 limitation](https://github.com/microsoft/WSL/issues/4739). This also applies to running on Docker with a WSL2 backend.
To fix it, you could either:
* **Recommended**: Use WSL2 applications to edit your files.
* It is also recommended to move the project folder outside of a Windows filesystem. Accessing Windows filesystem from WSL2 is slow. Removing that overhead will improve performance.
* Set [`usePolling: true`](/reference/Interface.WatcherFileWatcherOptions#usepolling).
* Note that `usePolling` leads to higher CPU utilization.
:::
#### Inherited from
[`InputOptions`](Interface.InputOptions.md).[`watch`](Interface.InputOptions.md#watch)
---
---
url: /reference/TypeAlias.RolldownPlugin.md
---
# Type Alias: RolldownPlugin\
* **Type**: [`Plugin`](Interface.Plugin.md)<`A`> | `BuiltinPlugin` | `ParallelPlugin`
## Type Parameters
### A
`A` = `any`
---
---
url: /reference/TypeAlias.RolldownPluginOption.md
---
# Type Alias: RolldownPluginOption\
* **Type**: `MaybePromise`<`NullValue`<[`RolldownPlugin`](TypeAlias.RolldownPlugin.md)<`A`>> | { `name`: `string`; } | `false` | `RolldownPluginOption`\[]>
## Type Parameters
### A
`A` = `any`
---
---
url: /reference/Variable.RUNTIME_MODULE_ID.md
---
# Variable: RUNTIME\_MODULE\_ID
* **Type**: "\u0000rolldown/runtime.js"
* **Default**: `'\0rolldown/runtime.js'`
Runtime helper module ID
---
---
url: /reference/TypeAlias.SourcemapIgnoreListOption.md
---
# Type Alias: SourcemapIgnoreListOption
* **Type**: (`relativeSourcePath`, `sourcemapPath`) => `boolean`
## Parameters
### relativeSourcePath
`string`
### sourcemapPath
`string`
## Returns
`boolean`
---
---
url: /reference/TypeAlias.TopLevelFilterExpression.md
---
# Type Alias: TopLevelFilterExpression
* **Exported from**: `rolldown/filter`
* **Type**: `Include` | `Exclude`
---
---
url: /reference/TypeAlias.WarningHandlerWithDefault.md
---
# Type Alias: WarningHandlerWithDefault
* **Type**: (`warning`, `defaultHandler`) => `void`
## Parameters
### warning
[`RolldownLog`](Interface.RolldownLog.md)
### defaultHandler
[`LoggingFunction`](TypeAlias.LoggingFunction.md)
## Returns
`void`
---
---
url: /reference/Interface.WatcherFileWatcherOptions.md
---
# Interface: WatcherFileWatcherOptions
## Properties
### compareContentsForPolling?
* **Type**: `boolean`
* **Optional**
Whether to compare file contents for poll-based watchers.
When enabled, poll watchers will check file contents to determine if they actually changed.
This option is only used when [`usePolling`](#usepolling) is `true`.
#### Default
```ts
false
```
***
### debounceDelay?
* **Type**: `number`
* **Optional**
Debounce delay in milliseconds for fs-level debounced watchers.
Only used when [`useDebounce`](#usedebounce) is `true`.
#### Default
```ts
10
```
***
### debounceTickRate?
* **Type**: `number`
* **Optional**
Tick rate in milliseconds for the debouncer's internal polling.
Only used when [`useDebounce`](#usedebounce) is `true`.
When undefined, auto-selects 1/4 of debounceDelay.
***
### pollInterval?
* **Type**: `number`
* **Optional**
Interval between each poll in milliseconds.
This option is only used when [`usePolling`](#usepolling) is `true`.
#### Default
```ts
100
```
***
### useDebounce?
* **Type**: `boolean`
* **Optional**
Whether to use debounced event delivery at the filesystem level.
This coalesces rapid filesystem events before they reach the build coordinator.
#### Default
```ts
false
```
***
### usePolling?
* **Type**: `boolean`
* **Optional**
Whether to use polling-based file watching instead of native OS events.
Polling is useful for environments where native FS events are unreliable,
such as network mounts, Docker volumes, or WSL2.
#### Default
```ts
false
```
---
---
url: /builtin-plugins.md
---
# Builtin Plugins
Rolldown offers a set of built-in plugins, implemented in Rust, to achieve higher performance. These plugins cover common use cases and can be easily included in your build process.
---
---
url: /builtin-plugins/bundle-analyzer.md
---
# Bundle Analyzer Plugin
The `bundleAnalyzerPlugin` is a built-in Rolldown plugin that emits a detailed report describing your bundle's chunks, modules, dependencies, and reachability information. The report can be consumed by visualization tools, custom scripts, or LLM-based coding agents.
:::tip EXPERIMENTAL
This plugin is currently experimental and is exported from `rolldown/experimental`. Its API may change in future releases.
:::
## Usage
Import and use the plugin from Rolldown's experimental exports:
```js
import { defineConfig } from 'rolldown';
import { bundleAnalyzerPlugin } from 'rolldown/experimental';
export default defineConfig({
input: 'src/main.js',
output: {
dir: 'dist',
format: 'esm',
},
plugins: [bundleAnalyzerPlugin()],
});
```
After running the build, the plugin emits an analysis file alongside your bundled output (by default `dist/analyze-data.json`).
## Options
### `fileName`
* **Type:** `string`
* **Default:** `'analyze-data.json'` when `format` is `'json'`, `'analyze-data.md'` when `format` is `'md'`
The filename used for the emitted analysis asset. The file is emitted into the same output directory as the rest of the bundle.
```js
bundleAnalyzerPlugin({
fileName: 'bundle-analysis.json',
});
```
### `format`
* **Type:** `'json' | 'md'`
* **Default:** `'json'`
Selects the output format.
* `'json'` produces a structured data file suitable for programmatic analysis or third-party visualizers.
* `'md'` produces a markdown report tailored for LLM consumption (see [Markdown Format](#markdown-format) below).
```js
bundleAnalyzerPlugin({
format: 'md',
});
```
## JSON Format
When `format` is `'json'` (the default), the emitted file contains a structured object with the shape below. The `timestamp` field is milliseconds since the Unix epoch.
```jsonc
{
"meta": {
"bundler": "rolldown",
"version": "1.0.0",
"timestamp": 1705314645123,
},
"chunks": [
{
"id": "chunk-main",
"name": "main-abc123.js",
"size": 45230,
"type": "static-entry", // or "dynamic-entry" or "common"
"moduleIndices": [0, 1, 2],
"entryModule": 0,
"imports": [
{
"targetChunkIndex": 1,
"type": "static", // or "dynamic"
},
],
"reachableModuleIndices": [0, 1, 2, 3, 4],
},
],
"modules": [
{
"id": "mod-0",
"path": "src/main.js",
"size": 3450,
"importers": [1, 2],
},
],
}
```
The JSON output can be uploaded to community visualizers such as [chunk-visualize](https://iwanabethatguy.github.io/chunk-visualize/), or processed by custom scripts to track bundle metrics over time.
## Markdown Format
When `format: 'md'` is set, the plugin emits a structured markdown report instead of JSON. The report is designed to be consumed by LLM-based coding agents, so you can pipe it directly into a prompt for review and refactoring suggestions.
The report is organized into the following sections:
| Section | Description |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
| **Quick Summary** | Total output size, input module count, entry points, and number of code-split (common) chunks. |
| **Largest Modules by Output Contribution** | All modules sorted by size, with each module's percentage share of the total output. |
| **Entry Point Analysis** | For each entry: its output filename, bundle size, the chunks it loads, and the modules it bundles. |
| **Dependency Chains** | Modules imported by multiple files, useful for understanding why a module ends up in the bundle. |
| **Optimization Suggestions** | Actionable suggestions with severity levels (see below). |
| **Full Module Graph** | Complete per-module dependency information (imports, imported-by, size). |
| **Raw Data for Searching** | Grep-friendly lines using `[MODULE:]`, `[OUTPUT_BYTES:]`, `[IMPORT:]`, `[IMPORTED_BY:]`, `[ENTRY:]`, `[CHUNK:]` tags. |
### Optimization Suggestions
The suggestions section identifies modules that live in **shared common chunks** but are only reachable from a **single static entry**. Such modules are unnecessarily shared and could be moved closer to their entry point by enabling [`entriesAware: true`](../reference/TypeAlias.CodeSplittingGroup.md#entriesaware) on your [`output.codeSplitting`](../reference/OutputOptions.codeSplitting.md) groups, which is the same fix the report's own optimization tip recommends.
Each suggestion is tagged with a severity level based on the proportion of single-entry-reachable module size within the common chunk:
* `[HIGH]`: greater than 50%
* `[MEDIUM]`: between 30% and 50%
* `[LOW]`: less than 30%
### Piping the Report into an LLM
Because the report is plain markdown, you can feed it directly to an AI assistant for review:
```bash
# After running your build
cat dist/analyze-data.md | your-cli-coding-agent "review this bundle and suggest improvements"
```
## Example
A runnable example is available in the [`examples/bundle-analyzer-demo`](https://github.com/rolldown/rolldown/tree/main/examples/bundle-analyzer-demo) directory of the Rolldown repository. It demonstrates a multi-entry project that produces interesting optimization suggestions when analyzed with `format: 'md'`.
---
---
url: /builtin-plugins/esm-external-require.md
---
# ESM External Require Plugin
The `esmExternalRequirePlugin` is a built-in Rolldown plugin that converts CommonJS `require()` calls for external dependencies into ESM `import` statements, ensuring compatibility in environments that don't support the Node.js module API.
:::tip NOTE
This plugin sets `resolveId.meta.order` to `'pre'` to ensure external requires are resolved before other plugins. Additionally, it sets `enforce: 'pre'` by default for Vite compatibility.
:::
## Why This Is Needed
When bundling code with Rolldown, `require()` calls for external dependencies are not automatically converted to ESM imports to preserve the semantics of `require()`. While Rolldown injects `require` function when `platform: 'node'` is set, it does so by generating code like:
```js
import { createRequire } from 'node:module';
var __require = createRequire(import.meta.url);
```
However, this approach relies on the Node.js module API, which isn't available in some environments. This approach is also problematic for libraries that are expected to be bundled later, as this code is difficult to be analyzed and transformed by bundlers.
## Usage
Import and use the plugin from Rolldown's experimental exports:
```js
import { defineConfig } from 'rolldown';
import { esmExternalRequirePlugin } from 'rolldown/plugins';
export default defineConfig({
input: 'src/index.js',
output: {
dir: 'dist',
format: 'esm',
},
plugins: [
esmExternalRequirePlugin({
external: ['react', 'vue', /^node:/],
}),
],
});
```
:::warning The plugin must own its externals
List each module in this plugin's `external` option or in the top-level `external` option, never both. Top-level `external` wins during resolution, so the plugin skips duplicated modules entirely. The build succeeds with a warning while the output keeps calling `require()` on the external module at runtime.
:::
## Options
### `external`
Type: `(string | RegExp)[]`
Defines which dependencies should be treated as external. When the output format is ESM, their `require()` calls will be converted to `import` statements. For non-ESM output formats, the dependencies will be marked as external but the `require()` calls will remain unchanged.
### `skipDuplicateCheck`
Type: `boolean`
Default: `false`
When enabled, skips checking for duplicate externals between this plugin and the top-level `external` option. This can improve build performance when you're confident there are no duplicates.
```javascript
esmExternalRequirePlugin({
external: ['react', 'vue'],
skipDuplicateCheck: true, // Skip duplicate check for better performance
});
```
## Duplicate External Detection
By default, the plugin checks if any externals you specify are also configured in the top-level `external` option. If duplicates are found, you'll see a warning:
```
Found 2 duplicate external: `react`, `vue`. Remove them from top-level `external` as they're already handled by 'builtin:esm-external-require' plugin.
```
Treat this warning as a correctness signal. The plugin leaves duplicated modules untouched: the top-level `external` option takes priority, so the output still contains the raw `require()` calls this plugin is meant to convert. Remove the duplicates from top-level `external`. Nothing is lost: the plugin marks its own modules as external anyway.
`skipDuplicateCheck: true` doesn't make duplicates work. It only silences the warning, so enable it only when you're certain no module appears in both places.
## Limitations
Since this plugin changes `require()` calls to `import` statements, there are some semantic differences after bundling:
* resolution is now based on `import` behavior, not `require` behavior
* For example, `import` condition is used instead of `require` condition
* The values may be different from the original `require()` calls, especially for modules with default exports.
## How It Works
This plugin intercepts `require()` calls for dependencies specified in the option and creates virtual facade modules that:
1. Import the dependency using ESM `import * as m from '...'`
2. Re-export it using `module.exports = m` for CommonJS compatibility
3. Replace the original `require()` with the virtual module reference
For non-external `require()` calls, Rolldown automatically wraps them and converts them into ESM imports.
```js
// Input code
const react = require('react');
// Transformed output
const react = require('builtin:esm-external-require-react');
// Virtual module: builtin:esm-external-require-react
import * as m from 'react';
module.exports = m;
```
---
---
url: /builtin-plugins/replace.md
---
# Replace Plugin
The `replacePlugin` is a built-in Rolldown plugin that replaces the code based on string manipulation. This is an equivalent of `@rollup/plugin-replace`.
## Usage
Import and use the plugin from Rolldown's plugins exports:
```js
import { defineConfig } from 'rolldown';
import { replacePlugin } from 'rolldown/plugins';
export default defineConfig({
input: 'src/index.js',
output: {
dir: 'dist',
format: 'esm',
},
plugins: [
replacePlugin(
{
'process.env.NODE_ENV': JSON.stringify('production'),
__buildVersion: 15,
},
{
preventAssignment: false,
},
),
],
});
```
## Options
### `delimiters`
* **Type:** `[string, string]`
* **Default:** `["\\b", "\\b(?!\\.)"]`
Customizes how each key is matched. A key only matches when it's surrounded by these two patterns:
* `delimiters[0]` (**left**): what must come right before the key.
* `delimiters[1]` (**right**): what must come right after the key.
Both are regular expressions. The default `["\\b", "\\b(?!\\.)"]` matches a key only at word boundaries and skips property accesses, so `process` in `process.env` is left untouched.
### `preventAssignment`
* **Type:** `boolean`
* **Default:** `false`
Prevents replacing strings in variable declarations.
```js
replacePlugin({ DEBUG: 'false' }, { preventAssignment: true });
// const DEBUG = true; // Not replaced (assignment)
// console.log(DEBUG); // Replaced with `false`
```
### `objectGuards`
* **Type:** `boolean`
* **Default:** `false`
Automatically replaces `typeof` checks for object paths.
```js
replacePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }, { objectGuards: true });
// Also replaces:
// typeof process → "object"
// typeof process.env → "object"
```
### `sourcemap`
* **Type:** `boolean`
* **Default:** `false`
Generates source maps for the replacements.
## Important Notes
### Replacement Order
Keys are sorted by length (descending) to prevent partial replacements. This is crucial when you have overlapping replacement keys.
**Why order matters:**
```js
// Input code:
const apiV2 = API_URL_V2;
const api = API_URL;
replacePlugin({
API_URL: '"https://api.example.com"',
API_URL_V2: '"https://api.example.com/v2"',
});
// Without length sorting (❌ wrong):
// const apiV2 = "https://api.example.com"_V2; // Incorrect!
// const api = "https://api.example.com";
// With length sorting (✅ correct):
// const apiV2 = "https://api.example.com/v2"; // API_URL_V2 matched first
// const api = "https://api.example.com"; // Then API_URL matched
```
The plugin automatically handles this by processing longer keys first, so you don't need to worry about the order in which you define replacements.
### Word Boundaries
By default, replacements only occur at word boundaries to prevent unintended substring replacements.
**Example:**
```js
// Input code:
const currentEnv = env;
const environment = getEnvironment();
const config = process.env.NODE_ENV;
replacePlugin({ env: '"production"' });
// Output:
// const currentEnv = "production"; ✅ 'env' as standalone word
// const environment = getEnvironment(); ✅ 'env' is part of 'environment'
// const config = process.env.NODE_ENV; ✅ 'env' after '.' (property access)
```
This behavior ensures that replacing `env` doesn't accidentally break `environment` or property accesses like `process.env`. You can customize this with the `delimiters` option if needed.
## Migration from @rollup/plugin-replace
### Feature Comparison
| Feature | @rollup/plugin-replace | rolldown |
| --------------- | ---------------------------- | ------------------------------- |
| API | `replace({ values: {...} })` | `replacePlugin({...}, options)` |
| Function values | ✅ `() => value` | ❌ Static values only |
| File filtering | ✅ include/exclude | ❌ All files |
| Performance | JavaScript | Rust (faster) |
### Migration Example
```js
// Before (@rollup/plugin-replace)
replace({
values: { __VERSION__: () => getVersion() },
include: ['src/**/*.js'],
});
// After (rolldown)
replacePlugin({
__VERSION__: JSON.stringify(getVersion()),
});
```
---
---
url: /apis/bundler-api.md
---
# Bundler API
Rolldown provides three main API functions for bundling your code programmatically.
## `rolldown()`
`rolldown()` is the API compatible with Rollup's `rollup` function.
```js
import { rolldown } from 'rolldown';
let bundle,
failed = false;
try {
bundle = await rolldown({
input: 'src/main.js',
});
await bundle.write({
format: 'esm',
});
} catch (e) {
console.error(e);
failed = true;
}
if (bundle) {
await bundle.close();
}
process.exitCode = failed ? 1 : 0;
```
See [its reference](/reference/Function.rolldown) for more details.
## `watch()`
`watch()` is the API compatible with Rollup's `watch` function.
```js
import { watch } from 'rolldown';
const watcher = watch({/* ... */});
watcher.on('event', (event) => {
if (event.code === 'BUNDLE_END') {
console.log(event.duration);
event.result.close();
}
});
// Stop watching
watcher.close();
```
See [its reference](/reference/Function.watch) for more details.
## `build()`
::: warning Experimental
This API is experimental and may change in patch releases.
:::
`build()` is the simplest option for most use cases. The API is similar to esbuild's `build` function. It bundles and writes in a single call with automatic cleanup.
```js
import { build } from 'rolldown';
const result = await build({
input: 'src/main.js',
output: {
file: 'bundle.js',
},
});
console.log(result);
```
See [its reference](/reference/Function.build) for more details.
---
---
url: /apis/plugin-api.md
---
# Plugin API
## Overview
Rolldown's plugin interface is almost fully compatible with Rollup's (detailed tracking [here](https://github.com/rolldown/rolldown/issues/819)), so if you have written a Rollup plugin before, you already know how to write a Rolldown plugin!
A Rolldown plugin is an object that satisfies the [plugin interface](#plugin-interface) described below.
A plugin should be distributed as a package which exports a function that can be called with plugin specific options and returns such an object.
Plugins allow you to customize Rolldown's behavior by, for example, transpiling code before bundling, or shimming a built-in module that is not available.
### Example
The following example shows a Rolldown plugin that intercepts import requests to `virtual:example` and returns a custom content for it.
::: code-group
```js [rolldown-plugin-example.js]
const id = 'virtual:example';
const resolvedId = '\0' + id;
export default function examplePlugin() {
return {
name: 'example-plugin', // this name will show up in logs and errors
resolveId(source) {
if (source === id) {
// this signals to Rolldown that this import should resolve to a module named `\0virtual:example`
return resolvedId;
}
return null; // other ids should be handled as usual
},
load(id) {
if (id === resolvedId) {
// the source code for `\0virtual:example`
return `export default 'Hello from ${id}';`;
}
return null; // other ids should be handled as usual
},
};
}
```
```js [rolldown.config.js]
import { defineConfig } from 'rolldown';
import examplePlugin from './rolldown-plugin-example.js';
export default defineConfig({
plugins: [examplePlugin()],
});
```
:::
::: warning Hook Filters
This example plugin does not use [Hook Filters](/apis/plugin-api/hook-filters) for simplicity.
To improve performance, it is recommended to use them when possible.
:::
## Conventions
* Plugins should have a clear name with `rolldown-plugin-` prefix.
* Include `rolldown-plugin` keyword in the package.json `keywords` field.
* Make sure your plugin outputs correct source mappings if appropriate.
* If your plugin uses [virtual modules](#virtual-modules), follow the [Virtual Modules Convention](#virtual-modules).
* (recommended) Plugins should be tested.
* (recommended) Plugins should be documented in English.
### Virtual Modules Convention {#virtual-modules}
Virtual modules are a useful scheme that allows you to pass build time information or helper functions to source files using normal ESM import syntax. A virtual module is a module that does not exist on the file system and is instead resolved and provided by a plugin, as shown in the [example above](#example).
Once such a plugin is registered, the virtual module can be imported in JavaScript through its user-facing id:
```js
import msg from 'virtual:example';
console.log(msg);
```
Virtual modules in Rolldown are prefixed with `virtual:` for the user-facing path by convention. If possible the plugin name should be used as a namespace to avoid collisions with other plugins in the ecosystem. For example, a `rolldown-plugin-posts` could ask users to import a `virtual:posts` or `virtual:posts/helpers` virtual module to get build time information. Internally, plugins that use virtual modules should prefix the module ID with `\0` while resolving the id, a convention from the Rollup ecosystem. This prevents other plugins from trying to process the id (like node resolution), and core features like sourcemaps can use this info to differentiate between virtual modules and regular files.
Note that modules directly derived from a real file, as in the case of a script module in a Single File Component (like a `.vue` or `.svelte` SFC), don't need to follow this convention. SFCs generally generate a set of submodules when processed, but the code in these can be mapped back to the filesystem. Using `\0` for these submodules would prevent sourcemaps from working correctly.
## Plugin Interface
The [`Plugin`](/reference/Interface.Plugin) interface has a required `name` property and multiple optional properties and hooks.
Hooks are methods defined on the plugin that can be used to interact with the build process. They are called at various stages of the build. Hooks can affect how a build is run, provide information about a build, or modify a build once complete. There are different kinds of hooks:
* `async`: The hook may also return a Promise resolving to the same type of value; otherwise, the hook is marked as `sync`.
* `first`: If several plugins implement this hook, the hooks are run sequentially until a hook returns a value other than `null` or `undefined`.
* `sequential`: If several plugins implement this hook, all of them will be run in the specified plugin order. If a hook is `async`, subsequent hooks of this kind will wait until the current hook is resolved.
* `parallel`: If several plugins implement this hook, all of them will be run in the specified plugin order. If a hook is `async`, subsequent hooks of this kind will be run in parallel and not wait for the current hook.
Instead of a method, hooks can also be objects with a `handler` property. In this case, the `handler` property is the actual hook method. This allows you to provide additional optional properties to control the behavior of the hook. See the [`ObjectHook`](/reference/TypeAlias.ObjectHook) type for more information.
There are two types of hooks: [build hooks](#build-hooks) and [output generation hooks](#output-generation-hooks).
### Build Hooks
Build hooks are run during the build phase. They are mainly concerned with locating, providing and transforming input files before they are processed by Rolldown.
The first hook of the build phase is [`options`](/reference/Interface.Plugin#options), the last one is always [`buildEnd`](/reference/Interface.Plugin#buildend). If there is a build error, [`closeBundle`](/reference/Interface.Plugin#closebundle) will be called after that.
```dot+hooks-graph
# styles
sequential: fillcolor="#ffe8cc", dark$fillcolor="#9d4f1a"
parallel: fillcolor="#ffcccc", dark$fillcolor="#8a2a2a"
first: fillcolor="#fff4cc", dark$fillcolor="#9d7a1a"
internal: fillcolor="#f0f0f0", dark$fillcolor="#3a3a3a"
sync: color="#3c3c43", dark$color="#dfdfd6"
async: color="#ff7e17", dark$color="#cc5f1a", penwidth=1
# nodes
watchChange(/reference/Interface.Plugin#watchchange): parallel, async
closeWatcher(/reference/Interface.Plugin#closewatcher): parallel, async
options(/reference/Interface.Plugin#options): sequential, async
outputOptions(/reference/Interface.Plugin#outputoptions): sequential, async
buildStart(/reference/Interface.Plugin#buildstart): parallel, async
resolveId(/reference/Interface.Plugin#resolveid): first, async
load(/reference/Interface.Plugin#load): first, async
transform(/reference/Interface.Plugin#transform): sequential, async
moduleParsed(/reference/Interface.Plugin#moduleparsed): parallel, async
internalTransform: internal
resolveDynamicImport(/reference/Interface.Plugin#resolvedynamicimport): first, async
buildEnd(/reference/Interface.Plugin#buildend): parallel, async
# edges
options -> outputOptions
outputOptions -> buildStart
buildStart -> resolveId: each entry
resolveId .-> buildEnd: external
resolveId -> load: non-external
load -> transform
transform -> internalTransform
internalTransform -> moduleParsed
moduleParsed .-> buildEnd: no imports
moduleParsed -> resolveDynamicImport: each import()
resolveDynamicImport -> load: non-external
moduleParsed -> resolveId: each import
resolveDynamicImport .-> buildEnd: external
resolveDynamicImport -> resolveId: unresolved
```
Note that `internalTransform` in the graph above is not a plugin hook, it is the step where Rolldown transforms non-JS code to JS.
Additionally, in watch mode the [`watchChange`](/reference/Interface.Plugin#watchchange) hook can be triggered at any time to notify a new run will be triggered once the current run has generated its outputs. Also, when watcher closes, the [`closeWatcher`](/reference/Interface.Plugin#closewatcher) hook will be triggered.
::: warning Unsupported Hooks
The following Build Hooks are supported by Rollup, but not by Rolldown:
* `shouldTransformCachedModule` ([#4389](https://github.com/rolldown/rolldown/issues/4389))
:::
### Output Generation Hooks
Output generation hooks can provide information about a generated bundle and modify a build once complete. Plugins that only use output generation hooks can also be passed in via the output options and therefore run only for certain outputs.
The first hook of the output generation phase is [`renderStart`](/reference/Interface.Plugin#renderstart), the last one is either [`generateBundle`](/reference/Interface.Plugin#generatebundle) if the output was successfully generated via [`bundle.generate(...)`](/reference/Interface.RolldownBuild#generate), [`writeBundle`](/reference/Interface.Plugin#writebundle) if the output was successfully generated via [`bundle.write(...)`](/reference/Interface.RolldownBuild#write), or [`renderError`](/reference/Interface.Plugin#rendererror) if an error occurred at any time during the output generation.
Additionally, [`closeBundle`](/reference/Interface.Plugin#closebundle) can be called as the very last hook, but it is the responsibility of the User to manually call [`bundle.close()`](/reference/Interface.RolldownBuild#close) to trigger this. The CLI will always make sure this is the case.
```dot+hooks-graph
# config
margin=150,0
# styles
sequential: fillcolor="#ffe8cc", dark$fillcolor="#9d4f1a"
parallel: fillcolor="#ffcccc", dark$fillcolor="#8a2a2a"
first: fillcolor="#fff4cc", dark$fillcolor="#9d7a1a"
internal: fillcolor="#f0f0f0", dark$fillcolor="#3a3a3a"
sync: color="#3c3c43", dark$color="#dfdfd6"
async: color="#ff7e17", dark$color="#cc5f1a", penwidth=1
!option: fillcolor="transparent"
!invisible: label="", shape=circle, fixedsize=true, width=0.2, height=0.2, style=filled, fillcolor="#ffffff"
# nodes
renderStart(/reference/Interface.Plugin#renderstart): parallel, sync
resolveFileUrl(/reference/Interface.Plugin#resolvefileurl): first, sync
banner(/reference/Interface.Plugin#banner): sequential, sync
footer(/reference/Interface.Plugin#footer): sequential, sync
intro(/reference/Interface.Plugin#intro): sequential, sync
outro(/reference/Interface.Plugin#outro): sequential, sync
renderChunk(/reference/Interface.Plugin#renderchunk): sequential, sync
minify: internal
postBanner: option, sync
postFooter: option, sync
augmentChunkHash(/reference/Interface.Plugin#augmentchunkhash): sequential, async
generateBundle(/reference/Interface.Plugin#generatebundle): sequential, sync
writeBundle(/reference/Interface.Plugin#writebundle): parallel, sync
renderError(/reference/Interface.Plugin#rendererror): parallel, sync
closeBundle(/reference/Interface.Plugin#closebundle): parallel, sync
beforeImportMeta: invisible
beforeAddons: invisible
afterAddons: invisible
# groups
generateChunks: beforeAddons, banner, footer, intro, outro, afterAddons
# edges
renderStart -> beforeImportMeta: each chunk
beforeImportMeta -> resolveFileUrl: each import.meta.ROLLDOWN_FILE_URL_*
resolveFileUrl -> beforeImportMeta
beforeImportMeta -> beforeAddons
augmentChunkHash -> generateBundle
generateBundle -> writeBundle
writeBundle .-> closeBundle
beforeAddons -> banner
beforeAddons -> footer
beforeAddons -> intro
beforeAddons -> outro
banner -> afterAddons
footer -> afterAddons
intro -> afterAddons
outro -> afterAddons
afterAddons .-> beforeImportMeta: next chunk, constraint=false
afterAddons -> renderChunk: each chunk
renderChunk -> minify
minify -> postBanner
minify -> postFooter
postBanner -> augmentChunkHash
postFooter -> augmentChunkHash
augmentChunkHash .-> renderChunk: next chunk, constraint=false
renderError .-> closeBundle
```
Note that `minify` in the graph above is not a plugin hook and is the step where Rolldown runs the minifier. Also note that `postBanner` and `postFooter` are not plugin hooks, these are output options and do not have corresponding hooks, unlike `banner` and `footer`.
::: warning Unsupported Hooks
The following Output Generation Hooks are supported by Rollup, but not by Rolldown:
* `resolveImportMeta` ([#1010](https://github.com/rolldown/rolldown/issues/1010))
* `renderDynamicImport` ([#4532](https://github.com/rolldown/rolldown/issues/4532))
:::
## Plugin Context
A number of utility functions and informational bits can be accessed from within most hooks via `this`. See the [`PluginContext`](/reference/Interface.PluginContext) type for more information.
## Supporting TypeScript and JSX
To achieve optimal performance, Rolldown runs the internal transform which transforms TypeScript and JSX to JavaScript after the [`transform`](/reference/Interface.Plugin#transform) hooks are called. This means the plugins using `transform` hook need to support TypeScript and JSX. Basically, there are two ways to achieve this.
### Handling TypeScript and JSX Syntax
[`this.parse`](/reference/Interface.PluginContext#parse) supports parsing TypeScript and JSX by passing the `lang` option. This should allow the plugin to process TypeScript and JSX easily.
### Transforming TypeScript and JSX beforehand
If processing TypeScript and JSX AST is not an option, you can still transform them to JavaScript by using the `transform` function exposed from `rolldown/utils`. Note that this has an additional overhead.
## Notable Differences from Rollup
While Rolldown's plugin interface is largely compatible with Rollup's, there are some important behavioral differences to be aware of:
### Output Generation Handling
In Rollup, all outputs are generated together in a single process. However, Rolldown handles each output generation separately. This means that if you have multiple output configurations, Rolldown will process each output independently, which can affect how certain plugins behave, especially those that maintain state across the entire build process.
These are the concrete differences:
* [`outputOptions`](/reference/Interface.FunctionPluginHooks#outputoptions) hook is called **before** the build hooks in Rolldown, whereas Rollup calls them **after** the build hooks
* Build hooks are called for each output separately, whereas Rollup calls them once for all outputs
* [`closeBundle`](/reference/Interface.FunctionPluginHooks#closebundle) hook is called **only** when you called [`generate()`](/reference/Interface.RolldownBuild#generate) or [`write()`](/reference/Interface.RolldownBuild#write) at least once, whereas Rollup calls it regardless of whether you called `generate()` or `write()`
### Watch Mode Hook Behavior
In Rollup, the [`options`](/reference/Interface.Plugin#options) hook is called on every rebuild in watch mode. In Rolldown, the `options` hook is only called once when the watcher is created, and is not called again on subsequent rebuilds.
### Sequential Hook Execution
In Rollup, certain hooks like [`writeBundle`](/reference/Interface.FunctionPluginHooks#writebundle) are "parallel" by default, meaning they run concurrently across multiple plugins. This requires plugins to explicitly set `sequential: true` if they need their hooks to run one after another.
In Rolldown, the [`writeBundle`](/reference/Interface.FunctionPluginHooks#writebundle) hook is already sequential by default, so plugins do not need to specify `sequential: true` for this hook.
### Sourcemap Validation
Rollup does not check a plugin's sourcemap against its own `sources` and `names`. A mapping that points at a missing source is dropped. A mapping that points at a missing name is kept without the name. Rolldown checks every index while converting the map to the internal representation. So an invalid map that Rollup accepts can fail the build here. For example:
```
Failed to convert json sourcemap to struct
Reference to non-existing source at position 1
```
---
---
url: /apis/plugin-api/hook-filters.md
---
# Plugin Hook Filters
Hook filters allow Rolldown to skip unnecessary Rust-to-JS calls by evaluating filter conditions on the Rust side before invoking your plugin. This improves performance and enables better parallelization. See [Why Plugin Hook Filters](/in-depth/why-plugin-hook-filter) for more details.
## Basic Usage
Instead of checking conditions inside your hook:
```js{5}
export default function myPlugin() {
return {
name: 'example',
transform(code, id) {
if (!id.endsWith('.data')) {
// early return
return
}
// perform actual transform
return transformedCode
},
}
}
```
Use the object hook format with a `filter` property:
```js{5-7}
export default function myPlugin() {
return {
name: 'example',
transform: {
filter: {
id: /\.data$/
},
handler(code) {
// perform actual transform
return transformedCode
},
}
}
}
```
Rolldown evaluates the filter on the Rust side and only calls your handler when the filter matches.
::: tip
[`@rolldown/pluginutils`](https://npmx.dev/package/@rolldown/pluginutils) exports some utilities for hook filters like `exactRegex` and `prefixRegex`.
:::
## Filter Properties
In addition to `id`, you can also filter based on `moduleType` and the module's source code. The `filter` property works similarly to [`createFilter` from `@rollup/pluginutils`](https://github.com/rollup/plugins/blob/master/packages/pluginutils/README.md#createfilter).
* If multiple values are passed to `include`, the filter matches if **any** of them match.
* If a filter has both `include` and `exclude`, `exclude` takes precedence.
* If multiple filter properties are specified, the filter matches when all of the specified properties match. In other words, if even one property fails to match, it is excluded, regardless of the other properties. For example, the following filter matches a module only if its file names ends with `.js`, its source code contains `foo`, and does not contain `bar`:
```js
{
id: {
include: /\.js$/,
exclude: /\.ts$/
},
code: {
include: 'foo',
exclude: 'bar'
}
}
```
The following properties are supported by each hook:
* `resolveId` hook: `id`
* `load` hook: `id`
* `transform` hook: `id`, `moduleType`, `code`
See [`HookFilter`](/reference/Interface.HookFilter) as well.
> \[!NOTE]
> `id` is treated as a glob pattern when you pass a `string`, and treated as a regular expression when you pass a `RegExp`.
> In the `resolve` hook, `id` must be a `RegExp`. `string`s are not allowed.
> This is because the `id` value in `resolveId` is the exact text written in the import statement and usually not an absolute path, while glob patterns are designed to match absolute paths.
## Composable Filters
For more complex filtering logic, Rolldown provides composable filter expressions via the [`@rolldown/pluginutils`](https://github.com/rolldown/plugins/tree/main/packages/pluginutils) package. These allow you to build filters using logical operators like `and`, `or`, and `not`.
> \[!WARNING]
> Composable filters are not yet supported in Vite or unplugin. They can be used in Rolldown plugins only.
### Example
```js
import { and, id, include, moduleType } from '@rolldown/pluginutils';
export default function myPlugin() {
return {
name: 'my-plugin',
transform: {
filter: [include(and(id(/\.ts$/), moduleType('ts')))],
handler(code, id) {
// Only called for .ts files with moduleType 'ts'
return transformedCode;
},
},
};
}
```
### Available Filter Functions
* `and(...exprs)` / `or(...exprs)` / `not(expr)` — Logical composition of filter expressions.
* `id(pattern, params?)` — Filter by id. A `string` pattern is matched by exact equality (not glob); a `RegExp` is tested against the id.
* `importerId(pattern, params?)` — Filter by importer id. A `string` pattern is matched by exact equality; a `RegExp` is tested against the importer id. Only usable with the `resolveId` hook.
* `moduleType(type)` — Filter by module type (e.g. 'js', 'tsx', or 'json').
* `code(pattern)` — Filter by code content.
* `query(key, pattern)` — Filter by query parameter.
* `include(expr)` / `exclude(expr)` — Top-level include/exclude wrappers.
* `queries(obj)` — Compose multiple query filters.
See the [`@rolldown/pluginutils` README](https://github.com/rolldown/plugins/tree/main/packages/pluginutils#readme) for the full API reference.
## Interoperability
Plugin hook filters are supported in Rollup 4.38.0+, Vite 6.3.0+, and all versions of Rolldown.
### Supporting Older Versions
If you're authoring a plugin that needs to support older versions of Rollup (< 4.38.0) or Vite (< 6.3.0), you can provide a fallback implementation that works in both environments.
The strategy is to use the object hook format with filters when available, and fall back to a regular function that checks conditions internally for older versions:
```js
const idFilter = /\.data$/;
export default function myPlugin() {
return {
name: 'my-plugin',
transform: {
// Filter is used by Rolldown and newer Rollup/Vite versions
filter: { id: idFilter },
// Handler is called when filter matches
handler(code, id) {
// Double-check in handler for compatibility with older versions
// This is only necessary if you're supporting older versions
if (!idFilter.test(id)) {
return null;
}
// perform actual transform
return transformedCode;
},
},
};
}
```
This approach ensures your plugin will:
* Use filters for optimal performance in Rolldown and newer Rollup/Vite versions
* Still work correctly in older versions (they will call the handler for all files, but the internal check ensures correct behavior)
> \[!TIP]
> When supporting older versions, keep both the filter pattern and the internal check in sync to avoid confusion.
### `moduleType` Filter
The [Module Type concept](/in-depth/module-types) does not exist in Rollup / Vite 7 and below. For that reason, the `moduleType` filter is not supported by those tools and will be ignored.
---
---
url: /apis/plugin-api/file-urls.md
---
# File URLs
To reference a file URL reference from within JS code, use the `import.meta.ROLLDOWN_FILE_URL_referenceId` replacement. This will generate code that resolves the emitted file relative to `import.meta.url` and assumes the `URL` global is available. This works out of the box for the `esm` format, and for the `cjs` format on the `node` platform where `import.meta.url` is [polyfilled](/in-depth/non-esm-output-formats#well-known-import-meta-properties). For the `iife` and `umd` formats, `import.meta.url` needs to be polyfilled or the [`resolveFileUrl`](/reference/Interface.Plugin#resolvefileurl) hook needs to be implemented to return code that does not rely on `import.meta.url`. The same hook can also be used to customize the URL resolution for the other formats.
> \[!TIP]
> Rolldown also accepts `import.meta.ROLLUP_FILE_URL_referenceId` as an alias of `import.meta.ROLLDOWN_FILE_URL_referenceId` for compatibility with Rollup.
The following example will detect imports of `.svg` files, emit the imported files as assets, and return their URLs to be used e.g. as the `src` attribute of an `img` tag:
::: code-group
```js [rolldown-plugin-svg-asset.js]
import path from 'node:path';
import fs from 'node:fs';
function svgResolverPlugin() {
return {
name: 'svg-resolver',
resolveId: {
filter: { id: /\.svg$/ },
handler(source, importer) {
return path.resolve(path.dirname(importer), source);
},
},
load: {
filter: { id: /\.svg$/ },
handler(id) {
const referenceId = this.emitFile({
type: 'asset',
name: path.basename(id),
source: fs.readFileSync(id),
});
return `export default import.meta.ROLLDOWN_FILE_URL_${referenceId};`;
},
},
};
}
```
```js [main.js (usage)]
import logo from '../images/logo.svg';
const image = document.createElement('img');
image.src = logo;
document.body.appendChild(image);
```
:::
Similar to assets, emitted chunks can be referenced from within JS code via `import.meta.ROLLDOWN_FILE_URL_referenceId` as well.
The following example will detect imports prefixed with `register-paint-worklet:` and generate the necessary code and separate chunk to generate a CSS paint worklet. Note that this will only work in modern browsers and will only work if the output format is set to `es`.
::: code-group
```js [rolldown-plugin-paint-worklet.js]
import { prefixRegex } from '@rolldown/pluginutils';
const REGISTER_WORKLET = 'register-paint-worklet:';
function registerPaintWorkletPlugin() {
return {
name: 'register-paint-worklet',
load: {
filter: { id: prefixRegex(REGISTER_WORKLET) },
handler(id) {
return `CSS.paintWorklet.addModule(
import.meta.ROLLDOWN_FILE_URL_${this.emitFile({
type: 'chunk',
id: id.slice(REGISTER_WORKLET.length),
})}
);`;
},
},
resolveId: {
filter: { id: prefixRegex(REGISTER_WORKLET) },
handler(source, importer) {
// We remove the prefix, resolve everything to absolute ids and
// add the prefix again. This makes sure that you can use
// relative imports to define worklets
return this.resolve(source.slice(REGISTER_WORKLET.length), importer).then(
(resolvedId) => REGISTER_WORKLET + resolvedId.id,
);
},
},
};
}
```
```js [main.js (usage)]
import 'register-paint-worklet:./worklet.js';
import { color, size } from './config.js';
document.body.innerHTML += `color: ${color}, size: ${size} `;
```
```js [worklet.js (usage)]
import { color, size } from './config.js';
registerPaint(
'vertical-lines',
class {
paint(ctx, geom) {
for (let x = 0; x < geom.width / size; x++) {
ctx.beginPath();
ctx.fillStyle = color;
ctx.rect(x * size, 0, 2, geom.height);
ctx.fill();
}
}
},
);
```
```js [config.js (usage)]
export const color = 'greenyellow';
export const size = 6;
```
:::
If you build this code, both the main chunk and the worklet will share the code from `config.js` via a shared chunk. This enables us to make use of the browser cache to reduce transmitted data and speed up loading the worklet.
## Passing a `urlId`
::: warning Experimental
The `urlId` API is experimental and may change in minor versions.
:::
Rolldown extends the syntax with an optional `urlId` (`import.meta.ROLLDOWN_FILE_URL_referenceId_urlId`). The `urlId` is an arbitrary identifier that is forwarded to the [`resolveFileUrl`](/reference/Interface.Plugin#resolvefileurl) hook as `args.urlId`, so a single plugin can resolve the same emitted file differently depending on where it is referenced from:
```js [rolldown-plugin-svg-resolver.js]
import path from 'node:path';
import fs from 'node:fs';
function svgResolverPlugin() {
return {
name: 'svg-resolver',
load: {
filter: { id: /\.svg$/ },
handler(id) {
const referenceId = this.emitFile({
type: 'asset',
name: path.basename(id),
source: fs.readFileSync(id),
});
// Append a `urlId` so `resolveFileUrl` can special-case this reference.
return `export default import.meta.ROLLDOWN_FILE_URL_${referenceId}_inline;`;
},
},
resolveFileUrl({ referenceId, relativePath, urlId }) {
if (urlId === 'inline') {
// resolve inlined references differently
}
// ...
},
};
}
```
The `urlId` is only recognized on the rolldown-specific `ROLLDOWN_FILE_URL_` prefix. The Rollup-compatible `ROLLUP_FILE_URL_` alias never carries one. The default resolution (when no plugin handles the reference) ignores `urlId`.
The `urlId` can only contain ASCII identifier characters: letters (`a`-`z`, `A`-`Z`), digits (`0`-`9`), `_`, and `$`.
---
---
url: /apis/plugin-api/transformations.md
---
# Source Code Transformations
If a plugin transforms source code, it should generate a sourcemap automatically, unless there's a specific `sourceMap: false` option. Rolldown only cares about the `mappings` property (everything else is handled automatically). [magic-string](https://github.com/Rich-Harris/magic-string) provides a simple way to generate such a map for elementary transformations like adding or removing code snippets.
If it doesn't make sense to generate a sourcemap, return an empty sourcemap:
```js
return {
code: transformedCode,
map: { mappings: '' },
};
```
If the transformation does not move code, you can preserve existing sourcemaps by returning `null`:
```js
return {
code: transformedCode,
map: null,
};
```
## Transforming a Chunk
To transform a chunk, you can use [`renderChunk`](/reference/Interface.Plugin#renderchunk). If you return the sourcemap for the transform you applied, Rolldown composes that map with the previous transforms and rebuilds `x_google_ignoreList` field based on the options:
```js
import MagicString from 'magic-string';
export default function myPlugin() {
return {
name: 'example',
renderChunk(code) {
const s = new MagicString(code);
s.prepend('/* banner */\n');
return { code: s.toString(), map: s.generateMap({ hires: 'boundary' }) };
},
};
}
```
We discourage transforming in [`generateBundle`](/reference/Interface.Plugin#generatebundle). It runs after hashing, so the emitted filename keeps the hash of the untransformed code. It also runs after the `.map` asset is built, so editing `chunk.map` does not change that file. That said, if you have to transform there, compose the maps and write the asset yourself:
```js
import remapping from '@jridgewell/remapping';
import MagicString from 'magic-string';
export default function myPlugin() {
return {
name: 'example',
generateBundle(options, bundle) {
for (const chunk of Object.values(bundle)) {
if (chunk.type !== 'chunk') continue;
const s = new MagicString(chunk.code);
// ...your transform...
if (!s.hasChanged()) continue;
// A low-resolution map can compose down to nothing, so keep the mappings at the boundaries.
const step = s.generateMap({ source: chunk.fileName, hires: 'boundary' });
chunk.code = s.toString();
if (chunk.map) {
// compose the sourcemap
chunk.map = remapping([step, chunk.map], () => null);
// The emitted file comes from this asset, not from `chunk.map`.
const asset = bundle[`${chunk.fileName}.map`];
if (asset) asset.source = chunk.map.toString();
}
}
},
};
}
```
---
---
url: /apis/plugin-api/inter-plugin-communication.md
---
# Inter-plugin communication
At some point when using many dedicated plugins, there may be the need for unrelated plugins to be able to exchange information during the build. There are several mechanisms through which Rolldown makes this possible.
## Custom resolver options
Assume you have a plugin that should resolve an import to different ids depending on how the import was generated by another plugin. One way to achieve this would be to rewrite the import to use special proxy ids, e.g. a transpiled import via `require("foo")` in a CommonJS file could become a regular import with a special id `import "foo?require=true"` so that a resolver plugin knows this.
The problem here, however, is that this proxy id may or may not cause unintended side effects when passed to other resolvers because it does not really correspond to a file. Moreover, if the id is created by plugin `A` and the resolution happens in plugin `B`, it creates a dependency between these plugins so that `A` is not usable without `B`.
Custom resolver option offer a solution here by allowing to pass additional options for plugins when manually resolving a module via [`this.resolve`](/reference/Interface.PluginContext#resolve). This happens without changing the id and thus without impairing the ability for other plugins to resolve the module correctly if the intended target plugin is not present.
```js
function requestingPlugin() {
return {
name: 'requesting',
async buildStart() {
const resolution = await this.resolve('foo', undefined, {
custom: { resolving: { specialResolution: true } },
});
console.log(resolution.id); // "special"
},
};
}
function resolvingPlugin() {
return {
name: 'resolving',
resolveId(id, importer, { custom }) {
if (custom.resolving?.specialResolution) {
return 'special';
}
return null;
},
};
}
```
Note the convention that custom options should be added using a property corresponding to the plugin name of the resolving plugin. It is responsibility of the resolving plugin to specify which options it respects.
## Custom module meta-data
Plugins can annotate modules with custom meta-data which can be set by themselves and other plugins via the [`resolveId`](/reference/Interface.Plugin#resolveid), [`load`](/reference/Interface.Plugin#load), and [`transform`](/reference/Interface.Plugin#transform) hooks and accessed via [`this.getModuleInfo`](/reference/Interface.PluginContext#getmoduleinfo), [`this.load`](/reference/Interface.PluginContext#load) and the [`moduleParsed`](/reference/Interface.Plugin#moduleparsed) hook. This meta-data should always be `JSON.stringify`-able and will be persisted in the cache e.g. in watch mode.
```js
function annotatingPlugin() {
return {
name: 'annotating',
transform(code, id) {
if (thisModuleIsSpecial(code, id)) {
return { meta: { annotating: { special: true } } };
}
},
};
}
function readingPlugin() {
let parentApi;
return {
name: 'reading',
buildEnd() {
const specialModules = Array.from(this.getModuleIds()).filter(
(id) => this.getModuleInfo(id).meta.annotating?.special,
);
// do something with this list
},
};
}
```
Note the convention that plugins that add or modify data should use a property corresponding to the plugin name, in this case `annotating`. On the other hand, any plugin can read all meta-data from other plugins via `this.getModuleInfo`.
If several plugins add meta-data or meta-data is added in different hooks, then these `meta` objects will be merged shallowly. That means if plugin `first` adds `{meta: {first: {resolved: "first"}}}` in the resolveId hook and `{meta: {first: {loaded: "first"}}}` in the load hook while plugin `second` adds `{meta: {second: {transformed: "second"}}}` in the `transform` hook, then the resulting `meta` object will be `{first: {loaded: "first"}, second: {transformed: "second"}}`. Here the result of the `resolveId` hook will be overwritten by the result of the `load` hook as the plugin was both storing them under its `first` top-level property. The `transform` data of the other plugin on the other hand will be placed next to it.
The `meta` object of a module is created as soon as Rolldown starts loading a module and is updated for each lifecycle hook of the module. If you store a reference to this object, you can also update it manually. To access the meta object of a module that has not been loaded yet, you can trigger its creation and loading the module via [`this.load`](/reference/Interface.PluginContext#load):
```js
function plugin() {
return {
name: 'test',
buildStart() {
// trigger loading a module. We could also pass an initial
// "meta" object here, but it would be ignored if the module
// was already loaded via other means
this.load({ id: 'my-id' });
// the module info is now available, we do not need to await
// this.load
const meta = this.getModuleInfo('my-id').meta;
// we can also modify meta manually now
meta.test = { some: 'data' };
},
};
}
```
## Direct plugin communication
For any other kind of inter-plugin communication, we recommend the pattern below. Note that `api` will never conflict with any upcoming plugin hooks.
```js
function parentPlugin() {
return {
name: 'parent',
api: {
//...methods and properties exposed for other plugins
doSomething(...args) {
// do something interesting
},
},
// ...plugin hooks
};
}
function dependentPlugin() {
let parentApi;
return {
name: 'dependent',
buildStart({ plugins }) {
const parentName = 'parent';
const parentPlugin = plugins.find((plugin) => plugin.name === parentName);
if (!parentPlugin) {
// or handle this silently if it is optional
throw new Error(`This plugin depends on the "${parentName}" plugin.`);
}
// now you can access the API methods in subsequent hooks
parentApi = parentPlugin.api;
},
transform(code, id) {
if (thereIsAReasonToDoSomething(id)) {
parentApi.doSomething(id);
}
},
};
}
```
## Descriptive metadata
Plugins can attach descriptive metadata to modules and to themselves. This metadata does is only informational and intended to be surfaced by tooling that inspects a build, for example [Vite devtools](https://github.com/vitejs/devtools).
### Module descriptions
Tools often show a module by its id, which is often opaque. For example, `\0vite/modulepreload-polyfill.js` gives no hint about what the module is. This is useful for virtual modules. A plugin can attach a human-readable [`description`](/reference/Interface.ModuleOptions#description) to a module, returned from the [`resolveId`](/reference/Interface.Plugin#resolveid), [`load`](/reference/Interface.Plugin#load), or [`transform`](/reference/Interface.Plugin#transform) hooks.
```js
function modulePreloadPolyfillPlugin() {
return {
name: 'vite:modulepreload-polyfill',
load: {
filter: { id: /^\0vite\/modulepreload-polyfill\.js$/ },
handler(id) {
return {
code: '/* ... */',
description: 'A polyfill for `link` tag with `rel="modulepreload"`',
};
},
},
};
}
```
### Plugin metadata
A single package often ships several plugins, and a plugin's `name` does not always reveal which package it came from. A plugin can declare its originating package name and version via the [`meta`](/reference/Interface.Plugin#meta) property of the plugin object, letting tooling attribute and group plugins by package. It is also possible to attach a short description of what the plugin does via the `description` property.
```js
function vuePlugin() {
return {
name: 'vite:vue',
meta: {
packageName: '@vitejs/plugin-vue',
version: '5.0.0',
description: 'Handles Vue single-file components',
},
// ...plugin hooks
};
}
```
See the [`PluginMeta`](/reference/Interface.PluginMeta) type for the full shape.
---
---
url: /apis/cli.md
---
# Command Line Interface
Rolldown can be used from the command line. You can provide an optional Rolldown configuration file to simplify command line usage and enable advanced Rolldown functionality.
## Configuration Files
Rolldown configuration files are optional, but they are powerful and convenient and thus **recommended**.
A config file is an ES module that exports a default object with the desired options.
Typically, it is called `rolldown.config.js` and sits in the root directory of your project.
You can also use CJS syntax in CJS files, which uses `module.exports` instead of `export default`.
Rolldown also natively supports TypeScript configuration files.
Consult the [reference](/reference/) for a comprehensive list of options you can include in your config file.
```js [rolldown.config.js]
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs',
},
};
```
To use a config file with Rolldown, pass the `-c` (or `--config`) flag:
```shell
rolldown -c # use rolldown.config.{js,mjs,cjs,ts,mts,cts}
rolldown --config # same as above
rolldown -c my.config.js # use a custom config file
```
If you don't pass a file name, Rolldown will try to load `rolldown.config.{js,mjs,cjs,ts,mts,cts}` in the working directory.
If no config file is found, Rolldown will show an error.
You can also export a function from your config file. The function will be called with command line arguments so you can dynamically adapt your configuration:
```js [rolldown.config.js]
import { defineConfig } from 'rolldown';
export default defineConfig((commandLineArgs) => {
if (commandLineArgs.watch) {
// watch-specific config
}
return {
input: 'src/main.js',
};
});
```
### Config Loaders
By default Rolldown loads a config file by bundling it with Rolldown first (`configLoader: 'bundle'`). This works on any supported runtime, including for TypeScript configs.
If your runtime can import the config directly (Node.js 22.18+ (native TypeScript type stripping), Bun, Deno, or a loader registered via `--import` (e.g. `tsx`, `jiti`)), you can skip the bundling step with the `native` loader:
```shell
rolldown -c rolldown.config.ts --configLoader native
```
The `native` loader is more simple and is planned to be the default in the future.
### Config Intellisense
Since Rolldown ships with TypeScript typings, you can leverage your IDE's intellisense with JSDoc type hints:
```js [rolldown.config.js]
/** @type {import('rolldown').RolldownOptions} */
export default {
// ...
};
```
Alternatively you can use the `defineConfig` helper, which provides intellisense without the need for JSDoc annotations:
```js [rolldown.config.js]
import { defineConfig } from 'rolldown';
export default defineConfig({
// ...
});
```
### Configuration Arrays
To build different bundles from different inputs, you can supply an array of configuration objects:
```js [rolldown.config.js]
import { defineConfig } from 'rolldown';
export default defineConfig([
{
input: 'src/main.js',
output: { format: 'esm', entryFileNames: 'bundle.esm.js' },
},
{
input: 'src/main.js',
output: { format: 'cjs', entryFileNames: 'bundle.cjs.js' },
},
]);
```
::: tip Different outputs with same inputs
You can also supply an array for the `output` option to generate multiple outputs from the same input:
```js [rolldown.config.js]
import { defineConfig } from 'rolldown';
export default defineConfig({
input: 'src/main.js',
output: [
{ format: 'esm', entryFileNames: 'bundle.esm.js' },
{ format: 'cjs', entryFileNames: 'bundle.cjs.js' },
],
});
```
:::
## Command Line Flags
Flags can be passed as `--foo`, `--foo `, or `--foo=`. Boolean flags like `--minify` don't need a value, while key-value options like `--transform.define` use comma-separated syntax: `--transform.define key:value,key2:value2`. Many flags have short aliases (e.g., `-m` for `--minify`, `-f` for `--format`).
::: warning Disabling boolean flags
To turn a boolean flag *off*, prefix it with `--no-`, e.g. `--no-minify` or `--no-codeSplitting`. Passing `false` as a value—`--minify false` or `--codeSplitting=false`—is **not** supported and will error, because the value is read as the string `"false"` rather than a boolean. This matches [Rollup's CLI behavior](https://rollupjs.org/command-line-interface/) (`--no-treeshake`, etc.).
Some flags accept either a boolean or an object (e.g. `codeSplitting`). For those you can:
* enable with defaults: `--codeSplitting`
* disable: `--no-codeSplitting`
* set nested fields with dot-notation: `--codeSplitting.minSize 30000`
:::
::: info Integration into other tools
Note that your shell interprets arguments before Rolldown sees them—quotes and wildcards may behave unexpectedly. For advanced build processes or integration into other tools, consider using the [JavaScript API](/apis/bundler-api) instead. Key differences when switching from config files to the API:
* Configuration must be an object (not a Promise or function)
* Run [`rolldown.rolldown`](/reference/Function.rolldown) separately for each set of `inputOptions` (no config arrays)
* Use [`bundle.generate(outputOptions)`](/reference/Interface.RolldownBuild#generate) or [`bundle.write(outputOptions)`](/reference/Interface.RolldownBuild#write) instead of the `output` option
:::
Many options have command line flag equivalents.
See the [reference](/reference/) for details of those flags.
In those cases, any arguments passed here will override the config file, if you're using one.
This is a list of all supported flags:
```sh-vue
{{ data.help }}
```
The flags listed below are only available via the command line interface.
### `-c, --config `
Use the specified config file. If the argument is used but no filename is specified, Rolldown will look for a default config file. See [Configuration Files](#configuration-files) for more details.
### `--configLoader `
How to load the config file. One of:
* `bundle` (default): bundle the config with Rolldown before importing it.
* `native`: import the config directly, relying on the runtime for TypeScript and loader support. See [Config Loaders](#config-loaders).
### `-h` / `--help`
Show the help message.
### `-v` / `--version`
Show the installed version number.
### `-w` / `--watch`
Rebuild the bundle when source files change on disk.
::: info `ROLLDOWN_WATCH` env
While in watch mode, the `ROLLDOWN_WATCH` and `ROLLUP_WATCH` environment variable will be set to `true` by Rolldown's command line interface and can be checked by other processes. Plugins should instead check [`this.meta.watchMode`](/reference/Interface.PluginContextMeta#watchmode), which is independent of the command line interface.
:::
### `--environment `
Pass additional settings to the config file via `process.env`.
Values are comma-separated key-value pairs, where a value of `true` can be omitted.
For example:
```shell
rolldown -c --environment INCLUDE_DEPS,BUILD:production
```
This will set `process.env.INCLUDE_DEPS = 'true'` and `process.env.BUILD = 'production'`.
You can invoke this option multiple times.
In that case, subsequently set variables will overwrite previous definitions.
::: tip Overwriting the values
If you have `package.json` scripts:
```json
{
"scripts": {
"build": "rolldown -c --environment BUILD:production"
}
}
```
you can call this script with `npm run build -- --environment BUILD:development` to set `process.env.BUILD="development"`.
:::
---
---
url: /apis/rust-crates.md
---
# Rust Crates
Rolldown is also provided as a Rust crate on crates.io.
The main crate is the [rolldown](https://crates.io/crates/rolldown) crate.
## Maintenance Policy
Before using the crates, make sure to understand the following policies:
* The crates will not follow the semver contract. Breaking changes may be introduced freely in any version.
* The documentation for the crates will not be provided.
* Any issues that only affect for the Rust crates will not be worked on as a team and will be closed. That said, we will accept pull requests for those use cases.
The JS package is our focus and we would like to reduce the maintenance cost of the crates as much as possible. If there's a long-time contributor who is willing to take on the maintenance of this area, we are open to revisiting the last two policies.
---
---
url: /contribution-guide.md
---
# Contribution Guide
Contributions are always welcome, no matter how large or small! Here we summarize some general guidelines on how you can get involved in the Rolldown project.
## Open development
All development happens directly on [GitHub](https://github.com/rolldown/rolldown). Both core team members and external contributors (via forks) send pull requests which go through the same review process.
Outside of GitHub, we also use a [Discord server](https://chat.rolldown.rs) for real-time discussions.
## AI Usage Policy
When using AI tools (including LLMs like ChatGPT, Claude, Copilot, etc.) to contribute to Rolldown:
* **Please disclose AI usage** to reduce maintainer fatigue
* **Discuss before you open a pull request when the change calls for it** — follow the same rules as [Submitting a pull request](#submitting-a-pull-request) below; if you're unsure which path applies, open an issue first
* **You are responsible** for all AI-generated issues or PRs you submit
* **Low-quality or unreviewed AI content will be closed immediately**
* **Contributors who submit repeated low-quality ("slop") PRs will be banned without prior warning.** Bans may be lifted if you commit to contributing to Rolldown in accordance with this policy. You may request an unban via our [Discord](https://chat.rolldown.rs/).
We encourage the use of AI tools to assist with development, but all contributions must be thoroughly reviewed and tested by the contributor before submission. AI-generated code should be understood, validated, and adapted to meet Rolldown's standards.
## Reporting a bug
Please open a bug report on GitHub only after searching the existing issues and finding no match. Be as descriptive as possible, and include all applicable labels.
The best way to get your bug fixed is to include a minimal reproduction — a public repository with a runnable example, a usable code snippet, or a link to our [REPL](https://repl.rolldown.rs/) for a quick in-browser repro.
## Requesting new functionality
Before requesting new functionality, search the [open issues](https://github.com/rolldown/rolldown/issues) — someone may have requested it already. If not, open an issue with the title prefixed with `[request]`. Be as descriptive as possible, and include all applicable labels.
## Submitting a pull request
We welcome pull requests for bugs, fixes, improvements, and new features. Before you open one, please check which of the two paths below applies to your change: [send it directly](#send-a-pull-request-directly), or [discuss the approach first](#discuss-the-approach-first). Either way, be sure your build passes locally before you submit.
For setting up the project's development environment, see [Project Setup](../development-guide/setup-the-project.md).
> \[!NOTE]
> Please read the [Etiquette](https://developer.mozilla.org/en-US/docs/MDN/Community/Open_source_etiquette) chapter before submitting a pull request.
### Send a pull request directly
No prior discussion is needed for changes whose correctness speaks for itself:
* Clear bug fixes where the expected behavior is unambiguous
* Documentation, typo, and comment fixes
* Tests for existing behavior
* Small, self-contained internal cleanups with no user-facing change
If there's a related issue, link it in your pull request.
### Discuss the approach first
For the changes below, please open or comment on an issue and reach agreement with the team **before** you start coding or open a pull request:
* New features and new public APIs
* Changes to existing public APIs or to default behavior
* Fixes for an issue that doesn't yet have an agreed-upon approach in the thread
For these changes, the hard part is usually agreeing on the right direction, not writing the code. Talking it through first means your work goes into something we can merge, instead of stalling while the direction is still being worked out.
If you open a pull request in this category without that agreement, we may close it. **Closing it is not a rejection of your work, or of you as a contributor.** It only means the change needs to go through the discussion process first. If you want to drive it forward, share your thinking on the linked issue or in our [Discord](https://chat.rolldown.rs) — once there's agreement on the direction, the pull request is very welcome.
### Draft pull requests
If your pull request is still a work in progress, please open it as a [draft](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request) and only mark it **Ready for review** once you genuinely want the team to review it. Converting a PR to "Ready for review" notifies reviewers and code owners, so please hold off until your changes are complete and your build passes locally. This keeps maintainers' inboxes focused on PRs that actually need attention.
### Branch organization
Submit all pull requests directly to the `main` branch. We only use separate branches for upcoming releases or breaking changes; otherwise, everything targets `main`.
Code that lands in `main` must be compatible with the latest stable release. It may contain additional features, but no breaking changes. We should be able to release a new minor version from the tip of `main` at any time.
---
---
url: /acknowledgements.md
---
# Acknowledgements
The Rolldown project was originally created by [Yinan Long](https://github.com/Brooooooklyn) (aka Brooooooklyn, author of [NAPI-RS](https://napi.rs/)). Today, Rolldown is led by [Evan You](https://github.com/yyx990803) (the creator of [Vite](https://vitejs.dev/)) together with a full-time [team](./team.md) and passionate open source [contributors](https://github.com/rolldown/rolldown/graphs/contributors).
## Past contributors
We’d like to recognize a few people who are former team members or have made significant contributions to the project, documentation, and its ecosystem (listed in alphabetical order):
This list is not exhaustive.
## Additional Thanks
Additionally, we’re grateful to:
* [Charlike Mike Reagent](https://github.com/tunnckoCore) for letting us use the `rolldown` package name on npm
---
---
url: /glossary.md
---
# Glossary
Common terms and concepts used in Rolldown documentation.
## B
* [Barrel Module](./barrel-module.md)
## E
* [Entry](./entry.md)
* [Entry Chunk](./entry-chunk.md)
* [Entry Name](./entry-name.md)
## U
* [User-defined Entry](./user-defined-entry.md)
---
---
url: /reference/Interface.ChecksOptions.md
---
# Interface: ChecksOptions
See [InputOptions.checks](InputOptions.checks.md)
---
---
url: /reference/Interface.CommentsOptions.md
---
# Interface: CommentsOptions
See [OutputOptions.comments](OutputOptions.comments.md)
---
---
url: /reference/Interface.GeneratedCodeOptions.md
---
# Interface: GeneratedCodeOptions
See [OutputOptions.generatedCode](OutputOptions.generatedCode.md)
---
---
url: /reference/Interface.InputOptions.md
---
# Interface: InputOptions
## Extended by
* [`RolldownOptions`](Interface.RolldownOptions.md)
* [`WatchOptions`](Interface.WatchOptions.md)
## Properties
### checks?
* **Type**: [`ChecksOptions`](Interface.ChecksOptions.md)
* **Optional**
Controls which warnings are emitted during the build process. Each option can be set to `true` (emit warning) or `false` (suppress warning).
***
### context?
* **Type**: `string`
* **Optional**
The value of `this` at the top level of each module. **Normally, you don't need to set this option.**
#### Default
```ts
undefined
```
#### Example
**Set custom context**
```js
export default {
context: 'globalThis',
output: {
format: 'iife',
},
};
```
#### In-depth
The `context` option controls what `this` refers to in the top-level scope of the input modules.
In ES modules, the `this` value is `undefined` by specification. This option allows you to set a different value. For example, if your input modules expect `this` to be `window` like in non-ES module scripts, you can set `context` to `'window'`.
Note that if the input module is detected as CommonJS, Rolldown will use `exports` as the `this` value regardless of this option.
***
### cwd?
* **Type**: `string`
* **Optional**
The working directory to use when resolving relative paths in the configuration.
#### Default
```ts
process.cwd()
```
***
### devtools?
* **Type**: object with the properties below
* **Optional**
* **Experimental**
Devtools integration options.
When enabled, Rolldown writes JSON-lines devtools output under
`node_modules/.rolldown/{session_id}/`, resolved against [`cwd`](#cwd).
Consumers can parse the output with `@rolldown/debug` after
`await bundle.close()` resolves.
#### sessionId?
* **Type**: `string`
* **Optional**
***
### experimental?
* **Type**: object with the properties below
* **Optional**
* **Experimental**
Experimental features that may change in future releases and can introduce behavior change without a major version bump.
#### attachDebugInfo?
* **Type**: `"none"` | `"simple"` | `"full"`
* **Optional**
Attach debug information to the output bundle.
Available modes:
* `none`: No debug information is attached.
* `simple`: Attach comments indicating which files the bundled code comes from. These comments could be removed by the minifier.
* `full`: Attach detailed debug information to the output bundle. These comments are using legal comment syntax, so they won't be removed by the minifier.
##### Default
'simple'
##### In-depth
Each chunk will include a comment explaining the reason why it was created:
| Reason | Format | Description |
| --------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| User-defined Entry | `User-defined Entry: [Entry-Module-Id: ] [Name: Some("")]` | Explicit entry point from build config |
| Dynamic Entry | `Dynamic Entry: [Entry-Module-Id: ] [Name: None]` | Chunk created from `import()` expression |
| Common Chunk | `Common Chunk: [Shared-By: , , ...]` | Shared modules extracted for multiple entries |
| Manual Code Splitting | `ManualCodeSplitting: [Group-Name: ]` | Chunk created by [`output.codeSplitting`](/reference/OutputOptions.codeSplitting) option |
| Preserve Modules | `Enabling Preserve Module: [User-defined: ] [Module-Id: ]` | Per-module chunk from [`output.preserveModules`](/reference/OutputOptions.preserveModules) option |
When rolldown optimized away empty facade chunks (entry chunks with no modules of their own), the target chunk will include `Eliminated Facade Chunk: [Chunk-Name: ] [Entry-Module-Id: ]`.
#### chunkImportMap?
* **Type**: `boolean` | { `baseUrl?`: `string`; `fileName?`: `string`; }
* **Optional**
Enables automatic generation of a chunk import map asset during build.
This map only includes chunks with hashed filenames, where keys are derived from the facade module
name or primary chunk name. It produces stable and unique hash-based filenames, effectively preventing
cascading cache invalidation caused by content hashes and maximizing browser cache reuse.
The output defaults to `importmap.json` unless overridden via `fileName`. A base URL prefix
(default `"/"`) can be applied to all paths. The resulting JSON is a valid import map and can be
directly injected into HTML via `/i,
``
);
fs.writeFileSync(htmlPath, html);
delete bundle['importmap.json'];
}
}
}
]
}
```
> \[!TIP]
> If you want to learn more, you can check out the example here: [examples/chunk-import-map](https://github.com/rolldown/rolldown/tree/main/examples/chunk-import-map)
##### Default
```ts
false
```
#### chunkModulesOrder?
* **Type**: `"exec-order"` | `"module-id"`
* **Optional**
Control which order should be used when rendering modules in a chunk.
Available options:
* `exec-order`: Almost equivalent to the topological order of the module graph, but specially handling when module graph has cycle.
* `module-id`: This is more friendly for gzip compression, especially for some javascript static asset lib (e.g. icon library)
> \[!NOTE]
> Try to sort the modules by their module id if possible (Since rolldown scope hoist all modules in the chunk, we only try to sort those modules by module id if we could ensure runtime behavior is correct after sorting).
##### Default
```ts
'exec-order'
```
#### chunkOptimization?
* **Type**: `boolean` | [`ChunkOptimizationOptions`](Interface.ChunkOptimizationOptions.md)
* **Optional**
Control chunk optimizations.
`true` enables both common-chunk merging and redundant dynamic chunk-load avoidance.
`false` disables all chunk optimizations. Use the object form to control
`mergeCommonChunks` and `avoidRedundantChunkLoads` separately.
These optimizations are automatically disabled when any module uses top-level await (TLA) or contains TLA dependencies,
as they could affect execution order guarantees.
##### Default
```ts
true
```
#### incrementalBuild?
* **Type**: `boolean`
* **Optional**
Enable incremental build support. Required to be used with `watch` mode.
##### Default
```ts
false
```
#### lazyBarrel?
* **Type**: `boolean`
* **Optional**
Control whether to enable lazy barrel optimization.
Lazy barrel optimization avoids compiling unused re-export modules in side-effect-free barrel modules,
significantly improving build performance for large codebases with many barrel modules.
This option is planned to be removed in the future. If you need to opt out, please open an issue
describing your use case so we can address it before the option is gone.
##### See
[Lazy Barrel Documentation](/in-depth/lazy-barrel-optimization)
##### Default
```ts
false
```
#### nativeMagicString?
* **Type**: `boolean`
* **Optional**
Use native Rust implementation of MagicString for source map generation.
[MagicString](https://github.com/rich-harris/magic-string) is a JavaScript library commonly used by bundlers
for string manipulation and source map generation. When enabled, rolldown will use a native Rust
implementation of MagicString instead of the JavaScript version, providing significantly better performance
during source map generation and code transformation.
**Benefits**
* **Improved Performance**: The native Rust implementation is typically faster than the JavaScript version,
especially for large codebases with extensive source maps.
* **Background Processing**: Source map generation is performed asynchronously in a background thread,
allowing the main bundling process to continue without blocking. This parallel processing can significantly
reduce overall build times when working with JavaScript transform hooks.
* **Better Integration**: Seamless integration with rolldown's native Rust architecture.
##### Example
```js
export default {
experimental: {
nativeMagicString: true
},
output: {
sourcemap: true
}
}
```
> \[!NOTE]
> This is an experimental feature. While it aims to provide identical behavior to the JavaScript
> implementation, there may be edge cases. Please report any discrepancies you encounter.
> For a complete working example, see [examples/native-magic-string](https://github.com/rolldown/rolldown/tree/main/examples/native-magic-string)
##### Default
```ts
false
```
#### resolveNewUrlToAsset?
* **Type**: `boolean`
* **Optional**
When enabled, `new URL()` calls will be transformed to a stable asset URL which includes the updated name and content hash.
It is necessary to pass `import.meta.url` as the second argument to the
`new URL` constructor, otherwise no transform will be applied.
:::warning
JavaScript and TypeScript files referenced via `new URL('./file.js', import.meta.url)` or `new URL('./file.ts', import.meta.url)` will **not** be transformed or bundled. The file will be copied as-is, meaning TypeScript files remain untransformed and dependencies are not resolved.
The expected behavior for JS/TS files is still being discussed and may
change in future releases. See [#7258](https://github.com/rolldown/rolldown/issues/7258) for more context.
:::
##### Example
```js
// main.js
const url = new URL('./styles.css', import.meta.url);
console.log(url);
// Example output after bundling WITHOUT the option (default)
const url = new URL('./styles.css', import.meta.url);
console.log(url);
// Example output after bundling WITH `experimental.resolveNewUrlToAsset` set to `true`
const url = new URL('assets/styles-CjdrdY7X.css', import.meta.url);
console.log(url);
```
##### Default
```ts
false
```
***
### external?
* **Type**: `string` | `RegExp` | (`string` | `RegExp`)\[] | [`ExternalOptionFunction`](TypeAlias.ExternalOptionFunction.md)
* **Optional**
Specifies which modules should be treated as external and not bundled. External modules will be left as import statements in the output.
When creating an `iife` or `umd` bundle, you will need to provide global variable names to replace your external imports via the [`output.globals`](/reference/OutputOptions.globals) option.
#### How Matching Works
The `external` option is checked **twice** during module resolution, against two different kinds of IDs:
1. **First check — raw import specifier** (e.g. `'lodash'`, `'./utils'`) is tested before any resolution happens, with `isResolved: false`. To mark `import "dependency"` as external, use `"dependency"` exactly as written in the import statement. If it matches, the module is immediately marked as external — **plugins and the internal resolver are skipped entirely**.
2. **Second check — resolved ID** (e.g. `'/project/node_modules/vue/dist/vue.runtime.esm-bundler.js'`) is tested after plugins and the internal resolver have run, with `isResolved: true`. If it matches, the module is marked as external.
The second check only runs if the first did not match. In both cases, [`makeAbsoluteExternalsRelative`](/reference/InputOptions.makeAbsoluteExternalsRelative) applies uniformly to determine whether absolute IDs are re-relativized in the output.
See the [External Modules guide](/in-depth/external-modules) for a detailed explanation of the full resolution flow and how the output path is determined.
#### Examples
##### String pattern
```js
export default {
external: 'react',
};
```
##### Regular expression
```js
export default {
external: /^react\//,
};
```
##### Array of patterns
```js
export default {
external: ['react', 'react-dom', /^lodash/],
};
```
##### Function
```js
import path from 'node:path';
export default {
external: (id) => {
return !id.startsWith('.') && !path.isAbsolute(id);
},
};
```
::: warning Performance Overhead
Using the function form has significant performance overhead because Rolldown is written in Rust and must call JavaScript functions from Rust for every module in your dependency graph.
Unless the logic relies on values other than `id`, it is recommended to use non-function values.
:::
#### Caveats
##### Avoid `/node_modules/` for npm packages
Because the pattern `/node_modules/` can only match on the **second check** (the resolved absolute path), the full resolved path like `/path/to/node_modules/vue/dist/vue.runtime.esm-bundler.js` ends up in the output verbatim. This makes the output non-portable.
Instead, match packages by name or use a pattern for bare module IDs:
```js
export default {
// Exact package names
external: ['vue', 'react', 'react-dom'],
// Package name patterns
external: [/^vue/, /^react/, /^@mui/],
// All bare module IDs (not starting with `.` or `/` or `C:\`)
external: /^[^./](?!:[/\\])/,
};
```
***
### input?
* **Type**: `string` | `string`\[] | `Record`<`string`, `string`>
* **Optional**
Defines entries and location(s) of entry modules for the bundle. Relative paths are resolved based on the [`cwd`](#cwd) option.
#### Examples
##### Single entry
```js
export default defineConfig({
input: 'src/index.js',
});
```
##### Multiple entries
```js
export default defineConfig({
input: ['src/index.js', 'src/vendor.js'],
});
```
##### Named multiple entries
```js
export default defineConfig({
input: {
index: 'src/index.js',
utils: 'src/utils/index.js',
'components/Foo': 'src/components/Foo.js',
},
});
```
#### In-depth
`input` allows you to specify one or more [entries](/glossary/entry) with [names](/glossary/entry-name) for the bundling process.
When multiple entries are specified (either as an array or an object), Rolldown will create separate [entry chunks](/glossary/entry-chunk) for each entry. If a module is referenced from multiple entries, Rolldown will share the code of that module for those entries.
The generated chunk names will follow the [`output.chunkFileNames`](/reference/OutputOptions.chunkFileNames) option. When using the object form, the `[name]` portion of the file name will be the name of the object property while for the array form, it will be the file name of the entry point. Note that it is possible when using the object form to put entry points into different sub-folders by adding a `/` to the name.
If you want to convert a set of files to another format while maintaining the file structure and export signatures, the recommended way—instead of using [`output.preserveModules`](/reference/OutputOptions.preserveModules) that may tree-shake exports as well as emit virtual files created by plugins—is to turn every file into an entry point. You can do so dynamically e.g. via the [`tinyglobby`](https://github.com/SuperchupuDev/tinyglobby) package:
```js
import { defineConfig } from 'rolldown';
import { globSync } from 'tinyglobby';
import path from 'node:path';
export default defineConfig({
input: Object.fromEntries(
globSync('src/**/*.js').map((file) => [
// This removes `src/` as well as the file extension from each
// file, so e.g. src/nested/foo.js becomes nested/foo, and
// normalizes Windows backslashes to forward slashes.
path
.relative('src', file.slice(0, file.length - path.extname(file).length))
.split(path.sep)
.join('/'),
// This expands the relative paths to absolute paths, so e.g.
// src/nested/foo.js becomes /project/src/nested/foo.js
path.resolve(file),
]),
),
output: {
dir: 'dist',
format: 'esm',
},
});
```
***
### logLevel?
* **Type**: `"info"` | `"debug"` | `"warn"` | `"silent"`
* **Optional**
Controls the verbosity of console logging during the build.
The default logLevel of "info" means that info and warnings logs will be processed while debug logs will be swallowed, which means that they are neither passed to plugin [`onLog`](/reference/Interface.Plugin#onlog) hooks nor the [`onLog`](/reference/InputOptions.onLog) option or printed to the console.
#### Default
```ts
'info'
```
***
### makeAbsoluteExternalsRelative?
* **Type**: `false` | `true` | `"ifRelativeSource"`
* **Optional**
Determines if absolute external paths should be converted to relative paths in the output.
This does not only apply to paths that are absolute in the source but also to paths that are resolved to an absolute path by either a plugin or Rolldown core.
Despite the name, this option controls two things:
1. **Resolve-time normalization** — whether relative specifiers (e.g. `'./utils'`) are normalized to absolute paths internally for deduplication. Without normalization, `'./utils'` imported from different directories may collapse into one external module because they share the same raw string.
2. **Render-time output** — whether a resolved module ID (the absolute path after resolution) gets converted to a relative path in the output. It does not affect bare specifiers (e.g. `'lodash'`) or IDs that are already relative.
Both behaviors depend on the **original import specifier** (what you wrote in source code, e.g. `'./utils'`) vs the **resolved module ID** (the absolute path after resolution, e.g. `'/project/src/utils.js'`). See the [External Modules guide](/in-depth/external-modules) for how this fits into the full resolution flow.
#### Values
##### `"ifRelativeSource"` (default)
Only convert the resolved absolute ID to a relative path if the **original import specifier** was relative.
```js
// Original: relative specifier → converted to relative in output
import './lib/utils.js'; // → import './lib/utils.js'
// Original: absolute specifier → kept absolute in output
import '/project/lib/utils.js'; // → import '/project/lib/utils.js'
```
The idea: if you wrote a relative import, you probably want a relative import in the output. If you wrote an absolute import, you probably meant it to stay absolute.
##### `true`
Always convert resolved absolute IDs to relative paths:
```js
// Both become relative in output
import './lib/utils.js'; // → import './lib/utils.js'
import '/project/lib/utils.js'; // → import '../lib/utils.js'
```
When converting an absolute path to a relative path, Rolldown does *not* take the [`file`](/reference/OutputOptions.file) or [`dir`](/reference/OutputOptions.dir) options into account, because those may not be present e.g. for builds using the JavaScript API. Instead, it assumes that the root of the generated bundle is located at the common shared parent directory of all entry points.
If the output chunk is itself nested in a subdirectory by choosing e.g. `chunkFileNames: "chunks/[name].js"`, the relative path is adjusted accordingly.
##### `false`
Never convert. Resolved absolute IDs are kept as-is. Relative specifiers are also **not** normalized to absolute paths internally, which means two files importing `'./utils'` from different directories may be treated as the same external module.
```js
import './lib/utils.js'; // → import './lib/utils.js' (as-is)
import '/project/lib/utils.js'; // → import '/project/lib/utils.js' (as-is)
```
::: warning Deduplication issue with `false`
Setting `makeAbsoluteExternalsRelative: false` disables the normalization of relative specifiers. This means `'./utils'` imported from `src/a.js` and `'./utils'` imported from `src/b/c.js` may be treated as the same external module, even though they refer to different files. Use `false` only if you are certain all your external specifiers are already unique (e.g. bare package names).
:::
#### Example
Given `import '/project/lib/utils.js'` (absolute specifier) in an external module, with output at `dist/index.js`:
| `makeAbsoluteExternalsRelative` | Output path |
| ------------------------------- | ------------------------- |
| `true` | `'../lib/utils.js'` |
| `"ifRelativeSource"` (default) | `'/project/lib/utils.js'` |
| `false` | `'/project/lib/utils.js'` |
Given `import './lib/utils.js'` (relative specifier) with a flat output at `dist/index.js`:
| `makeAbsoluteExternalsRelative` | Output path |
| ------------------------------- | ------------------ |
| `true` | `'./lib/utils.js'` |
| `"ifRelativeSource"` (default) | `'./lib/utils.js'` |
| `false` | `'./lib/utils.js'` |
The same relative specifier with a nested chunk at `dist/chunks/index.js`:
| `makeAbsoluteExternalsRelative` | Output path |
| ------------------------------- | ------------------- |
| `true` | `'../lib/utils.js'` |
| `"ifRelativeSource"` (default) | `'../lib/utils.js'` |
| `false` | `'./lib/utils.js'` |
With `true` or `"ifRelativeSource"`, relative specifiers are normalized to absolute paths internally, then re-relativized from the output chunk's location — so the path adjusts correctly for nested chunks. With `false`, the raw specifier is kept as-is with no adjustment.
***
### moduleTypes?
* **Type**: [`ModuleTypes`](TypeAlias.ModuleTypes.md)
* **Optional**
Maps file patterns to module types, controlling how files are processed.
This is conceptually similar to [esbuild's `loader`](https://esbuild.github.io/api/#loader) option, allowing you to specify how each file extensions should be handled.
See [the In-Depth Guide](/in-depth/module-types) for more details.
#### Example
```js
import { defineConfig } from 'rolldown'
export default defineConfig({
moduleTypes: {
'.frag': 'text',
}
})
```
***
### onLog?
* **Type**: (`level`, `log`, `defaultHandler`) => `void`
* **Optional**
A function that intercepts log messages. If not supplied, logs are printed to the console.
This handler will not be invoked if logs are filtered out by the [`logLevel`](/reference/InputOptions.logLevel) option. I.e. by default, `"debug"` logs will be swallowed.
If the default handler is not invoked, the log will not be printed to the console. Moreover, you can change the log level by invoking the default handler with a different level. Using the additional level `"error"` will turn the log into a thrown error that has all properties of the log attached.
#### Parameters
##### level
`"info"` | `"debug"` | `"warn"`
##### log
[`RolldownLog`](Interface.RolldownLog.md)
##### defaultHandler
[`LogOrStringHandler`](TypeAlias.LogOrStringHandler.md)
#### Returns
`void`
#### Example
```js
export default defineConfig({
onLog(level, log, defaultHandler) {
if (log.code === 'CIRCULAR_DEPENDENCY') {
return; // Ignore circular dependency warnings
}
if (level === 'warn') {
defaultHandler('error', log); // turn other warnings into errors
} else {
defaultHandler(level, log); // otherwise, just print the log
}
}
})
```
***
### ~~onwarn?~~
* **Type**: (`warning`, `defaultHandler`) => `void`
* **Optional**
A function that will intercept warning messages.
If the default handler is invoked, the log will be handled as a warning. If both an `onLog` and `onwarn` handler are provided, the `onwarn` handler will only be invoked if `onLog` calls its default handler with a `level` of `"warn"`.
#### Parameters
##### warning
[`RolldownLog`](Interface.RolldownLog.md)
##### defaultHandler
(`warning`) => `void`
#### Returns
`void`
#### Deprecated
This is a legacy API. Consider using [`onLog`](#onlog) instead for better control over all log types.
To migrate from `onwarn` to `onLog`, check the `level` parameter to filter for warnings:
```js
// Before: Using `onwarn`
export default {
onwarn(warning, defaultHandler) {
// Suppress certain warnings
if (warning.code === 'CIRCULAR_DEPENDENCY') return;
// Handle other warnings with default behavior
defaultHandler(warning);
},
};
```
```js
// After: Using `onLog`
export default {
onLog(level, log, defaultHandler) {
// Handle only warnings (same behavior as `onwarn`)
if (level === 'warn') {
// Suppress certain warnings
if (log.code === 'CIRCULAR_DEPENDENCY') return;
// Handle other warnings with default behavior
defaultHandler(level, log);
} else {
// Let other log levels pass through
defaultHandler(level, log);
}
},
};
```
***
### optimization?
* **Type**: [`OptimizationOptions`](TypeAlias.OptimizationOptions.md)
* **Optional**
Configure optimization features for the bundler.
***
### platform?
* **Type**: `"node"` | `"browser"` | `"neutral"`
* **Optional**
Expected platform where the code run.
When the platform is set to neutral:
* When bundling is enabled the default output format is set to esm, which uses the export syntax introduced with ECMAScript 2015 (i.e. ES6). You can change the output format if this default is not appropriate.
* The main fields setting is empty by default. If you want to use npm-style packages, you will likely have to configure this to be something else such as main for the standard main field used by node.
* The conditions setting does not automatically include any platform-specific values.
#### Default
* `'node'` if the format is `'cjs'`
* `'browser'` for other formats
#### Examples
##### Browser platform
```js
export default {
platform: 'browser',
output: {
format: 'esm',
},
};
```
##### Node.js platform
```js
export default {
platform: 'node',
output: {
format: 'cjs',
},
};
```
##### Platform-neutral
```js
export default {
platform: 'neutral',
output: {
format: 'esm',
},
};
```
#### In-depth
The platform setting provides sensible defaults for module resolution and environment-specific behavior, similar to esbuild's `platform` option.
##### `'node'`
Optimized for Node.js environments:
* **Conditions**: Includes `'node'`, `'import'`, `'require'` based on output format
* **Main fields**: `['main', 'module']`
* **Target**: Node.js runtime behavior
* **process.env handling**: Preserves `process.env.NODE_ENV` and other Node.js globals
##### `'browser'`
Optimized for browser environments:
* **Conditions**: Includes `'browser'`, `'import'`, `'module'`, `'default'`
* **Main fields**: `['browser', 'module', 'main']` - prefers browser-specific entry points
* **Target**: Browser runtime behavior
* **Built-ins**: Node.js built-in modules are not polyfilled by default
:::tip
For browser builds, you may want to use [rolldown-plugin-node-polyfills](https://github.com/rolldown/rolldown-plugin-node-polyfills) to polyfill Node.js built-ins if needed.
:::
##### `'neutral'`
Platform-agnostic configuration:
* **Default format**: Always `'esm'`
* **Conditions**: Only includes format-specific conditions, no platform-specific ones
* **Main fields**: Empty by default - relies on package.json `"exports"` field
* **Use cases**: Universal libraries that run in multiple environments
##### Difference from esbuild
Notable differences from esbuild's `platform` option:
* The default output format is always `'esm'` regardless of platform (in esbuild, Node.js defaults to `'cjs'`)
##### Choosing a Platform
**Use `'browser'`** when:
* Building for web applications
* Targeting modern browsers with ES modules support
* Need browser-specific package entry points
**Use `'node'`** when:
* Building server-side applications
* Creating CLI tools
* Need Node.js-specific features and modules
**Use `'neutral'`** when:
* Building universal libraries
* Want maximum portability
* Avoiding platform-specific assumptions
***
### plugins?
* **Type**: [`RolldownPluginOption`](TypeAlias.RolldownPluginOption.md)
* **Optional**
The list of plugins to use.
Falsy plugins will be ignored, which can be used to easily activate or deactivate plugins. Nested plugins will be flattened. Async plugins will be awaited and resolved.
See [Plugin API document](/apis/plugin-api) for more details about creating plugins.
#### Example
```js
import { defineConfig } from 'rolldown'
export default defineConfig({
plugins: [
examplePlugin1(),
// Conditional plugins
process.env.ENV1 && examplePlugin2(),
// Nested plugins arrays are flattened
[examplePlugin3(), examplePlugin4()],
]
})
```
***
### preserveEntrySignatures?
* **Type**: `false` | `"strict"` | `"allow-extension"` | `"exports-only"`
* **Optional**
Controls how entry chunk exports are preserved.
This determines whether Rolldown needs to create facade chunks (additional wrapper chunks) to maintain the exact export signatures of entry modules, or whether it can combine entry modules with other chunks for optimization.
#### Default
`'exports-only'`
#### Values
##### `'exports-only'`
Follows `'strict'` behavior for entry modules that have exports, but allows `'allow-extension'` behavior for entry modules without exports.
##### `'strict'`
Entry chunks will exactly match the exports of their corresponding entry modules. If additional internal bindings need to be exposed (for example, when modules are shared between chunks), Rolldown will create facade chunks to maintain the exact export signature.
**Use case:** This is the recommended setting for **libraries** where you need guaranteed, stable export signatures.
##### `'allow-extension'`
Entry chunks can expose all exports from the corresponding entry module, and may also include additional exports from other modules if they're bundled together. This allows more optimization opportunities but may expose internal implementation details.
##### `false`
Provides maximum flexibility. Entry chunks can be merged freely with other chunks regardless of export signatures. This can lead to better optimization but may change the exposed exports significantly.
**Use case:** This is the recommended setting for **application** where you don't need guaranteed, stable export signatures.
#### Understanding Facade Chunks
A facade chunk is a small wrapper chunk that Rolldown creates to preserve the exact export signature of an entry module when the actual implementation has been bundled into another chunk.
**Example scenario:**
If you have two entry points that share code, and `preserveEntrySignatures` is set to `'strict'`, Rolldown might:
1. Bundle the shared code into a common chunk
2. Create facade chunks for each entry point that re-export from the common chunk
3. This ensures each entry point maintains its exact original export signature
#### In-depth
##### Override per Entry Point
The `preserveEntrySignatures` option is a global setting. The only way to override it for individual entry chunks is to use the plugin API and emit those chunks via [`this.emitFile`](/reference/Interface.PluginContext#emitfile) instead of using the [`input`](/reference/InputOptions.input) option.
###### Practical Example: Mixed Library and Application Build
```js
// rolldown.config.js
export default {
preserveEntrySignatures: 'exports-only', // Default for most entries
plugins: [
{
name: 'custom-entries',
buildStart() {
// Library entry that needs strict signature preservation
this.emitFile({
type: 'chunk',
id: 'src/library/index.js',
fileName: 'library.js',
preserveEntrySignature: 'strict',
});
// Application entry that can be optimized
this.emitFile({
type: 'chunk',
id: 'src/app/main.js',
fileName: 'app.js',
preserveEntrySignature: false,
});
},
},
],
};
```
When using `this.emitFile` with type `'chunk'`, you can specify:
* **`preserveEntrySignature`**: Override the global setting
* `false`: Maximum optimization, merge chunks freely
* `'strict'`: Exact export signature preservation
* `'allow-extension'`: Allow additional exports from merged chunks
* `'exports-only'`: Strict only for modules with exports
* **`fileName`**: Custom output filename for the entry chunk
* **`id`**: Module ID or path to use as the entry point
##### When to Use Each Setting
* **`'strict'`**: Building libraries, need guaranteed export signatures
* **`'exports-only'`**: Most applications, balanced approach (default)
* **`'allow-extension'`**: Advanced optimizations, okay with exposing extra exports
* **`false`**: Maximum bundle size reduction, export signatures don't matter
***
### resolve?
* **Type**: object with the properties below
* **Optional**
Options for built-in module resolution feature.
#### alias?
* **Type**: `Record`<`string`, `string` | `false` | `string`\[]>
* **Optional**
Substitute one package for another.
One use case for this feature is replacing a node-only package with a browser-friendly package in third-party code that you don't control.
##### Example
```js
resolve: {
alias: {
'@': '/src',
'utils': './src/utils',
}
}
```
> \[!WARNING]
> `resolve.alias` will not call [`resolveId`](/reference/Interface.Plugin#resolveid) hooks of other plugin.
> If you want to call `resolveId` hooks of other plugin, use `viteAliasPlugin` from `rolldown/experimental` instead.
> You could find more discussion in [this issue](https://github.com/rolldown/rolldown/issues/3615)
#### aliasFields?
* **Type**: `string`\[]\[]
* **Optional**
Fields in package.json to check for aliased paths.
This option is expected to be used for `browser` field support.
##### Default
* `[['browser']]` for `browser` platform
* `[]` for other platforms
#### conditionNames?
* **Type**: `string`\[]
* **Optional**
Condition names to use when resolving exports in package.json.
##### Default
Defaults based on platform and import kind:
* `browser` platform
* `["import", "browser", "default"]` for import statements
* `["require", "browser", "default"]` for require() calls
* `node` platform
* `["import", "node", "default"]` for import statements
* `["require", "node", "default"]` for require() calls
* `neutral` platform
* `["import", "default"]` for import statements
* `["require", "default"]` for require() calls
#### exportsFields?
* **Type**: `string`\[]\[]
* **Optional**
Fields in package.json to check for exports.
##### Default
`[['exports']]`
#### extensionAlias?
* **Type**: `Record`<`string`, `string`\[]>
* **Optional**
Map of extensions to alternative extensions.
With writing `import './foo.js'` in a file, you want to resolve it to `foo.ts` instead of `foo.js`.
You can achieve this by setting: `extensionAlias: { '.js': ['.ts', '.js'] }`.
#### extensions?
* **Type**: `string`\[]
* **Optional**
Extensions to try when resolving files. These are tried in order from first to last.
##### Default
`['.tsx', '.ts', '.jsx', '.js', '.json']`
#### mainFields?
* **Type**: `string`\[]
* **Optional**
Fields in package.json to check for entry points.
##### Default
Defaults based on platform:
* `node` platform: `['main', 'module']`
* `browser` platform: `['browser', 'module', 'main']`
* `neutral` platform: `[]`
#### mainFiles?
* **Type**: `string`\[]
* **Optional**
Filenames to try when resolving directories.
##### Default
```ts
['index']
```
#### modules?
* **Type**: `string`\[]
* **Optional**
Directories to search for modules.
##### Default
```ts
['node_modules']
```
#### symlinks?
* **Type**: `boolean`
* **Optional**
Whether to follow symlinks when resolving modules.
##### Default
```ts
true
```
#### ~~tsconfigFilename?~~
* **Type**: `string`
* **Optional**
##### Deprecated
Use the top-level [`tsconfig`](#tsconfig) option instead.
***
### shimMissingExports?
* **Type**: `boolean`
* **Optional**
When `true`, creates shim variables for missing exports instead of throwing an error.
#### Default
false
#### Examples
##### Enable shimming
```js
export default {
shimMissingExports: true,
};
```
##### Example scenario
**module-a.js:**
```js
export { nonExistent } from './module-b.js';
```
**module-b.js:**
```js
// nonExistent is not actually exported here
export const something = 'value';
```
With `shimMissingExports: false` (default), this would throw an error. With `shimMissingExports: true`, Rolldown will create a shim variable:
```js
// Bundled output (simplified)
const nonExistent = undefined;
export { nonExistent, something };
```
***
### transform?
* **Type**: [`TransformOptions`](Interface.TransformOptions.md)
* **Optional**
Configure how the code is transformed. This process happens after the `transform` hook.
#### Example
**Enable legacy decorators**
```js
export default defineConfig({
transform: {
decorator: {
legacy: true,
},
},
})
```
Note that if you have correct `tsconfig.json` file, Rolldown will automatically detect and enable legacy decorators support.
#### In-depth
Rolldown uses Oxc under the hood for transformation.
While Oxc does not support lowering the latest decorators proposal yet, Rolldown is able to bundle them.
***
### treeshake?
* **Type**: `boolean` | [`TreeshakingOptions`](TypeAlias.TreeshakingOptions.md)
* **Optional**
Controls tree-shaking (dead code elimination).
See the [In-depth Dead Code Elimination Guide](/in-depth/dead-code-elimination) for more details.
When `false`, tree-shaking will be disabled.
When `true`, it is equivalent to setting each options to the default value.
#### Default
```ts
true
```
***
### tsconfig?
* **Type**: `string` | `boolean`
* **Optional**
Configures TypeScript configuration file resolution and usage.
#### Options
##### Auto-discovery mode (`true`)
When set to `true`, Rolldown enables auto-discovery mode. For each module, both the resolver and transformer search **upward** from the module's directory, starting at the nearest `tsconfig.json`. If it has `references`, Rolldown checks each referenced project's `files`/`include`/`exclude` and uses the first one that matches the file. If no reference matches, it checks the `tsconfig.json`'s own `files`/`include`/`exclude`. If the file matches neither, Rolldown continues upward to the next `tsconfig.json` and repeats. If no `tsconfig.json` matches the file, no config is applied (no `paths`/`baseUrl`), the same as TypeScript.
Whether an `include` glob matches a file depends on its extension: by default only TypeScript files (`.ts`/`.tsx`/`.mts`/`.cts`) match, plus `.js`/`.jsx`/`.mjs`/`.cjs` when `allowJs` is enabled. A glob that names an explicit extension (for example `src/**/*.vue`) matches that extension verbatim, so a non-TS file can pick up the project's `paths`/`baseUrl`. (`files` lists exact paths and matches them regardless of extension or `allowJs`)
If the tsconfig has `references`, Rolldown resolves them the way TypeScript does: a referenced project that includes the file **takes precedence over the root**, and the first matching reference wins. Each referenced project matches with its own `compilerOptions` (such as `allowJs`). If no referenced project includes the file, Rolldown falls back to the root's own `files`/`include`/`exclude`. A solution-style root (only `references` with an explicit empty `files`/`include`, as Vite scaffolds) has no file patterns of its own, so once none of its references match either, it does **not** own the file, and discovery continues in the parent directories as described above.
```js
export default {
tsconfig: true,
};
```
##### Explicit path (`string`)
Specifies the path to a specific TypeScript configuration file. You may provide a relative path (resolved relative to `cwd`) or an absolute path.
If the tsconfig has `references`, this mode behaves like auto-discovery mode for reference resolution.
```js
export default {
tsconfig: './tsconfig.json',
};
```
```js
export default {
tsconfig: '/absolute/path/to/tsconfig.json',
};
```
:::tip
Rolldown respects `references` and `include`/`exclude` patterns in tsconfig, while esbuild does not. If you need esbuild-compatible behavior, specify a tsconfig without `references`. You can use [`extends`](https://www.typescriptlang.org/tsconfig/#extends) to share the options between the two.
:::
#### What's used from tsconfig
When a tsconfig is resolved, Rolldown uses different parts for different purposes:
##### Resolver
Uses the following for module path mapping:
* `compilerOptions.paths`: Path mapping for module resolution
* `compilerOptions.baseUrl`: Base directory for path resolution
##### Transformer
Uses select compiler options including:
* `jsx`: JSX transformation mode
* `experimentalDecorators`: Enable decorator support
* `emitDecoratorMetadata`: Emit decorator metadata
* `strictNullChecks` (falling back to `strict`): Controls whether `null`/`undefined` are elided from nullable-union `design:type` decorator metadata, and only applies when `emitDecoratorMetadata` is enabled. When neither is set it defaults to enabled, matching TypeScript 6.0+ (where `strict` is on by default)
* `verbatimModuleSyntax`: Module syntax preservation
* `useDefineForClassFields`: Class field semantics
* And other TypeScript-specific options
##### Example
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"]
}
}
}
```
With this configuration:
* JSX will use React's automatic runtime
* Path aliases like `@/utils` will resolve to `src/utils`
#### Priority
Top-level `transform` options always take precedence over tsconfig settings:
```js
export default {
tsconfig: './tsconfig.json', // Has jsx: 'react-jsx'
transform: {
jsx: {
mode: 'classic', // This takes precedence
},
},
};
```
:::tip
For TypeScript projects, it's recommended to use `tsconfig: true` for auto-discovery or specify an explicit path to ensure consistent compilation behavior and enable path mapping.
:::
#### Default
```ts
true
```
***
### watch?
* **Type**: `false` | [`WatcherOptions`](Interface.WatcherOptions.md)
* **Optional**
* **Experimental**
Watch mode related options.
These options only take effect when running with the [`--watch`](/apis/cli#w-watch) flag, or using [`watch()`](Function.watch.md) API.
Rolldown uses the following APIs to watch for changes by default:
* Linux, Android: `inotify`
* macOS: `FSEvents`
* Windows: `ReadDirectoryChangesW`
* BSD descendants (e.g. FreeBSD): `kqueue`
* Other: None (polling)
There are some limitations for each API. If you need to work around them, you can use [`watcher.usePolling`](/reference/Interface.WatcherFileWatcherOptions#usepolling) to force Rolldown to use polling instead of the native API.
::: warning Using on Windows Subsystem for Linux (WSL) 2
When running Rolldown on WSL2, file system watching does not work when a file is edited by Windows applications (non-WSL2 process). This is due to [a WSL2 limitation](https://github.com/microsoft/WSL/issues/4739). This also applies to running on Docker with a WSL2 backend.
To fix it, you could either:
* **Recommended**: Use WSL2 applications to edit your files.
* It is also recommended to move the project folder outside of a Windows filesystem. Accessing Windows filesystem from WSL2 is slow. Removing that overhead will improve performance.
* Set [`usePolling: true`](/reference/Interface.WatcherFileWatcherOptions#usepolling).
* Note that `usePolling` leads to higher CPU utilization.
:::
---
---
url: /reference/Interface.OutputOptions.md
---
# Interface: OutputOptions
## Properties
### ~~advancedChunks?~~
* **Type**: object with the properties below
* **Optional**
#### ~~groups?~~
* **Type**: [`CodeSplittingGroup`](TypeAlias.CodeSplittingGroup.md)\[]
* **Optional**
#### ~~includeDependenciesRecursively?~~
* **Type**: `boolean`
* **Optional**
#### ~~maxModuleSize?~~
* **Type**: `number`
* **Optional**
#### ~~maxSize?~~
* **Type**: `number`
* **Optional**
#### ~~minModuleSize?~~
* **Type**: `number`
* **Optional**
#### ~~minShareCount?~~
* **Type**: `number`
* **Optional**
#### ~~minSize?~~
* **Type**: `number`
* **Optional**
#### Deprecated
Please use [`output.codeSplitting`](#codesplitting) instead.
Allows you to do manual chunking.
:::warning
If `advancedChunks` and `codeSplitting` are both specified, `advancedChunks` option will be ignored.
:::
***
### assetFileNames?
* **Type**: `string` | ((`chunkInfo`) => `string`)
* **Optional**
The pattern to use for naming custom emitted assets to include in the build output, or a function that is called per asset with [`PreRenderedAsset`](Interface.PreRenderedAsset.md) to return such a pattern.
Patterns support the following placeholders:
* `[extname]`: The file extension of the asset including a leading dot, e.g. `.css`.
* `[ext]`: The file extension without a leading dot, e.g. css.
* `[hash]`: A hash based on the content of the asset. You can also set a specific hash length via e.g. `[hash:10]`. By default, it will create a base-64 hash. If you need a reduced character set, see [`output.hashCharacters`](#hashcharacters).
* `[name]`: The file name of the asset excluding any extension.
Forward slashes (`/`) can be used to place files in sub-directories.
See also [`output.chunkFileNames`](#chunkfilenames), [`output.entryFileNames`](#entryfilenames).
#### Default
```ts
'assets/[name]-[hash][extname]'
```
***
### banner?
* **Type**: `string` | ((`chunk`) => `string` | `Promise`<`string`>)
* **Optional**
A string to prepend to the bundle before [`renderChunk`](Interface.Plugin.md#renderchunk) hook.
See [`output.intro`](#intro), [`output.postBanner`](#postbanner) as well.
:::warning
When using `output.banner` with minification enabled, the banner content may be stripped out unless it is formatted as a legal comment. To ensure your banner persists through minification, do either:
* Use [`output.postBanner`](/reference/OutputOptions.postBanner) instead, which are added after minification, or
* Use one of these comment formats:
* Comments starting with `/*!` (e.g., `/*! My banner */`)
* Comments containing `@license` (e.g., `/* @license My banner */`)
* Comments containing `@preserve` (e.g., `/* @preserve My banner */`)
* Comments starting with `//!` (for single-line comments)
The latter way's behavior is controlled by the [`output.legalComments`](/reference/OutputOptions.legalComments) option, which defaults to `'inline'` and preserves these special comment formats.
:::
#### Examples
##### Adding shebang for CLI tools
```js
export default {
output: {
banner: (chunk) => {
// Add shebang only to the CLI entry point
if (chunk.name === 'cli') {
return '#!/usr/bin/env node';
}
return '';
},
},
};
```
##### Adding "use strict" directive
```js
export default {
output: {
format: 'cjs',
banner: '"use strict";',
},
};
```
***
### chunkFileNames?
* **Type**: `string` | ((`chunkInfo`) => `string`)
* **Optional**
The pattern to use for naming shared chunks created when code-splitting, or a function that is called per chunk with [`PreRenderedChunk`](Interface.PreRenderedChunk.md) to return such a pattern.
Patterns support the following placeholders:
* `[format]`: The rendering format defined in the output options. The value is any of [`InternalModuleFormat`](TypeAlias.InternalModuleFormat.md).
* `[hash]`: A hash based only on the content of the final generated chunk, including transformations in `renderChunk` and any referenced file hashes. You can also set a specific hash length via e.g. `[hash:10]`. By default, it will create a base-64 hash. If you need a reduced character set, see [`output.hashCharacters`](#hashcharacters).
* `[name]`: The name of the chunk. This can be explicitly set via the [`output.codeSplitting`](#codesplitting) option or when the chunk is created by a plugin via `this.emitFile`. Otherwise, it will be derived from the chunk contents.
Forward slashes (`/`) can be used to place files in sub-directories.
See also [`output.assetFileNames`](#assetfilenames), [`output.entryFileNames`](#entryfilenames).
#### Default
```ts
'[name]-[hash].js'
```
***
### cleanDir?
* **Type**: `boolean`
* **Optional**
Clean output directory ([`output.dir`](#dir)) before emitting output.
#### Default
false
#### Examples
##### Basic usage
```js
export default {
output: {
cleanDir: true,
},
};
```
##### Multiple outputs in one config
When multiple outputs share the same directory, only set `cleanDir: true` for the first output:
```js
export default {
output: [
{
dir: 'dist',
format: 'es',
cleanDir: true, // Clean on first output
},
{
dir: 'dist',
format: 'cjs',
// cleanDir defaults to false, so files from first output are preserved
},
],
};
```
##### Multiple configurations
When multiple configurations share the same directory, only set `cleanDir: true` for the first configuration:
```js
export default [
{
input: 'src/index.js',
output: {
dir: 'dist',
cleanDir: true, // Clean on first configuration
},
},
{
input: 'src/other.js',
output: {
dir: 'dist',
// cleanDir defaults to false, so files from first config are preserved
},
},
];
```
##### Different directories in multiple outputs
When multiple outputs use different directories, you can safely use `cleanDir: true` for each:
```js
export default {
output: [
{
dir: 'dist/es',
format: 'es',
cleanDir: true, // Safe - different directory
},
{
dir: 'dist/cjs',
format: 'cjs',
cleanDir: true, // Safe - different directory
},
],
};
```
#### In-depth
##### Execution timing
The timing of the directory cleanup is important for plugin compatibility:
* The cleanup occurs **before** the `generateBundle` hook is called
* Files created by plugins during `generateBundle` or `writeBundle` hooks are **not** deleted
* This ensures that plugin-generated files are preserved even when `cleanDir` is enabled
For advanced use cases involving multiple outputs with the same `output.dir`, consider using a separate cleanup script for more control over the cleanup process.
##### ⚠️ Multiple configurations behavior
When using multiple configurations or outputs, the `cleanDir` option will be executed **separately for each configuration/output** following the order they are defined.
**The two patterns:**
* **Multiple configurations**: `export default defineConfig([{ output: { cleanDir: true, ... } }, { output: {...} }])`
* **Multiple outputs in one config**: `defineConfig({ output: [{ cleanDir: true, ... }, { ... }] })`
**The problem:**
If multiple outputs share the same `output.dir` and have `cleanDir: true`, later outputs may clean files generated by earlier outputs. This happens because each output executes its cleanup independently.
**Best practice:**
To avoid this issue, only set `cleanDir: true` for the first output, or use different output directories. This ensures that all generated files are preserved.
***
### codeSplitting?
* **Type**: `boolean` | [`CodeSplittingOptions`](TypeAlias.CodeSplittingOptions.md)
* **Optional**
Controls how code splitting is performed.
* `true`: Default behavior, automatic code splitting. **(default)**
* `false`: Inline all dynamic imports into a single bundle (equivalent to deprecated `inlineDynamicImports: true`).
* `object`: Advanced manual code splitting configuration.
For deeper understanding, please refer to the in-depth [documentation](/in-depth/manual-code-splitting).
:::warning
Be aware that manual code splitting can change the behavior of the application if side effects are triggered before the corresponding modules are actually used. You can change the chunking configuration to keep order-sensitive modules together, or you can use the [`output.strictExecutionOrder`](/reference/OutputOptions.strictExecutionOrder) option to preserve source execution order. The option wraps modules so their bodies run in source order, at a bundle-size cost; `experimental.onDemandWrapping` replaces wrap-all with a conservative plan derived from predicted chunk execution hazards.
:::
#### Example
**Basic vendor chunk**
```js
export default defineConfig({
output: {
codeSplitting: {
minSize: 20000,
groups: [
{
name: 'vendor',
test: /node_modules/,
},
],
},
},
});
```
**Multiple chunk groups with priorities**
```js
export default defineConfig({
output: {
codeSplitting: {
groups: [
{
name: 'react-vendor',
test: /node_modules[\\/]react/,
priority: 20,
},
{
name: 'ui-vendor',
test: /node_modules[\\/]antd/,
priority: 15,
},
{
name: 'vendor',
test: /node_modules/,
priority: 10,
},
{
name: 'common',
minShareCount: 2,
minSize: 10000,
priority: 5,
},
],
},
},
});
```
**Size-based splitting**
```js
export default defineConfig({
output: {
codeSplitting: {
groups: [
{
name: 'large-libs',
test: /node_modules/,
minSize: 100000, // 100KB
maxSize: 250000, // 250KB
priority: 10,
},
],
},
},
});
```
#### Default
```ts
true
```
***
### comments?
* **Type**: `boolean` | [`CommentsOptions`](Interface.CommentsOptions.md)
* **Optional**
Control which comments are preserved in the output.
* `true`: Preserve legal, annotation, and JSDoc comments (default)
* `false`: Strip all comments
* Object: Granular control over comment categories
Note: Regular line and block comments without these markers
are always removed regardless of this option.
When both `legalComments` and `comments.legal` are set, `comments.legal` takes priority.
#### Default
```ts
true
```
***
### dir?
* **Type**: `string`
* **Optional**
The directory in which all generated chunks are placed.
The [`output.file`](#file) option can be used instead if only a single chunk is generated.
The output directory will be generated if it does not already exist, but it will not be cleared if it already contains some files. Any generated files will silently overwrite existing files with the same name. If you want the output directory to only contain files from the current run, you can use [`output.cleanDir`](/reference/OutputOptions.cleanDir) option.
#### Default
```ts
'dist'
```
***
### dynamicImportInCjs?
* **Type**: `boolean`
* **Optional**
Whether to keep external dynamic imports as `import(...)` expressions in CommonJS output.
If set to `false`, external dynamic imports will be rewritten to use `require(...)` calls.
This may be necessary to support environments that do not support dynamic `import()` in CommonJS modules like old Node.js versions.
#### Default
```ts
true
```
***
### entryFileNames?
* **Type**: `string` | ((`chunkInfo`) => `string`)
* **Optional**
The pattern to use for chunks created from entry points, or a function that is called per entry chunk with [`PreRenderedChunk`](Interface.PreRenderedChunk.md) to return such a pattern.
Patterns support the following placeholders:
* `[format]`: The rendering format defined in the output options. The value is any of [`InternalModuleFormat`](TypeAlias.InternalModuleFormat.md).
* `[hash]`: A hash based only on the content of the final generated chunk, including transformations in `renderChunk` and any referenced file hashes. You can also set a specific hash length via e.g. `[hash:10]`. By default, it will create a base-64 hash. If you need a reduced character set, see [`output.hashCharacters`](#hashcharacters).
* `[name]`: The file name (without extension) of the entry point, unless the object form of input was used to define a different name.
Forward slashes (`/`) can be used to place files in sub-directories. This pattern will also be used for every file when setting the [`output.preserveModules`](#preservemodules) option.
See also [`output.assetFileNames`](#assetfilenames), [`output.chunkFileNames`](#chunkfilenames).
#### Default
```ts
'[name].js'
```
***
### esModule?
* **Type**: `boolean` | `"if-default-prop"`
* **Optional**
Whether to add a `__esModule: true` property when generating exports for non-ES [formats](#format).
This property signifies that the exported value is the namespace of an ES module and that the default export of this module corresponds to the `.default` property of the exported object.
* `true`: Always add the property when using [named exports mode](#exports), which is similar to what other tools do.
* `"if-default-prop"`: Only add the property when using [named exports mode](#exports) and there also is a default export. The subtle difference is that if there is no default export, consumers of the CommonJS version of your library will get all named exports as default export instead of an error or `undefined`.
* `false`: Never add the property even if the default export would become a property `.default`.
#### Default
'if-default-prop'
#### Interaction with Consuming Tools
Different tools handle the `__esModule` marker differently when importing your bundle:
* **Rolldown**: Use heuristics based on Node.js's behavior. See the [Bundling CJS](/in-depth/bundling-cjs#ambiguous-default-import-from-cjs-modules) guide for more details.
* **esbuild**: Use heuristics based on Node.js's behavior.
* **Node.js**: Does not respect `__esModule`. The default export is the `module.exports` value.
* **Babel**: Respects `__esModule`.
***
### exports?
* **Type**: `"auto"` | `"named"` | `"default"` | `"none"`
* **Optional**
Which exports mode to use.
When `'auto'` is used, Rolldown will automatically determine the export mode based on the exports of the `input` modules. If the `input` modules have a single default export, then `'default'` mode is used. If the `input` modules have named exports, then `'named'` mode is used. If there are no exports, then `'none'` mode is used.
`'default'` can only be used when the `input` modules have a single default export. `'none'` can only be used when the `input` modules have no exports. Otherwise, Rolldown will throw an error.
The difference between `'default'` and `'named'` affects how other people can consume your bundle. If you use `'default'`, a CommonJS user could do this, for example:
```js
// your-lib package entry
export default 'Hello world';
// a CommonJS consumer
/* require( "your-lib" ) returns "Hello world" */
const hello = require('your-lib');
```
With `'named'`, a user would do this instead:
```js
// your-lib package entry
export const hello = 'Hello world';
// a CommonJS consumer
/* require( "your-lib" ) returns {hello: "Hello world"} */
const hello = require('your-lib').hello;
/* or using destructuring */
const { hello } = require('your-lib');
```
The wrinkle is that if you use `'named'` exports but also have a default export, a user would have to do something like this to use the default export:
```js
// your-lib package entry
export default 'foo';
export const bar = 'bar';
// a CommonJS consumer
/* require( "your-lib" ) returns {default: "foo", bar: "bar"} */
const foo = require('your-lib').default;
const bar = require('your-lib').bar;
/* or using destructuring */
const { default: foo, bar } = require('your-lib');
```
::: tip
There are many tools that are capable of resolving a CommonJS `require(...)` call with an ES module. If you are generating CommonJS output that is meant to be interchangeable with ESM output for those tools, you should always use `'named'` export mode. The reason is that most of those tools will by default return the namespace of an ES module on `require` where the default export is the `.default` property.
In other words for those tools, you cannot create a package interface where `const lib = require("your-lib")` yields the same as `import lib from "your-lib"`. With `'named'` export mode however, `const {lib} = require("your-lib")` will be equivalent to `import {lib} from "your-lib"`.
:::
#### Default
```ts
'auto'
```
***
### extend?
* **Type**: `boolean`
* **Optional**
Whether to extend the global variable defined by the [`name`](#name) option in `umd` or `iife` [formats](#format).
When `true`, the global variable will be defined as `global.name = global.name || {}`.
When `false`, the global defined by name will be overwritten like `global.name = {}`.
#### Default
```ts
false
```
***
### externalLiveBindings?
* **Type**: `boolean`
* **Optional**
Whether to generate code to support live bindings for [external](Interface.InputOptions.md#external) imports.
With the default value of `true`, Rolldown will generate code to support live bindings for external imports.
When set to `false`, Rolldown will assume that exports from external modules do not change. This will allow Rolldown to generate smaller code. Note that this can cause issues when there are circular dependencies involving an external dependency.
#### Default
true
#### Example
```js
// input
export { x } from 'external';
```
```js
// CJS output with externalLiveBindings: true
var external = require('external');
Object.defineProperty(exports, 'x', {
enumerable: true,
get: function () {
return external.x;
},
});
```
```js
// CJS output with externalLiveBindings: false
var external = require('external');
exports.x = external.x;
```
***
### file?
* **Type**: `string`
* **Optional**
The file path for the single generated chunk.
The [`output.dir`](#dir) option should be used instead if multiple chunks are generated.
***
### footer?
* **Type**: `string` | ((`chunk`) => `string` | `Promise`<`string`>)
* **Optional**
A string to append to the bundle before [`renderChunk`](Interface.Plugin.md#renderchunk) hook.
See [`output.outro`](#outro), [`output.postFooter`](#postfooter) as well.
:::warning
When using `output.footer` with minification enabled, the footer content may be stripped out unless it is formatted as a legal comment. To ensure your footer persists through minification, do either:
* Use [`output.postFooter`](/reference/OutputOptions.postFooter) instead, which is added after minification, or
* Use one of these comment formats:
* Comments starting with `/*!` (e.g., `/*! My footer */`)
* Comments containing `@license` (e.g., `/* @license My footer */`)
* Comments containing `@preserve` (e.g., `/* @preserve My footer */`)
* Comments starting with `//!` (for single-line comments)
The latter way's behavior is controlled by the [`output.legalComments`](/reference/OutputOptions.legalComments) option, which defaults to `'inline'` and preserves these special comment formats.
:::
#### Examples
##### Expose the default export as `module.exports` for CJS output with all named exports as properties
```js
export default {
output: {
format: 'cjs',
exports: 'named',
footer: (chunk) => {
if (chunk.isEntry) {
return `
module.exports = exports.default;
module.exports.default = module.exports;
module.exports.foo = module.exports.default.foo;`;
}
return '';
},
},
};
```
***
### format?
* **Type**: `"es"` | `"cjs"` | `"iife"` | `"umd"` | `"module"` | `"esm"` | `"commonjs"`
* **Optional**
Expected format of generated code.
* `'es'`, `'esm'` and `'module'` are the same format, all stand for ES module.
* `'cjs'` and `'commonjs'` are the same format, all stand for CommonJS module.
* `'iife'` stands for [Immediately Invoked Function Expression](https://developer.mozilla.org/en-US/docs/Glossary/IIFE).
* `'umd'` stands for [Universal Module Definition](https://github.com/umdjs/umd).
#### Default
'es'
#### In-depth
##### ES Module
[ES modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) (ESM) are the official JavaScript module standard. When `output.format: 'es'` is used, the bundle will use `export` syntax like this:
```js
function exportedFunction() {
/* ... */
}
let exportedValue = '/* ... */';
export { exportedFunction, exportedValue };
```
To load ES modules, use `