Rollup is a module bundler for JavaScript which compiles small pieces of code into something larger and more complex, such as a library or application. It uses the new standardized format for code modules included in the ES6 revision of JavaScript, instead of previous idiosyncratic solutions such as CommonJS and AMD. ES modules let you freely and seamlessly combine the most useful individual functions from your favorite libraries. This will eventually be possible natively everywhere, but Rollup lets you do it today.
npm install --global rollup
This will make Rollup available as a global command line tool. You can also install it locally, see Installing Rollup locally.
Rollup can be used either through a command line interface with an optional configuration file, or else through its JavaScript API. Run rollup --help
to see the available options and parameters.
See rollup-starter-lib and rollup-starter-app to see example library and application projects using Rollup
These commands assume the entry point to your application is named main.js
, and that you'd like all imports compiled into a single file named bundle.js
.
For browsers:
# compile to a <script> containing a self-executing function ('iife')
rollup main.js --file bundle.js --format iife
For Node.js:
# compile to a CommonJS module ('cjs')
rollup main.js --file bundle.js --format cjs
For both browsers and Node.js:
# UMD format requires a bundle name
rollup main.js --file bundle.js --format umd --name "myBundle"
Developing software is usually easier if you break your project into smaller separate pieces, since that often removes unexpected interactions and dramatically reduces the complexity of the problems you'll need to solve, and simply writing smaller projects in the first place isn't necessarily the answer. Unfortunately, JavaScript has not historically included this capability as a core feature in the language.
This finally changed with the ES6 revision of JavaScript, which includes a syntax for importing and exporting functions and data so they can be shared between separate scripts. The specification is now fixed, but it is only implemented in modern browsers and not finalised in Node.js. Rollup allows you to write your code using the new module system, and will then compile it back down to existing supported formats such as CommonJS modules, AMD modules, and IIFE-style scripts. This means that you get to write future-proof code, and you also get the tremendous benefits of…
In addition to enabling the use of ES modules, Rollup also statically analyzes the code you are importing, and will exclude anything that isn't actually used. This allows you to build on top of existing tools and modules without adding extra dependencies or bloating the size of your project.
For example, with CommonJS, the entire tool or library must be imported.
// import the entire utils object with CommonJS
const utils = require('./utils');
const query = 'Rollup';
// use the ajax method of the utils object
utils.ajax(`https://api.example.com?search=${query}`).then(handleResponse);
With ES modules, instead of importing the whole utils
object, we can just import the one ajax
function we need:
// import the ajax function with an ES6 import statement
import { ajax } from './utils';
const query = 'Rollup';
// call the ajax function
ajax(`https://api.example.com?search=${query}`).then(handleResponse);
Because Rollup includes the bare minimum, it results in lighter, faster, and less complicated libraries and applications. Since this approach can utilise explicit import
and export
statements, it is more effective than simply running an automated minifier to detect unused variables in the compiled output code.
Rollup can import existing CommonJS modules through a plugin.
To make sure your ES modules are immediately usable by tools that work with CommonJS such as Node.js and webpack, you can use Rollup to compile to UMD or CommonJS format, and then point to that compiled version with the main
property in your package.json
file. If your package.json
file also has a module
field, ES-module-aware tools like Rollup and webpack 2+ will import the ES module version directly.
Rollup should typically be used from the command line. You can provide an optional Rollup configuration file to simplify command line usage and enable advanced Rollup functionality.
Rollup 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:
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
}
};
Typically, it is called rollup.config.js
and sits in the root directory of your project. Behind the scenes, Rollup will usually transpile and bundle this file and its relative dependencies to CommonJS before requiring it. This has the advantage that you can share code with an ES module code base while having full interoperability with the Node ecosystem.
If you want to write your config as a CommonJS module using require
and module.exports
, you should change the file extension to .cjs
, which will prevent Rollup from trying to transpile the file. Furthermore if you are on Node 13+, changing the file extension to .mjs
will also prevent Rollup from transpiling it but import the file as an ES module instead. See using untranspiled config files for more details and why you might want to do this.
You can also use other languages for your configuration files like TypeScript. To do that, install a corresponding Rollup plugin like @rollup/plugin-typescript
and use the --configPlugin
option:
rollup --config rollup.config.ts --configPlugin typescript
Also have a look at Config Intellisense for more ways to use TypeScript typings in your config files.
Config files support the options listed below. Consult the big list of options for details on each option:
// rollup.config.js
// can be an array (for multiple inputs)
export default {
// core input options
external,
input, // conditionally required
plugins,
// advanced input options
cache,
onwarn,
preserveEntrySignatures,
strictDeprecations,
// danger zone
acorn,
acornInjectPlugins,
context,
moduleContext,
preserveSymlinks,
shimMissingExports,
treeshake,
// experimental
experimentalCacheExpiry,
perf,
// required (can be an array, for multiple outputs)
output: {
// core output options
dir,
file,
format, // required
globals,
name,
plugins,
// advanced output options
assetFileNames,
banner,
chunkFileNames,
compact,
entryFileNames,
extend,
footer,
hoistTransitiveImports,
inlineDynamicImports,
interop,
intro,
manualChunks,
minifyInternalExports,
outro,
paths,
preserveModules,
preserveModulesRoot,
sourcemap,
sourcemapExcludeSources,
sourcemapFile,
sourcemapPathTransform,
validate,
// danger zone
amd,
esModule,
exports,
externalLiveBindings,
freeze,
indent,
namespaceToStringTag,
noConflict,
preferConst,
sanitizeFileName,
strict,
systemNullSetters
},
watch: {
buildDelay,
chokidar,
clearScreen,
skipWrite,
exclude,
include
}
};
You can export an array from your config file to build bundles from several unrelated inputs at once, even in watch mode. To build different bundles with the same input, you supply an array of output options for each input:
// rollup.config.js (building more than one bundle)
export default [
{
input: 'main-a.js',
output: {
file: 'dist/bundle-a.js',
format: 'cjs'
}
},
{
input: 'main-b.js',
output: [
{
file: 'dist/bundle-b1.js',
format: 'cjs'
},
{
file: 'dist/bundle-b2.js',
format: 'es'
}
]
}
];
If you want to create your config asynchronously, Rollup can also handle a Promise
which resolves to an object or an array.
// rollup.config.js
import fetch from 'node-fetch';
export default fetch('/some-remote-service-or-file-which-returns-actual-config');
Similarly, you can do this as well:
// rollup.config.js (Promise resolving an array)
export default Promise.all([fetch('get-config-1'), fetch('get-config-2')]);
To use Rollup with a configuration file, pass the --config
or -c
flags:
# pass a custom config file location to Rollup
rollup --config my.config.js
# if you do not pass a file name, Rollup will try to load
# configuration files in the following order:
# rollup.config.mjs -> rollup.config.cjs -> rollup.config.js
rollup --config
You can also export a function that returns any of the above configuration formats. This function will be passed the current command line arguments so that you can dynamically adapt your configuration to respect e.g. --silent
. You can even define your own command line options if you prefix them with config
:
// rollup.config.js
import defaultConfig from './rollup.default.config.js';
import debugConfig from './rollup.debug.config.js';
export default commandLineArgs => {
if (commandLineArgs.configDebug === true) {
return debugConfig;
}
return defaultConfig;
};
If you now run rollup --config --configDebug
, the debug configuration will be used.
By default, command line arguments will always override the respective values exported from a config file. If you want to change this behaviour, you can make Rollup ignore command line arguments by deleting them from the commandLineArgs
object:
// rollup.config.js
export default commandLineArgs => {
const inputBase = commandLineArgs.input || 'main.js';
// this will make Rollup ignore the CLI argument
delete commandLineArgs.input;
return {
input: 'src/entries/' + inputBase,
output: {...}
}
}
Since Rollup ships with TypeScript typings, you can leverage your IDE's Intellisense with JSDoc type hints:
// rollup.config.js
/**
* @type {import('rollup').RollupOptions}
*/
const config = {
// ...
};
export default config;
Alternatively you can use the defineConfig
helper, which should provide Intellisense without the need for JSDoc annotations:
// rollup.config.js
import { defineConfig } from 'rollup';
export default defineConfig({
// ...
});
Besides RollupOptions
and the defineConfig
helper that encapsulates this type, the following types can prove useful as well:
OutputOptions
: The output
part of a config filePlugin
: A plugin object that provides a name
and some hooks. All hooks are fully typed to aid in plugin development.PluginImpl
: A function that maps an options object to a plugin object. Most public Rollup plugins follow this pattern.You can also directly write your config in TypeScript via the --configPlugin
option.
While config files provide an easy way to configure Rollup, they also limit how Rollup can be invoked and configured. Especially if you are bundling Rollup into another build tool or want to integrate it into an advanced build process, it may be better to directly invoke Rollup programmatically from your scripts.
If you want to switch from config files to using the JavaScript API at some point, there are some important differences to be aware of:
rollup.rollup
must be an object and cannot be wrapped in a Promise or a function.rollup.rollup
once for each set of inputOptions
.output
option will be ignored. Instead, you should run bundle.generate(outputOptions)
or bundle.write(outputOptions)
once for each set of outputOptions
.For interoperability, Rollup also supports loading configuration files from packages installed into node_modules
:
# this will first try to load the package "rollup-config-my-special-config";
# if that fails, it will then try to load "my-special-config"
rollup --config node:my-special-config
By default, Rollup will expect config files to be ES modules and bundle and transpile them and their relative imports to CommonJS before requiring them. This is a fast process and has the advantage that it is easy to share code between your configuration and an ES module code base. If you want to write your configuration as CommonJS instead, you can skip this process by using the .cjs
extension:
// rollup.config.cjs
module.exports = {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
}
};
It may be pertinent if you want to use the config file not only from the command line, but also from your custom scripts programmatically.
On the other hand if you are using at least Node 13 and have "type": "module"
in your package.json
file, Rollup's transpilation will prevent your configuration file from importing packages that are themselves ES modules. In that case, changing your file extension to .mjs
will instruct Rollup to import your configuration directly as an ES module. However, note that this is specific to Node 13+; on older Node versions, .mjs
is treated just like .js
.
There are some potential gotchas when using .mjs
on Node 13+:
You will only get a default export from CommonJS plugins
You may not be able to import JSON files such as your package.json file
. There are two ways to go around this:
run Rollup CLI via
node --experimental-json-modules ./node_modules/.bin/rollup --config
create a CommonJS wrapper that requires the JSON file:
// load-package.cjs
module.exports = require('./package.json');
// rollup.config.mjs
import pkg from './load-package.cjs';
...
Many options have command line equivalents. In those cases, any arguments passed here will override the config file, if you're using one. This is a list of all supported options:
-c, --config <filename> Use this config file (if argument is used but value
is unspecified, defaults to rollup.config.js)
-d, --dir <dirname> Directory for chunks (if absent, prints to stdout)
-e, --external <ids> Comma-separate list of module IDs to exclude
-f, --format <format> Type of output (amd, cjs, es, iife, umd, system)
-g, --globals <pairs> Comma-separate list of `moduleID:Global` pairs
-h, --help Show this help message
-i, --input <filename> Input (alternative to <entry file>)
-m, --sourcemap Generate sourcemap (`-m inline` for inline map)
-n, --name <name> Name for UMD export
-o, --file <output> Single output file (if absent, prints to stdout)
-p, --plugin <plugin> Use the plugin specified (may be repeated)
-v, --version Show version number
-w, --watch Watch files in bundle and rebuild on changes
--amd.id <id> ID for AMD module (default is anonymous)
--amd.autoId Generate the AMD ID based off the chunk name
--amd.basePath <prefix> Path to prepend to auto generated AMD ID
--amd.define <name> Function to use in place of `define`
--assetFileNames <pattern> Name pattern for emitted assets
--banner <text> Code to insert at top of bundle (outside wrapper)
--chunkFileNames <pattern> Name pattern for emitted secondary chunks
--compact Minify wrapper code
--context <variable> Specify top-level `this` value
--entryFileNames <pattern> Name pattern for emitted entry chunks
--environment <values> Settings passed to config file (see example)
--no-esModule Do not add __esModule property
--exports <mode> Specify export mode (auto, default, named, none)
--extend Extend global variable defined by --name
--no-externalLiveBindings Do not generate code to support live bindings
--failAfterWarnings Exit with an error if the build produced warnings
--footer <text> Code to insert at end of bundle (outside wrapper)
--no-freeze Do not freeze namespace objects
--no-hoistTransitiveImports Do not hoist transitive imports into entry chunks
--no-indent Don't indent result
--no-interop Do not include interop block
--inlineDynamicImports Create single bundle when using dynamic imports
--intro <text> Code to insert at top of bundle (inside wrapper)
--minifyInternalExports Force or disable minification of internal exports
--namespaceToStringTag Create proper `.toString` methods for namespaces
--noConflict Generate a noConflict method for UMD globals
--outro <text> Code to insert at end of bundle (inside wrapper)
--preferConst Use `const` instead of `var` for exports
--no-preserveEntrySignatures Avoid facade chunks for entry points
--preserveModules Preserve module structure
--preserveModulesRoot Put preserved modules under this path at root level
--preserveSymlinks Do not follow symlinks when resolving files
--no-sanitizeFileName Do not replace invalid characters in file names
--shimMissingExports Create shim variables for missing exports
--silent Don't print warnings
--sourcemapExcludeSources Do not include source code in source maps
--sourcemapFile <file> Specify bundle position for source maps
--stdin=ext Specify file extension used for stdin input
--no-stdin Do not read "-" from stdin
--no-strict Don't emit `"use strict";` in the generated modules
--strictDeprecations Throw errors for deprecated features
--systemNullSetters Replace empty SystemJS setters with `null`
--no-treeshake Disable tree-shaking optimisations
--no-treeshake.annotations Ignore pure call annotations
--no-treeshake.moduleSideEffects Assume modules have no side-effects
--no-treeshake.propertyReadSideEffects Ignore property access side-effects
--no-treeshake.tryCatchDeoptimization Do not turn off try-catch-tree-shaking
--no-treeshake.unknownGlobalSideEffects Assume unknown globals do not throw
--waitForBundleInput Wait for bundle input files
--watch.buildDelay <number> Throttle watch rebuilds
--no-watch.clearScreen Do not clear the screen when rebuilding
--watch.skipWrite Do not write files to disk when watching
--watch.exclude <files> Exclude files from being watched
--watch.include <files> Limit watching to specified files
--validate Validate output
The flags listed below are only available via the command line interface. All other flags correspond to and override their config file equivalents, see the big list of options for details.
-h
/--help
Print the help document.
-p <plugin>
, --plugin <plugin>
Use the specified plugin. There are several ways to specify plugins here:
Via a relative path:
rollup -i input.js -f es -p ./my-plugin.js
The file should export a function returning a plugin object.
Via the name of a plugin that is installed in a local or global node_modules
folder:
rollup -i input.js -f es -p @rollup/plugin-node-resolve
If the plugin name does not start with rollup-plugin-
or @rollup/plugin-
, Rollup will automatically try adding these prefixes:
rollup -i input.js -f es -p node-resolve
Via an inline implementation:
rollup -i input.js -f es -p '{transform: (c, i) => `/* ${JSON.stringify(i)} */\n${c}`}'
If you want to load more than one plugin, you can repeat the option or supply a comma-separated list of names:
rollup -i input.js -f es -p node-resolve -p commonjs,json
By default, plugin functions will be called with no argument to create the plugin. You can however pass a custom argument as well:
rollup -i input.js -f es -p 'terser={output: {beautify: true, indent_level: 2}}'
--configPlugin <plugin>
Allows specifying Rollup plugins to transpile or otherwise control the parsing of your configuration file. The main benefit is that it allows you to use non-JavaScript configuration files. For instance the following will allow you to write your configuration in TypeScript, provided you have @rollup/plugin-typescript
installed:
rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript
It supports the same syntax as the --plugin
option i.e., you can specify the option multiple times, you can omit the @rollup/plugin-
prefix and just write typescript
and you can specify plugin options via ={...}
.
-v
/--version
Print the installed version number.
-w
/--watch
Rebuild the bundle when its source files change on disk.
Note: While in watch mode, the ROLLUP_WATCH
environment variable will be set to "true"
by Rollup's command line interface and can be checked by other processes. Plugins should instead check this.meta.watchMode
, which is independent of the command line interface.
--silent
Don't print warnings to the console. If your configuration file contains an onwarn
handler, this handler will still be called. To manually prevent that, you can access the command line options in your configuration file as described at the end of Configuration Files.
--failAfterWarnings
Exit the build with an error if any warnings occurred, once the build is complete.
--environment <values>
Pass additional settings to the config file via process.ENV
.
rollup -c --environment INCLUDE_DEPS,BUILD:production
will set process.env.INCLUDE_DEPS === 'true'
and process.env.BUILD === 'production'
. You can use this option several times. In that case, subsequently set variables will overwrite previous definitions. This enables you for instance to overwrite environment variables in package.json
scripts:
// in package.json
{
"scripts": {
"build": "rollup -c --environment INCLUDE_DEPS,BUILD:production"
}
}
If you call this script via:
npm run build -- --environment BUILD:development
then the config file will receive process.env.INCLUDE_DEPS === 'true'
and process.env.BUILD === 'development'
.
--waitForBundleInput
This will not throw an error if one of the entry point files is not available. Instead, it will wait until all files are present before starting the build. This is useful, especially in watch mode, when Rollup is consuming the output of another process.
--stdin=ext
Specify a virtual file extension when reading content from stdin. By default, Rollup will use the virtual file name -
without an extension for content read from stdin. Some plugins, however, rely on file extensions to determine if they should process a file. See also Reading a file from stdin.
--no-stdin
Do not read files from stdin
. Setting this flag will prevent piping content to Rollup and make sure Rollup interprets -
and -.[ext]
as a regular file names instead of interpreting these as the name of stdin
. See also Reading a file from stdin.
When using the command line interface, Rollup can also read content from stdin:
echo "export const foo = 42;" | rollup --format cjs --file out.js
When this file contains imports, Rollup will try to resolve them relative to the current working directory. When using a config file, Rollup will only use stdin
as an entry point if the file name of the entry point is -
. To read a non-entry-point file from stdin, just call it -
, which is the file name that is used internally to reference stdin
. I.e.
import foo from '-';
in any file will prompt Rollup to try to read the imported file from stdin
and assign the default export to foo
. You can pass the --no-stdin
CLI flag to Rollup to treat -
as a regular file name instead.
As some plugins rely on file extensions to process files, you can specify a file extension for stdin via --stdin=ext
where ext
is the desired extension. In that case, the virtual file name will be -.ext
:
echo '{"foo": 42, "bar": "ok"}' | rollup --stdin=json -p json
The JavaScript API will always treat -
and -.ext
as regular file names.
Rollup provides a JavaScript API which is usable from Node.js. You will rarely need to use this, and should probably be using the command line API unless you are extending Rollup itself or using it for something esoteric, such as generating bundles programmatically.
The rollup.rollup
function receives an input options object as parameter and returns a Promise that resolves to a bundle
object with various properties and methods as shown below. During this step, Rollup will build the module graph and perform tree-shaking, but will not generate any output.
On a bundle
object, you can call bundle.generate
multiple times with different output options objects to generate different bundles in-memory. If you directly want to write them to disk, use bundle.write
instead.
Once you're finished with the bundle
object, you should call bundle.close()
, which will let plugins clean up their external processes or services via the closeBundle
hook.
const rollup = require('rollup');
// see below for details on the options
const inputOptions = {...};
const outputOptions = {...};
async function build() {
// create a bundle
const bundle = await rollup.rollup(inputOptions);
console.log(bundle.watchFiles); // an array of file names this bundle depends on
// generate output specific code in-memory
// you can call this function multiple times on the same bundle object
const { output } = await bundle.generate(outputOptions);
for (const chunkOrAsset of output) {
if (chunkOrAsset.type === 'asset') {
// For assets, this contains
// {
// fileName: string, // the asset file name
// source: string | Uint8Array // the asset source
// type: 'asset' // signifies that this is an asset
// }
console.log('Asset', chunkOrAsset);
} else {
// For chunks, this contains
// {
// code: string, // the generated JS code
// dynamicImports: string[], // external modules imported dynamically by the chunk
// exports: string[], // exported variable names
// facadeModuleId: string | null, // the id of a module that this chunk corresponds to
// fileName: string, // the chunk file name
// implicitlyLoadedBefore: string[]; // entries that should only be loaded after this chunk
// imports: string[], // external modules imported statically by the chunk
// importedBindings: {[imported: string]: string[]} // imported bindings per dependency
// isDynamicEntry: boolean, // is this chunk a dynamic entry point
// isEntry: boolean, // is this chunk a static entry point
// isImplicitEntry: boolean, // should this chunk only be loaded after other chunks
// map: string | null, // sourcemaps if present
// modules: { // information about the modules in this chunk
// [id: string]: {
// renderedExports: string[]; // exported variable names that were included
// removedExports: string[]; // exported variable names that were removed
// renderedLength: number; // the length of the remaining code in this module
// originalLength: number; // the original length of the code in this module
// code: string | null; // remaining code in this module
// };
// },
// name: string // the name of this chunk as used in naming patterns
// referencedFiles: string[] // files referenced via import.meta.ROLLUP_FILE_URL_<id>
// type: 'chunk', // signifies that this is a chunk
// }
console.log('Chunk', chunkOrAsset.modules);
}
}
// or write the bundle to disk
await bundle.write(outputOptions);
// closes the bundle
await bundle.close();
}
build();
The inputOptions
object can contain the following properties (see the big list of options for full details on these):
const inputOptions = {
// core input options
external,
input, // conditionally required
plugins,
// advanced input options
cache,
onwarn,
preserveEntrySignatures,
strictDeprecations,
// danger zone
acorn,
acornInjectPlugins,
context,
moduleContext,
preserveSymlinks,
shimMissingExports,
treeshake,
// experimental
experimentalCacheExpiry,
perf
};
The outputOptions
object can contain the following properties (see the big list of options for full details on these):
const outputOptions = {
// core output options
dir,
file,
format, // required
globals,
name,
plugins,
// advanced output options
assetFileNames,
banner,
chunkFileNames,
compact,
entryFileNames,
extend,
externalLiveBindings,
footer,
hoistTransitiveImports,
inlineDynamicImports,
interop,
intro,
manualChunks,
minifyInternalExports,
outro,
paths,
preserveModules,
preserveModulesRoot,
sourcemap,
sourcemapExcludeSources,
sourcemapFile,
sourcemapPathTransform,
validate,
// danger zone
amd,
esModule,
exports,
freeze,
indent,
namespaceToStringTag,
noConflict,
preferConst,
sanitizeFileName,
strict,
systemNullSetters
};
Rollup also provides a rollup.watch
function that rebuilds your bundle when it detects that the individual modules have changed on disk. It is used internally when you run Rollup from the command line with the --watch
flag. Note that when using watch mode via the JavaScript API, it is your responsibility to call event.result.close()
in response to the BUNDLE_END
event to allow plugins to clean up resources in the closeBundle
hook, see below.
const rollup = require('rollup');
const watchOptions = {...};
const watcher = rollup.watch(watchOptions);
watcher.on('event', event => {
// event.code can be one of:
// START — the watcher is (re)starting
// BUNDLE_START — building an individual bundle
// * event.input will be the input options object if present
// * event.output contains an array of the "file" or
// "dir" option values of the generated outputs
// BUNDLE_END — finished building a bundle
// * event.input will be the input options object if present
// * event.output contains an array of the "file" or
// "dir" option values of the generated outputs
// * event.duration is the build duration in milliseconds
// * event.result contains the bundle object that can be
// used to generate additional outputs by calling
// bundle.generate or bundle.write. This is especially
// important when the watch.skipWrite option is used.
// You should call "event.result.close()" once you are done
// generating outputs, or if you do not generate outputs.
// This will allow plugins to clean up resources via the
// "closeBundle" hook.
// END — finished building all bundles
// ERROR — encountered an error while bundling
// * event.error contains the error that was thrown
// * event.result is null for build errors and contains the
// bundle object for output generation errors. As with
// "BUNDLE_END", you should call "event.result.close()" if
// present once you are done.
});
// This will make sure that bundles are properly closed after each run
watcher.on('event', ({ result }) => {
if (result) {
result.close();
}
});
// stop watching
watcher.close();
The watchOptions
argument is a config (or an array of configs) that you would export from a config file.
const watchOptions = {
...inputOptions,
output: [outputOptions],
watch: {
buildDelay,
chokidar,
clearScreen,
skipWrite,
exclude,
include
}
};
See above for details on inputOptions
and outputOptions
, or consult the big list of options for info on chokidar
, include
and exclude
.
In order to aid in generating such a config, rollup exposes the helper it uses to load config files in its command line interface via a separate entry-point. This helper receives a resolved fileName
and optionally an object containing command line parameters:
const loadConfigFile = require('rollup/dist/loadConfigFile');
const path = require('path');
const rollup = require('rollup');
// load the config file next to the current script;
// the provided config object has the same effect as passing "--format es"
// on the command line and will override the format of all outputs
loadConfigFile(path.resolve(__dirname, 'rollup.config.js'), { format: 'es' }).then(
async ({ options, warnings }) => {
// "warnings" wraps the default `onwarn` handler passed by the CLI.
// This prints all warnings up to this point:
console.log(`We currently have ${warnings.count} warnings`);
// This prints all deferred warnings
warnings.flush();
// options is an array of "inputOptions" objects with an additional "output"
// property that contains an array of "outputOptions".
// The following will generate all outputs for all inputs, and write them to disk the same
// way the CLI does it:
for (const optionsObj of options) {
const bundle = await rollup.rollup(optionsObj);
await Promise.all(optionsObj.output.map(bundle.write));
}
// You can also pass this directly to "rollup.watch"
rollup.watch(options);
}
);
The following is intended as a lightweight reference for the module behaviors defined in the ES2015 specification, since a proper understanding of the import and export statements are essential to the successful use of Rollup.
Imported values cannot be reassigned, though imported objects and arrays can be mutated (and the exporting module, and any other importers, will be affected by the mutation). In that way, they behave similarly to const
declarations.
Import a specific item from a source module, with its original name.
import { something } from './module.js';
Import a specific item from a source module, with a custom name assigned upon import.
import { something as somethingElse } from './module.js';
Import everything from the source module as an object which exposes all the source module's named exports as properties and methods.
import * as module from './module.js';
The something
example from above would then be attached to the imported object as a property, e.g. module.something
. If present, the default export can be accessed via module.default
.
Import the default export of the source module.
import something from './module.js';
Load the module code, but don't make any new objects available.
import './module.js';
This is useful for polyfills, or when the primary purpose of the imported code is to muck about with prototypes.
Import modules using the dynamic import API.
import('./modules.js').then(({ default: DefaultExport, NamedExport }) => {
// do something with modules.
});
This is useful for code-splitting applications and using modules on-the-fly.
Export a value that has been previously declared:
const something = true;
export { something };
Rename on export:
export { something as somethingElse };
Export a value immediately upon declaration:
// this works with `var`, `let`, `const`, `class`, and `function`
export const something = true;
Export a single value as the source module's default export:
export default something;
This practice is only recommended if your source module only has one export.
It is bad practice to mix default and named exports in the same module, though it is allowed by the specification.
ES modules export live bindings, not values, so values can be changed after they are initially imported as per this demo:
// incrementer.js
export let count = 0;
export function increment() {
count += 1;
}
// main.js
import { count, increment } from './incrementer.js';
console.log(count); // 0
increment();
console.log(count); // 1
count += 1; // Error — only incrementer.js can change this
Before we begin, you'll need to have Node.js installed so that you can use NPM. You'll also need to know how to access the command line on your machine.
The easiest way to use Rollup is via the Command Line Interface (or CLI). For now, we'll install it globally (later on we'll learn how to install it locally to your project so that your build process is portable, but don't worry about that yet). Type this into the command line:
npm install rollup --global
# or `npm i rollup -g` for short
You can now run the rollup
command. Try it!
rollup
Because no arguments were passed, Rollup prints usage instructions. This is the same as running rollup --help
, or rollup -h
.
Let's create a simple project:
mkdir -p my-rollup-project/src
cd my-rollup-project
First, we need an entry point. Paste this into a new file called src/main.js
:
// src/main.js
import foo from './foo.js';
export default function () {
console.log(foo);
}
Then, let's create the foo.js
module that our entry point imports:
// src/foo.js
export default 'hello world!';
Now we're ready to create a bundle:
rollup src/main.js -f cjs
The -f
option (short for --format
) specifies what kind of bundle we're creating — in this case, CommonJS (which will run in Node.js). Because we didn't specify an output file, it will be printed straight to stdout
:
'use strict';
const foo = 'hello world!';
const main = function () {
console.log(foo);
};
module.exports = main;
You can save the bundle as a file like so:
rollup src/main.js -o bundle.js -f cjs
(You could also do rollup src/main.js -f cjs > bundle.js
, but as we'll see later, this is less flexible if you're generating sourcemaps.)
Try running the code:
node
> var myBundle = require('./bundle.js');
> myBundle();
'hello world!'
Congratulations! You've created your first bundle with Rollup.
So far, so good, but as we start adding more options it becomes a bit of a nuisance to type out the command.
To save repeating ourselves, we can create a config file containing all the options we need. A config file is written in JavaScript and is more flexible than the raw CLI.
Create a file in the project root called rollup.config.js
, and add the following code:
// rollup.config.js
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
}
};
(Note that you can use CJS modules and therefore module.exports = {/* config */}
)
To use the config file, we use the --config
or -c
flag:
rm bundle.js # so we can check the command works!
rollup -c
You can override any of the options in the config file with the equivalent command line options:
rollup -c -o bundle-2.js # `-o` is equivalent to `--file` (formerly "output")
Note: Rollup itself processes the config file, which is why we're able to use export default
syntax – the code isn't being transpiled with Babel or anything similar, so you can only use ES2015 features that are supported in the version of Node.js that you're running.
You can, if you like, specify a different config file from the default rollup.config.js
:
rollup --config rollup.config.dev.js
rollup --config rollup.config.prod.js
When working within teams or distributed environments it can be wise to add Rollup as a local dependency. Installing Rollup locally prevents the requirement that multiple contributors install Rollup separately as an extra step, and ensures that all contributors are using the same version of Rollup.
To install Rollup locally with NPM:
npm install rollup --save-dev
Or with Yarn:
yarn -D add rollup
After installing, Rollup can be run within the root directory of your project:
npx rollup --config
Or with Yarn:
yarn rollup --config
Once installed, it's common practice to add a single build script to package.json
, providing a convenient command for all contributors. e.g.
{
"scripts": {
"build": "rollup --config"
}
}
Note: Once installed locally, both NPM and Yarn will resolve the dependency's bin file and execute Rollup when called from a package script.
So far, we've created a simple bundle from an entry point and a module imported via a relative path. As you build more complex bundles, you'll often need more flexibility – importing modules installed with NPM, compiling code with Babel, working with JSON files and so on.
For that, we use plugins, which change the behaviour of Rollup at key points in the bundling process. A list of awesome plugins is maintained on the Rollup Awesome List.
For this tutorial, we'll use @rollup/plugin-json, which allows Rollup to import data from a JSON file.
Create a file in the project root called package.json
, and add the following content:
{
"name": "rollup-tutorial",
"version": "1.0.0",
"scripts": {
"build": "rollup -c"
}
}
Install @rollup/plugin-json as a development dependency:
npm install --save-dev @rollup/plugin-json
(We're using --save-dev
rather than --save
because our code doesn't actually depend on the plugin when it runs – only when we're building the bundle.)
Update your src/main.js
file so that it imports from your package.json instead of src/foo.js
:
// src/main.js
import { version } from '../package.json';
export default function () {
console.log('version ' + version);
}
Edit your rollup.config.js
file to include the JSON plugin:
// rollup.config.js
import json from '@rollup/plugin-json';
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [json()]
};
Run Rollup with npm run build
. The result should look like this:
'use strict';
var version = '1.0.0';
function main() {
console.log('version ' + version);
}
module.exports = main;
Note: Only the data we actually need gets imported – name
and devDependencies
and other parts of package.json
are ignored. That's tree-shaking in action.
Some plugins can also be applied specifically to some outputs. See plugin hooks for the technical details of what output-specific plugins can do. In a nut-shell, those plugins can only modify code after the main analysis of Rollup has completed. Rollup will warn if an incompatible plugin is used as an output-specific plugin. One possible use-case is minification of bundles to be consumed in a browser.
Let us extend the previous example to provide a minified build together with the non-minified one. To that end, we install rollup-plugin-terser
:
npm install --save-dev rollup-plugin-terser
Edit your rollup.config.js
file to add a second minified output. As format, we choose iife
. This format wraps the code so that it can be consumed via a script
tag in the browser while avoiding unwanted interactions with other code. As we have an export, we need to provide the name of a global variable that will be created by our bundle so that other code can access our export via this variable.
// rollup.config.js
import json from '@rollup/plugin-json';
import { terser } from 'rollup-plugin-terser';
export default {
input: 'src/main.js',
output: [
{
file: 'bundle.js',
format: 'cjs'
},
{
file: 'bundle.min.js',
format: 'iife',
name: 'version',
plugins: [terser()]
}
],
plugins: [json()]
};
Besides bundle.js
, Rollup will now create a second file bundle.min.js
:
var version = (function () {
'use strict';
var n = '1.0.0';
return function () {
console.log('version ' + n);
};
})();
For code splitting, there are cases where Rollup splits code into chunks automatically, like dynamic loading or multiple entry points, and there is a way to explicitly tell Rollup which modules to split into separate chunks via the output.manualChunks
option.
To use the code splitting feature to achieve the lazy dynamic loading (where some imported module(s) is only loaded after executing a function), we go back to the original example and modify src/main.js
to load src/foo.js
dynamically instead of statically:
// src/main.js
export default function () {
import('./foo.js').then(({ default: foo }) => console.log(foo));
}
Rollup will use the dynamic import to create a separate chunk that is only loaded on demand. In order for Rollup to know where to place the second chunk, instead of passing the --file
option we set a folder to output to with the --dir
option:
rollup src/main.js -f cjs -d dist
This will create a folder dist
containing two files, main.js
and chunk-[hash].js
, where [hash]
is a content based hash string. You can supply your own naming patterns by specifying the output.chunkFileNames
and output.entryFileNames
options.
You can still run your code as before with the same output, albeit a little slower as loading and parsing of ./foo.js
will only commence once we call the exported function for the first time.
node -e "require('./dist/main.js')()"
If we do not use the --dir
option, Rollup will again print the chunks to stdout
, adding comments to highlight the chunk boundaries:
//→ main.js:
'use strict';
function main() {
Promise.resolve(require('./chunk-b8774ea3.js')).then(({ default: foo }) => console.log(foo));
}
module.exports = main;
//→ chunk-b8774ea3.js:
('use strict');
var foo = 'hello world!';
exports.default = foo;
This is useful if you want to load and parse expensive features only once they are used.
A different use for code-splitting is the ability to specify several entry points that share some dependencies. Again we extend our example to add a second entry point src/main2.js
that statically imports src/foo.js
just like we did in the original example:
// src/main2.js
import foo from './foo.js';
export default function () {
console.log(foo);
}
If we supply both entry points to rollup, three chunks are created:
rollup src/main.js src/main2.js -f cjs
will output
//→ main.js:
'use strict';
function main() {
Promise.resolve(require('./chunk-b8774ea3.js')).then(({ default: foo }) => console.log(foo));
}
module.exports = main;
//→ main2.js:
('use strict');
var foo_js = require('./chunk-b8774ea3.js');
function main2() {
console.log(foo_js.default);
}
module.exports = main2;
//→ chunk-b8774ea3.js:
('use strict');
var foo = 'hello world!';
exports.default = foo;
Notice how both entry points import the same shared chunk. Rollup will never duplicate code and instead create additional chunks to only ever load the bare minimum necessary. Again, passing the --dir
option will write the files to disk.
You can build the same code for the browser via native ES modules, an AMD loader or SystemJS.
For example, with -f es
for native modules:
rollup src/main.js src/main2.js -f es -d dist
<!DOCTYPE html>
<script type="module">
import main2 from './dist/main2.js';
main2();
</script>
Or alternatively, for SystemJS with -f system
:
rollup src/main.js src/main2.js -f system -d dist
Install SystemJS via
npm install --save-dev systemjs
And then load either or both entry points in an HTML page as needed:
<!DOCTYPE html>
<script src="node_modules/systemjs/dist/s.min.js"></script>
<script>
System.import('./dist/main2.js').then(({ default: main }) => main());
</script>
See rollup-starter-code-splitting for an example on how to set up a web app that uses native ES modules on browsers that support them with a fallback to SystemJS if necessary.
this.addWatchFile(id: string) => void
this.emitFile(emittedFile: EmittedChunk | EmittedAsset) => string
this.error(error: string | Error, position?: number | { column: number; line: number }) => never
this.getCombinedSourcemap() => SourceMap
this.getFileName(referenceId: string) => string
this.getModuleIds() => IterableIterator<string>
this.getModuleInfo(moduleId: string) => (ModuleInfo | null)
this.getWatchFiles() => string[]
this.meta: {rollupVersion: string, watchMode: boolean}
this.parse(code: string, acornOptions?: AcornOptions) => ESTree.Program
this.resolve(source: string, importer?: string, options?: {skipSelf?: boolean, custom?: {[plugin: string]: any}}) => Promise<{id: string, external: boolean | "absolute", moduleSideEffects: boolean | 'no-treeshake', syntheticNamedExports: boolean | string, meta: {[plugin: string]: any}} | null>
this.setAssetSource(referenceId: string, source: string | Uint8Array) => void
this.warn(warning: string | RollupWarning, position?: number | { column: number; line: number }) => void
A Rollup plugin is an object with one or more of the properties, build hooks, and output generation hooks described below, and which follows our conventions. 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 customise Rollup's behaviour by, for example, transpiling code before bundling, or finding third-party modules in your node_modules
folder. For an example on how to use them, see Using plugins.
A List of Plugins may be found at github.com/rollup/awesome. If you would like to make a suggestion for a plugin, please submit a Pull Request.
The following plugin will intercept any imports of virtual-module
without accessing the file system. This is for instance necessary if you want to use Rollup in a browser. It can even be used to replace entry points as shown in the example.
// rollup-plugin-my-example.js
export default function myExample () {
return {
name: 'my-example', // this name will show up in warnings and errors
resolveId ( source ) {
if (source === 'virtual-module') {
return source; // this signals that rollup should not ask other plugins or check the file system to find this id
}
return null; // other ids should be handled as usually
},
load ( id ) {
if (id === 'virtual-module') {
return 'export default "This is virtual!"'; // the source code for "virtual-module"
}
return null; // other ids should be handled as usually
}
};
}
// rollup.config.js
import myExample from './rollup-plugin-my-example.js';
export default ({
input: 'virtual-module', // resolved by our plugin
plugins: [myExample()],
output: [{
file: 'bundle.js',
format: 'es'
}]
});
rollup-plugin-
prefix.rollup-plugin
keyword in package.json
.\0
. This prevents other plugins from trying to process it.name
Type: string
The name of the plugin, for use in error messages and warnings.
To interact with the build process, your plugin object includes 'hooks'. Hooks are functions which 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.Build hooks are run during the build phase, which is triggered by rollup.rollup(inputOptions)
. They are mainly concerned with locating, providing and transforming input files before they are processed by Rollup. The first hook of the build phase is options
, the last one is always buildEnd
. If there is a build error, closeBundle
will be called after that.
Additionally, in watch mode the 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
hook will be triggered.
See Output Generation Hooks for hooks that run during the output generation phase to modify the generated output.
buildEnd
Type: (error?: Error) => void
Kind: async, parallel
Previous Hook: moduleParsed
, resolveId
or resolveDynamicImport
.
Next Hook: outputOptions
in the output generation phase as this is the last hook of the build phase.
Called when rollup has finished bundling, but before generate
or write
is called; you can also return a Promise. If an error occurred during the build, it is passed on to this hook.
buildStart
Type: (options: InputOptions) => void
Kind: async, parallel
Previous Hook: options
Next Hook: resolveId
to resolve each entry point in parallel.
Called on each rollup.rollup
build. This is the recommended hook to use when you need access to the options passed to rollup.rollup()
as it takes the transformations by all options
hooks into account and also contains the right default values for unset options.
closeWatcher
Type: () => void
Kind: sync, sequential
Previous/Next Hook: This hook can be triggered at any time both during the build and the output generation phases. If that is the case, the current build will still proceed but no new watchChange
events will be triggered ever.
Notifies a plugin when watcher process closes and all open resources should be closed too. This hook cannot be used by output plugins.
load
Type: (id: string) => string | null | {code: string, map?: string | SourceMap, ast? : ESTree.Program, moduleSideEffects?: boolean | "no-treeshake" | null, syntheticNamedExports?: boolean | string | null, meta?: {[plugin: string]: any} | null}
Kind: async, first
Previous Hook: resolveId
or resolveDynamicImport
where the loaded id was resolved.
Next Hook: transform
to transform the loaded file.
Defines a custom loader. Returning null
defers to other load
functions (and eventually the default behavior of loading from the file system). To prevent additional parsing overhead in case e.g. this hook already used this.parse
to generate an AST for some reason, this hook can optionally return a { code, ast, map }
object. The ast
must be a standard ESTree AST with start
and end
properties for each node. If the transformation does not move code, you can preserve existing sourcemaps by setting map
to null
. Otherwise you might need to generate the source map. See the section on source code transformations.
If false
is returned for moduleSideEffects
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 returned, Rollup will use its default algorithm to include all statements in the module that have side-effects (such as modifying a global or exported variable). If "no-treeshake"
is returned, treeshaking will be turned off for this module and it will also be included in one of the generated chunks even if it is empty. If null
is returned or the flag is omitted, then moduleSideEffects
will be determined by the first resolveId
hook that resolved this module, the treeshake.moduleSideEffects
option, or eventually default to true
. The transform
hook can override this.
See synthetic named exports for the effect of the syntheticNamedExports
option. If null
is returned or the flag is omitted, then syntheticNamedExports
will be determined by the first resolveId
hook that resolved this module or eventually default to false
. The transform
hook can override this.
See custom module meta-data for how to use the meta
option. If a meta
object is returned by this hook, it will be merged shallowly with any meta
object returned by the resolveId hook. If no hook returns a meta
object it will default to an empty object. The transform
hook can further add or replace properties of this object.
You can use this.getModuleInfo
to find out the previous values of moduleSideEffects
, syntheticNamedExports
and meta
inside this hook.
moduleParsed
Type: (moduleInfo: ModuleInfo) => void
Kind: async, parallel
Previous Hook: transform
where the currently handled file was transformed.
NextHook: resolveId
and resolveDynamicImport
to resolve all discovered static and dynamic imports in parallel if present, otherwise buildEnd
.
This hook is called each time a module has been fully parsed by Rollup. See this.getModuleInfo
for what information is passed to this hook.
In contrast to the transform
hook, this hook is never cached and can be used to get information about both cached and other modules, including the final shape of the meta
property, the code
and the ast
.
Note that information about imported modules is not yet available in this hook, and information about importing modules may be incomplete as additional importers could be discovered later. If you need this information, use the buildEnd
hook.
options
Type: (options: InputOptions) => InputOptions | null
Kind: async, sequential
Previous Hook: This is the first hook of the build phase.
Next Hook: buildStart
Replaces or manipulates the options object passed to rollup.rollup
. Returning null
does not replace anything. If you just need to read the options, it is recommended to use the buildStart
hook as that hook has access to the options after the transformations from all options
hooks have been taken into account.
This is the only hook that does not have access to most plugin context utility functions as it is run before rollup is fully configured.
resolveDynamicImport
Type: (specifier: string | ESTree.Node, importer: string) => string | false | null | {id: string, external?: boolean}
Kind: async, first
Previous Hook: moduleParsed
for the importing file.
Next Hook: load
if the hook resolved with an id that has not yet been loaded, resolveId
if the dynamic import contains a string and was not resolved by the hook, otherwise buildEnd
.
Defines a custom resolver for dynamic imports. Returning false
signals that the import should be kept as it is and not be passed to other resolvers thus making it external. Similar to the resolveId
hook, you can also return an object to resolve the import to a different id while marking it as external at the same time.
In case a dynamic import is passed a string as argument, a string returned from this hook will be interpreted as an existing module id while returning null
will defer to other resolvers and eventually to resolveId
.
In case a dynamic import is not passed a string as argument, this hook gets access to the raw AST nodes to analyze and behaves slightly different in the following ways:
null
, the import is treated as external
without a warning.{id, external}
.Note that the return value of this hook will not be passed to resolveId
afterwards; if you need access to the static resolution algorithm, you can use this.resolve(source, importer)
on the plugin context.
resolveId
Type: (source: string, importer: string | undefined, options: {custom?: {[plugin: string]: any}) => string | false | null | {id: string, external?: boolean | "relative" | "absolute", moduleSideEffects?: boolean | "no-treeshake" | null, syntheticNamedExports?: boolean | string | null, meta?: {[plugin: string]: any} | null}
Kind: async, first
Previous Hook: buildStart
if we are resolving an entry point, moduleParsed
if we are resolving an import, or as fallback for resolveDynamicImport
. Additionally this hook can be triggered during the build phase from plugin hooks by calling this.emitFile
to emit an entry point or at any time by calling this.resolve
to manually resolve an id.
Next Hook: load
if the resolved id that has not yet been loaded, otherwise buildEnd
.
Defines a custom resolver. A resolver can be useful for e.g. locating third-party dependencies. Here source
is the importee exactly as it is written in the import statement, i.e. for
import { foo } from '../bar.js';
the source will be "../bar.js""
.
The importer
is the fully resolved id of the importing module. When resolving entry points, importer will be undefined
. You can use this for instance as a mechanism to define custom proxy modules for entry points.
The following plugin will only expose the default export from entry points while still keeping named exports available for internal usage:
async resolveId(source,importer) {
if (!importer) {
// We need to skip this plugin to avoid an infinite loop
const resolution = await this.resolve(source, undefined, { skipSelf: true });
// If it cannot be resolved, return `null` so that Rollup displays an error
if (!resolution) return null;
return `${resolution.id}?entry-proxy`;
}
return null;
},
load(id) {
if (id.endsWith('?entry-proxy')) {
const importee = id.slice(0, -'?entry-proxy'.length);
// Note that this will throw if there is no default export
return `export {default} from '${importee}';`;
}
return null;
}
Returning null
defers to other resolveId
functions 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 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. This allows you to replace dependencies with external dependencies without the need for the user to mark them as "external" manually via the external
option:
resolveId(source) {
if (source === 'my-dependency') {
return {id: 'my-dependency-develop', external: true};
}
return null;
}
If external
is true
, then absolute ids will be converted to relative ids based on the user's choice for the makeAbsoluteExternalsRelative
option. This choice can be overridden by passing either external: "relative"
to always convert an absolute id to a relative id or external: "absolute"
to keep it as an absolute id. When returning an object, 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 renormalised and deduplicated instead, return an absolute file system location as id
and choose external: "relative"
.
If false
is returned for moduleSideEffects
in the first hook that resolves a module id and no other module imports anything from this module, then this module will not be included even if the module would have side-effects. If true
is returned, Rollup will use its default algorithm to include all statements in the module that have side-effects (such as modifying a global or exported variable). If "no-treeshake"
is returned, treeshaking will be turned off for this module and it will also be included in one of the generated chunks even if it is empty. If null
is returned or the flag is omitted, then moduleSideEffects
will be determined by the treeshake.moduleSideEffects
option or default to true
. The load
and transform
hooks can override this.
See synthetic named exports for the effect of the syntheticNamedExports
option. If null
is returned or the flag is omitted, then syntheticNamedExports
will default to false
. The load
and transform
hooks can override this.
See custom module meta-data for how to use the meta
option. If null
is returned or the option is omitted, then meta
will default to an empty object. The load
and transform
hooks can add or replace properties of this object.
When triggering this hook from a plugin via this.resolve(source, importer, options)
, it is possible to pass a custom options object to this hook. While this object will be passed unmodified, plugins should follow the convention of adding a custom
property with an object where the keys correspond to the names of the plugins that the options are intended for. For details see custom resolver options.
transform
Type: (code: string, id: string) => string | null | {code?: string, map?: string | SourceMap, ast? : ESTree.Program, moduleSideEffects?: boolean | "no-treeshake" | null, syntheticNamedExports?: boolean | string | null, meta?: {[plugin: string]: any} | null}
Kind: async, sequential
Previous Hook: load
where the currently handled file was loaded.
NextHook: moduleParsed
once the file has been processed and parsed.
Can be used to transform individual modules. To prevent additional parsing overhead in case e.g. this hook already used this.parse
to generate an AST for some reason, this hook can optionally return a { code, ast, map }
object. The ast
must be a standard ESTree AST with start
and end
properties for each node. If the transformation does not move code, you can preserve existing sourcemaps by setting map
to null
. Otherwise you might need to generate the source map. See the section on source code transformations.
Note that in watch mode, the result of this hook is cached when rebuilding and the hook is only triggered again for a module id
if either the code
of the module has changed or a file has changed that was added via this.addWatchFile
the last time the hook was triggered for this module.
You can also use the object form of the return value to configure additional properties of the module. Note that it's possible to return only properties and no code transformations.
If false
is returned for moduleSideEffects
and no other module imports anything from this module, then this module will not be included even if the module would have side-effects.
If true
is returned, Rollup will use its default algorithm to include all statements in the module that have side-effects (such as modifying a global or exported variable).
If "no-treeshake"
is returned, treeshaking will be turned off for this module and it will also be included in one of the generated chunks even if it is empty.
If null
is returned or the flag is omitted, then moduleSideEffects
will be determined by the load
hook that loaded this module, the first resolveId
hook that resolved this module, the treeshake.moduleSideEffects
option, or eventually default to true
.
See synthetic named exports for the effect of the syntheticNamedExports
option. If null
is returned or the flag is omitted, then syntheticNamedExports
will be determined by the load
hook that loaded this module, the first resolveId
hook that resolved this module, the treeshake.moduleSideEffects
option, or eventually default to false
.
See custom module meta-data for how to use the meta
option. If null
is returned or the option is omitted, then meta
will be determined by the load
hook that loaded this module, the first resolveId
hook that resolved this module or eventually default to an empty object.
You can use this.getModuleInfo
to find out the previous values of moduleSideEffects
, syntheticNamedExports
and meta
inside this hook.
watchChange
Type: watchChange: (id: string, change: {event: 'create' | 'update' | 'delete'}) => void
Kind: sync, sequential
Previous/Next Hook: This hook can be triggered at any time both during the build and the output generation phases. If that is the case, the current build will still proceed but a new build will be scheduled to start once the current build has completed, starting again with options
.
Notifies a plugin whenever rollup has detected a change to a monitored file in --watch
mode. This hook cannot be used by output plugins. Second argument contains additional details of change event.
Output generation hooks can provide information about a generated bundle and modify a build once complete. They work the same way and have the same types as Build Hooks but are called separately for each call to bundle.generate(outputOptions)
or bundle.write(outputOptions)
. 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 outputOptions
, the last one is either generateBundle
if the output was successfully generated via bundle.generate(...)
, writeBundle
if the output was successfully generated via bundle.write(...)
, or renderError
if an error occurred at any time during the output generation.
Additionally, closeBundle
can be called as the very last hook, but it is the responsibility of the User to manually call bundle.close()
to trigger this. The CLI will always make sure this is the case.
augmentChunkHash
Type: (chunkInfo: ChunkInfo) => string
Kind: sync, sequential
Previous Hook: renderDynamicImport
for each dynamic import expression.
Next Hook: resolveFileUrl
for each use of import.meta.ROLLUP_FILE_URL_referenceId
and resolveImportMeta
for all other accesses to import.meta
.
Can be used to augment the hash of individual chunks. Called for each Rollup output chunk. Returning a falsy value will not modify the hash. Truthy values will be passed to hash.update
. The chunkInfo
is a reduced version of the one in generateBundle
without properties that rely on file names.
The following plugin will invalidate the hash of chunk foo
with the timestamp of the last build:
// rollup.config.js
augmentChunkHash(chunkInfo) {
if(chunkInfo.name === 'foo') {
return Date.now().toString();
}
}
banner
Type: string | (() => string)
Kind: async, parallel
Previous Hook: renderStart
Next Hook: renderDynamicImport
for each dynamic import expression.
Cf. output.banner/output.footer
.
closeBundle
Type: closeBundle: () => Promise<void> | void
Kind: async, parallel
Previous Hook: buildEnd
if there was a build error, otherwise when bundle.close()
is called, in which case this would be the last hook to be triggered.
Can be used to clean up any external service that may be running. Rollup'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()
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
in this hook and perform the necessary cleanup for watch mode in closeWatcher
.
footer
Type: string | (() => string)
Kind: async, parallel
Previous Hook: renderStart
Next Hook: renderDynamicImport
for each dynamic import expression.
Cf. output.banner/output.footer
.
generateBundle
Type: (options: OutputOptions, bundle: { [fileName: string]: AssetInfo | ChunkInfo }, isWrite: boolean) => void
Kind: async, sequential
Previous Hook: renderChunk
for each chunk.
Next Hook: writeBundle
if the output was generated via bundle.write(...)
, otherwise this is the last hook of the output generation phase and may again be followed by outputOptions
if another output is generated.
Called at the end of bundle.generate()
or immediately before the files are written in bundle.write()
. To modify the files after they have been written, use the writeBundle
hook. bundle
provides the full list of files being written or generated along with their details:
// AssetInfo
{
fileName: string,
name?: string,
source: string | Uint8Array,
type: 'asset',
}
// ChunkInfo
{
code: string,
dynamicImports: string[],
exports: string[],
facadeModuleId: string | null,
fileName: string,
implicitlyLoadedBefore: string[],
imports: string[],
importedBindings: {[imported: string]: string[]},
isDynamicEntry: boolean,
isEntry: boolean,
isImplicitEntry: boolean,
map: SourceMap | null,
modules: {
[id: string]: {
renderedExports: string[],
removedExports: string[],
renderedLength: number,
originalLength: number,
code: string | null
},
},
name: string,
referencedFiles: string[],
type: 'chunk',
}
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
plugin context function.
intro
Type: string | (() => string)
Kind: async, parallel
Previous Hook: renderStart
Next Hook: renderDynamicImport
for each dynamic import expression.
Cf. output.intro/output.outro
.
outputOptions
Type: (outputOptions: OutputOptions) => OutputOptions | null
Kind: sync, sequential
Previous Hook: buildEnd
if this is the first time an output is generated, otherwise either generateBundle
, writeBundle
or renderError
depending on the previously generated output. This is the first hook of the output generation phase.
Next Hook: renderStart
.
Replaces or manipulates the output options object passed to bundle.generate()
or bundle.write()
. Returning null
does not replace anything. If you just need to read the output options, it is recommended to use the renderStart
hook as this hook has access to the output options after the transformations from all outputOptions
hooks have been taken into account.
outro
Type: string | (() => string)
Kind: async, parallel
Previous Hook: renderStart
Next Hook: renderDynamicImport
for each dynamic import expression.
Cf. output.intro/output.outro
.
renderChunk
Type: (code: string, chunk: ChunkInfo, options: OutputOptions) => string | { code: string, map: SourceMap } | null
Kind: async, sequential
Previous Hook: resolveFileUrl
for each use of import.meta.ROLLUP_FILE_URL_referenceId
and resolveImportMeta
for all other accesses to import.meta
.
Next Hook: generateBundle
.
Can be used to transform individual chunks. Called for each Rollup output chunk file. Returning null
will apply no transformations.
renderDynamicImport
Type: ({format: string, moduleId: string, targetModuleId: string | null, customResolution: string | null}) => {left: string, right: string} | null
Kind: sync, first
Previous Hook: banner
, footer
, intro
, outro
.
Next Hook: augmentChunkHash
for each chunk that would contain a hash in the file name.
This hook provides fine-grained control over how dynamic imports are rendered by providing replacements for the code to the left (import(
) and right ()
) of the argument of the import expression. Returning null
defers to other hooks of this type and ultimately renders a format-specific default.
format
is the rendered output format, moduleId
the id of the module performing the dynamic import. If the import could be resolved to an internal or external id, then targetModuleId
will be set to this id, otherwise it will be null
. If the dynamic import contained a non-string expression that was resolved by a resolveDynamicImport
hook to a replacement string, then customResolution
will contain that string.
The following code will replace all dynamic imports with a custom handler, adding import.meta.url
as a second argument to allow the handler to resolve relative imports correctly:
// plugin
const plugin = {
name: 'dynamic-import-polyfill',
renderDynamicImport() {
return {
left: 'dynamicImportPolyfill(',
right: ', import.meta.url)'
};
}
};
// input
import('./lib.js');
// output
dynamicImportPolyfill('./lib.js', import.meta.url);
The next plugin will make sure all dynamic imports of esm-lib
are marked as external and retained as import expressions to e.g. allow a CommonJS build to import an ES module in Node 13+, cf. how to import ES modules from CommonJS in the Node documentation.
// plugin
const plugin = {
name: 'retain-import-expression',
resolveDynamicImport(specifier) {
if (specifier === 'esm-lib') return false;
return null;
},
renderDynamicImport({ targetModuleId }) {
if (targetModuleId === 'esm-lib') {
return {
left: 'import(',
right: ')'
};
}
}
};
Note that when this hook rewrites dynamic imports in non-ES formats, no interop code to make sure that e.g. the default export is available as .default
is generated. It is the responsibility of the plugin to make sure the rewritten dynamic import returns a Promise that resolves to a proper namespace object.
renderError
Type: (error: Error) => void
Kind: async, parallel
Previous Hook: Any hook from renderStart
to renderChunk
.
Next Hook: If it is called, this is the last hook of the output generation phase and may again be followed by outputOptions
if another output is generated.
Called when rollup encounters an error during bundle.generate()
or bundle.write()
. The error is passed to this hook. To get notified when generation completes successfully, use the generateBundle
hook.
renderStart
Type: (outputOptions: OutputOptions, inputOptions: InputOptions) => void
Kind: async, parallel
Previous Hook: outputOptions
Next Hook: banner
, footer
, intro
and outro
run in parallel.
Called initially each time bundle.generate()
or bundle.write()
is called. To get notified when generation has completed, use the generateBundle
and renderError
hooks. This is the recommended hook to use when you need access to the output options passed to bundle.generate()
or bundle.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 rollup.rollup()
so that plugins that can be used as output plugins, i.e. plugins that only use generate
phase hooks, can get access to them.
resolveFileUrl
Type: ({chunkId: string, fileName: string, format: string, moduleId: string, referenceId: string, relativePath: string}) => string | null
Kind: sync, first
Previous Hook: augmentChunkHash
for each chunk that would contain a hash in the file name.
Next Hook: renderChunk
for each chunk.
Allows to customize how Rollup resolves URLs of files that were emitted by plugins via this.emitFile
. By default, Rollup will generate code for import.meta.ROLLUP_FILE_URL_referenceId
that should correctly generate absolute URLs of emitted files independent of the output format and the host system where the code is deployed.
For that, all formats except CommonJS and UMD assume that they run in a browser environment where URL
and document
are available. In case that fails or to generate more optimized code, this hook can be used to customize this behaviour. To do that, the following information is available:
chunkId
: The id of the chunk this file is referenced from.fileName
: The path and file name of the emitted asset, relative to output.dir
without a leading ./
.format
: The rendered output format.moduleId
: The id of the original module this file is referenced from. Useful for conditionally resolving certain assets differently.referenceId
: The reference id of the file.relativePath
: The path and file name of the emitted file, relative to the chunk the file is referenced from. This will path will contain no leading ./
but may contain a leading ../
.Note that since this hook has access to the filename of the current chunk, its return value will not be considered when generating the hash of this chunk.
The following plugin will always resolve all files relative to the current document:
// rollup.config.js
resolveFileUrl({fileName}) {
return `new URL('${fileName}', document.baseURI).href`;
}
resolveImportMeta
Type: (property: string | null, {chunkId: string, moduleId: string, format: string}) => string | null
Kind: sync, first
Previous Hook: augmentChunkHash
for each chunk that would contain a hash in the file name.
Next Hook: renderChunk
for each chunk.
Allows to customize how Rollup handles import.meta
and import.meta.someProperty
, in particular import.meta.url
. In ES modules, import.meta
is an object and import.meta.url
contains the URL of the current module, e.g. http://server.net/bundle.js
for browsers or file:///path/to/bundle.js
in Node.
By default for formats other than ES modules, Rollup replaces import.meta.url
with code that attempts to match this behaviour by returning the dynamic URL of the current chunk. Note that all formats except CommonJS and UMD assume that they run in a browser environment where URL
and document
are available. For other properties, import.meta.someProperty
is replaced with undefined
while import.meta
is replaced with an object containing a url
property.
This behaviour can be changed—also for ES modules—via this hook. For each occurrence of import.meta<.someProperty>
, this hook is called with the name of the property or null
if import.meta
is accessed directly. For example, the following code will resolve import.meta.url
using the relative path of the original module to the current working directory and again resolve this path against the base URL of the current document at runtime:
// rollup.config.js
resolveImportMeta(property, {moduleId}) {
if (property === 'url') {
return `new URL('${path.relative(process.cwd(), moduleId)}', document.baseURI).href`;
}
return null;
}
Note that since this hook has access to the filename of the current chunk, its return value will not be considered when generating the hash of this chunk.
writeBundle
Type: (options: OutputOptions, bundle: { [fileName: string]: AssetInfo | ChunkInfo }) => void
Kind: async, parallel
Previous Hook: generateBundle
Next Hook: If it is called, this is the last hook of the output generation phase and may again be followed by outputOptions
if another output is generated.
Called only at the end of bundle.write()
once all files have been written. Similar to the generateBundle
hook, bundle
provides the full list of files being written along with their details.
☢️ These hooks have been deprecated and may be removed in a future Rollup version.
resolveAssetUrl
- Use resolveFileUrl
- Function hook that allows to customize the generated code for asset URLs.More properties may be supported in the future, as and when they prove necessary.
A number of utility functions and informational bits can be accessed from within most hooks via this
:
this.addWatchFile(id: string) => void
Adds additional files to be monitored in watch mode so that changes to these files will trigger rebuilds. id
can be an absolute path to a file or directory or a path relative to the current working directory. This context function can only be used in hooks during the build phase, i.e. in buildStart
, load
, resolveId
, and transform
.
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.
this.emitFile(emittedFile: EmittedChunk | EmittedAsset) => string
Emits a new file that is included in the build output and returns a referenceId
that can be used in various places to reference the emitted file. emittedFile
can have one of two forms:
// EmittedChunk
{
type: 'chunk',
id: string,
name?: string,
fileName?: string,
implicitlyLoadedAfterOneOf?: string[],
importer?: string,
preserveSignature?: 'strict' | 'allow-extension' | 'exports-only' | false,
}
// EmittedAsset
{
type: 'asset',
name?: string,
fileName?: string,
source?: string | Uint8Array
}
In both cases, either a name
or a fileName
can be supplied. If a 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
is supplied, this will be used as substitution for [name]
in the corresponding output.chunkFileNames
or output.assetFileNames
pattern, possibly adding a unique number to the end of the file name to avoid conflicts. If neither a name
nor fileName
is supplied, a default name will be used.
You can reference the URL of an emitted file in any code returned by a load
or transform
plugin hook via import.meta.ROLLUP_FILE_URL_referenceId
. See File URLs for more details and an example.
The generated code that replaces import.meta.ROLLUP_FILE_URL_referenceId
can be customized via the resolveFileUrl
plugin hook. You can also use this.getFileName(referenceId)
to determine the file name as soon as it is available
If the type
is chunk
, then this emits a new chunk with the given module id
as entry point. To resolve it, the id
will be passed through build hooks just like regular entry points, starting with resolveId
. If an importer
is provided, this acts as the second parameter of resolveId
and is important to properly resolve relative paths. If it is not provided, paths will be resolved relative to the current working directory. If a value for preserveSignature
is provided, this will override preserveEntrySignatures
for this particular chunk.
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
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
name pattern will be used.
By default, Rollup assumes that emitted chunks are executed independent of other entry points, possibly even before any other code is executed. This means that if an emitted chunk shares a dependency with an existing entry point, Rollup will create an additional chunk for dependencies that are shared between those entry points. Providing a non-empty array of module ids for implicitlyLoadedAfterOneOf
will change that behaviour by giving Rollup additional information to prevent this in some cases. Those ids will be resolved the same way as the id
property, respecting the importer
property if it is provided. Rollup will now assume that the emitted chunk is only executed if at least one of the entry points that lead to one of the ids in implicitlyLoadedAfterOneOf
being loaded has already been executed, creating the same chunks as if the newly emitted chunk was only reachable via dynamic import from the modules in implicitlyLoadedAfterOneOf
. Here is an example that uses this to create a simple HTML file with several scripts, creating optimized chunks to respect their execution order:
// rollup.config.js
function generateHtml() {
let ref1, ref2, ref3;
return {
buildStart() {
ref1 = this.emitFile({
type: 'chunk',
id: 'src/entry1'
});
ref2 = this.emitFile({
type: 'chunk',
id: 'src/entry2',
implicitlyLoadedAfterOneOf: ['src/entry1']
});
ref3 = this.emitFile({
type: 'chunk',
id: 'src/entry3',
implicitlyLoadedAfterOneOf: ['src/entry2']
});
},
generateBundle() {
this.emitFile({
type: 'asset',
fileName: 'index.html',
source: `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="${this.getFileName(ref1)}" type="module"></script>
<script src="${this.getFileName(ref2)}" type="module"></script>
<script src="${this.getFileName(ref3)}" type="module"></script>
</body>
</html>`
});
}
};
}
export default {
input: [],
preserveEntrySignatures: false,
plugins: [generateHtml()],
output: {
format: 'es',
dir: 'dist'
}
};
If there are no dynamic imports, this will create exactly three chunks where the first chunk contains all dependencies of src/entry1
, the second chunk contains only the dependencies of src/entry2
that are not contained in the first chunk, importing those from the first chunk, and again the same for the third chunk.
Note that even though any module id can be used in implicitlyLoadedAfterOneOf
, Rollup will throw an error if such an id cannot be uniquely associated with a chunk, e.g. because the id
cannot be reached implicitly or explicitly from the existing static entry points, or because the file is completely tree-shaken. Using only entry points, either defined by the user or of previously emitted chunks, will always work, though.
If the type
is asset
, then this emits an arbitrary new file with the given source
as content. It is possible to defer setting the source
via this.setAssetSource(referenceId, source)
to a later time to be able to reference a file during the build phase while setting the source separately for each output during the generate phase. Assets with a specified 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 such an asset is not deduplicated, the output.assetFileNames
name pattern will be used.
this.error(error: string | Error, position?: number | { column: number; line: number }) => never
Structurally equivalent to this.warn
, except that it will also abort the bundling process.
this.getCombinedSourcemap() => SourceMap
Get the combined source maps of all previous plugins. This context function can only be used in the transform
plugin hook.
this.getFileName(referenceId: string) => string
Get the file name of a chunk or asset that has been emitted via this.emitFile
. The file name will be relative to outputOptions.dir
.
this.getModuleIds() => IterableIterator<string>
Returns an Iterator
that gives access to all module ids in the current graph. It can be iterated via
for (const moduleId of this.getModuleIds()) {
/* ... */
}
or converted into an Array via Array.from(this.getModuleIds())
.
this.getModuleInfo(moduleId: string) => (ModuleInfo | null)
Returns additional information about the module in question in the form
{
id: string, // the id of the module, for convenience
code: string | null, // the source code of the module, `null` if external or not yet available
ast: ESTree.Program, // the parsed abstract syntax tree if available
isEntry: boolean, // is this a user- or plugin-defined entry point
isExternal: boolean, // for external modules that are referenced but not included in the graph
importedIds: string[], // the module ids statically imported by this module
importers: string[], // the ids of all modules that statically import this module
dynamicallyImportedIds: string[], // the module ids imported by this module via dynamic import()
dynamicImporters: string[], // the ids of all modules that import this module via dynamic import()
implicitlyLoadedAfterOneOf: string[], // implicit relationships, declared via this.emitChunk
implicitlyLoadedBefore: string[], // implicit relationships, declared via this.emitChunk
hasModuleSideEffects: boolean | "no-treeshake" // are imports of this module included if nothing is imported from it
meta: {[plugin: string]: any} // custom module meta-data
syntheticNamedExports: boolean | string // final value of synthetic named exports
}
During the build, this object represents currently available information about the module. Before the buildEnd
hook, this information may be incomplete as e.g. the importedIds
are not yet resolved or additional importers
are discovered.
Returns null
if the module id cannot be found.
this.getWatchFiles() => string[]
Get ids of the files which has been watched previously. Include both files added by plugins with this.addWatchFile
and files added implicitly by rollup during the build.
this.meta: {rollupVersion: string, watchMode: boolean}
An object containing potentially useful Rollup metadata:
rollupVersion
: The currently running version of Rollup as define in package.json
.watchMode
: true
if Rollup was started via rollup.watch(...)
or from the command line with --watch
, false
otherwise.meta
is the only context property accessible from the options
hook.
this.parse(code: string, acornOptions?: AcornOptions) => ESTree.Program
Use Rollup's internal acorn instance to parse code to an AST.
this.resolve(source: string, importer?: string, options?: {skipSelf?: boolean, custom?: {[plugin: string]: any}}) => Promise<{id: string, external: boolean | "absolute", moduleSideEffects: boolean | 'no-treeshake', syntheticNamedExports: boolean | string, meta: {[plugin: string]: any}} | null>
Resolve imports to module ids (i.e. file names) using the same plugins that Rollup uses, and determine if an import should be external. If null
is returned, the import could not be resolved by Rollup 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
option or by explicit plugin choice in the resolveId
hook, external
will be "absolute"
instead of true
.
If you pass skipSelf: true
, then the resolveId
hook of the plugin from which this.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 behaviour, do not use skipSelf
but implement your own infinite loop prevention mechanism if necessary.
You can also pass an object of plugin-specific options via the custom
option, see custom resolver options for details.
this.setAssetSource(referenceId: string, source: string | Uint8Array) => void
Set the deferred source of an asset. Note that you can also pass a Node Buffer
as source
as it is a sub-class of Uint8Array
.
this.warn(warning: string | RollupWarning, position?: number | { column: number; line: number }) => void
Using this method will queue warnings for a build. These warnings will be printed by the CLI just like internally generated warnings (except with the plugin name), or captured by custom onwarn
handlers.
The warning
argument can be a string
or an object with (at minimum) a message
property:
this.warn('hmm...');
// is equivalent to
this.warn({ message: 'hmm...' });
Use the second form if you need to add additional properties to your warning object. Rollup will augment the warning object with a plugin
property containing the plugin name, code
(PLUGIN_WARNING
) and id
(the file being transformed) properties.
The position
argument is a character index where the warning was raised. If present, Rollup will augment the warning object with pos
, loc
(a standard { file, line, column }
object) and frame
(a snippet of code showing the error).
☢️ These context utility functions have been deprecated and may be removed in a future Rollup version.
this.emitAsset(assetName: string, source: string) => string
- Use this.emitFile
- Emits a custom file that is included in the build output, returning a referenceId
that can be used to reference the emitted file. You can defer setting the source if you provide it later via this.setAssetSource(referenceId, source)
. A string or Uint8Array
/Buffer
source must be set for each asset through either method or an error will be thrown on generate completion.
Emitted assets will follow the output.assetFileNames
naming scheme. You can reference the URL of the file in any code returned by a load
or transform
plugin hook via import.meta.ROLLUP_ASSET_URL_referenceId
.
The generated code that replaces import.meta.ROLLUP_ASSET_URL_referenceId
can be customized via the resolveFileUrl
plugin hook. Once the asset has been finalized during generate
, you can also use this.getFileName(referenceId)
to determine the file name.
this.emitChunk(moduleId: string, options?: {name?: string}) => string
- Use this.emitFile
- Emits a new chunk with the given module as entry point. This will not result in duplicate modules in the graph, instead if necessary, existing chunks will be split. It returns a referenceId
that can be used to later access the generated file name of the chunk.
Emitted chunks will follow the output.chunkFileNames
, output.entryFileNames
naming scheme. If a name
is provided, this will be used for the [name]
file name placeholder, otherwise the name will be derived from the file name. If a name
is provided, this name must not conflict with any other entry point names unless the entry points reference the same entry module. You can reference the URL of the emitted chunk in any code returned by a load
or transform
plugin hook via import.meta.ROLLUP_CHUNK_URL_referenceId
.
The generated code that replaces import.meta.ROLLUP_CHUNK_URL_referenceId
can be customized via the resolveFileUrl
plugin hook. Once the chunk has been rendered during generate
, you can also use this.getFileName(referenceId)
to determine the file name.
this.getAssetFileName(referenceId: string) => string
- Use this.getFileName
- Get the file name of an asset, according to the assetFileNames
output option pattern. The file name will be relative to outputOptions.dir
.
this.getChunkFileName(referenceId: string) => string
- Use this.getFileName
- Get the file name of an emitted chunk. The file name will be relative to outputOptions.dir
.
this.isExternal(id: string, importer: string | undefined, isResolved: boolean) => boolean
- Use this.resolve
- Determine if a given module ID is external when imported by importer
. When isResolved
is false, Rollup will try to resolve the id before testing if it is external.
this.moduleIds: IterableIterator<string>
- Use this.getModuleIds
- An Iterator
that gives access to all module ids in the current graph. It can be iterated via
for (const moduleId of this.moduleIds) {
/* ... */
}
or converted into an Array via Array.from(this.moduleIds)
.
this.resolveId(source: string, importer?: string) => Promise<string | null>
- Use this.resolve
- Resolve imports to module ids (i.e. file names) using the same plugins that Rollup uses. Returns null
if an id cannot be resolved.
To reference a file URL reference from within JS code, use the import.meta.ROLLUP_FILE_URL_referenceId
replacement. This will generate code that depends on the output format and generates a URL that points to the emitted file in the target environment. Note that all formats except CommonJS and UMD assume that they run in a browser environment where URL
and document
are available.
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:
// plugin
export default function svgResolverPlugin() {
return {
resolveId(source, importer) {
if (source.endsWith('.svg')) {
return path.resolve(path.dirname(importer), source);
}
},
load(id) {
if (id.endsWith('.svg')) {
const referenceId = this.emitFile({
type: 'asset',
name: path.basename(id),
source: fs.readFileSync(id)
});
return `export default import.meta.ROLLUP_FILE_URL_${referenceId};`;
}
}
};
}
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.ROLLUP_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
.
// plugin
const REGISTER_WORKLET = 'register-paint-worklet:';
export default function paintWorkletPlugin() {
return {
load(id) {
if (id.startsWith(REGISTER_WORKLET)) {
return `CSS.paintWorklet.addModule(import.meta.ROLLUP_FILE_URL_${this.emitFile({
type: 'chunk',
id: id.slice(REGISTER_WORKLET.length)
})});`;
}
},
resolveId(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
if (source.startsWith(REGISTER_WORKLET)) {
return this.resolve(source.slice(REGISTER_WORKLET.length), importer).then(
resolvedId => REGISTER_WORKLET + resolvedId.id
);
}
return null;
}
};
}
Usage:
// main.js
import 'register-paint-worklet:./worklet.js';
import { color, size } from './config.js';
document.body.innerHTML += `<h1 style="background-image: paint(vertical-lines);">color: ${color}, size: ${size}</h1>`;
// worklet.js
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();
}
}
}
);
// config.js
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.
Transformer plugins (i.e. those that return a transform
function for e.g. transpiling non-JS files) should support options.include
and options.exclude
, both of which can be a minimatch pattern or an array of minimatch patterns. If options.include
is omitted or of zero length, files should be included by default; otherwise they should only be included if the ID matches one of the patterns.
The transform
hook, if returning an object, can also include an ast
property. Only use this feature if you know what you're doing. Note that only the last AST in a chain of transforms will be used (and if there are transforms, any ASTs generated by the load
hook will be discarded for the transformed modules.)
(Use @rollup/pluginutils for commonly needed functions, and to implement a transformer in the recommended manner.)
import { createFilter } from '@rollup/pluginutils';
export default function myPlugin(options = {}) {
const filter = createFilter(options.include, options.exclude);
return {
transform(code, id) {
if (!filter(id)) return;
// proceed with the transformation...
return {
code: generatedCode,
map: generatedSourceMap
};
}
};
}
If a plugin transforms source code, it should generate a sourcemap automatically, unless there's a specific sourceMap: false
option. Rollup only cares about the mappings
property (everything else is handled automatically). If it doesn't make sense to generate a sourcemap, (e.g. rollup-plugin-string), return an empty sourcemap:
return {
code: transformedCode,
map: { mappings: '' }
};
If the transformation does not move code, you can preserve existing sourcemaps by returning null
:
return {
code: transformedCode,
map: null
};
If you create a plugin that you think would be useful to others, please publish it to NPM and add submit it to github.com/rollup/awesome!
It is possible to designate a fallback export for missing exports by setting the syntheticNamedExports
option for a module in the resolveId
, load
or transform
hook. If a string value is used for syntheticNamedExports
, this module will fallback the resolution of any missing named exports to properties of the named export of the given name:
dep.js: ({syntheticNamedExports: '__synthetic'}
)
export const foo = 'explicit';
export const __synthetic = {
foo: 'foo',
bar: 'bar'
}
main.js:
import { foo, bar, baz, __synthetic } from './dep.js';
// logs "explicit" as non-synthetic exports take precedence
console.log(foo);
// logs "bar", picking the property from __synthetic
console.log(bar);
// logs "undefined"
console.log(baz);
// logs "{foo:'foo',bar:'bar'}"
console.log(__synthetic);
When used as an entry point, only explicit exports will be exposed. The synthetic fallback export, i.e. __synthetic
in the example, will not be exposed for string values of syntheticNamedExports
. However if the value is true
, the default export will be exposed. This is the only notable difference between syntheticNamedExports: true
and syntheticNamedExports: 'default'
.
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 Rollup makes this possible.
Assume you have a plugin that should resolve a module to different ids depending on how it is imported. One way to achieve this would be to use special proxy ids when importing this module, e.g. a transpiled import via require("foo")
could be denoted with an id 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. 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 one 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. 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.
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.
Plugins can annotate modules with custom meta-data which can be accessed by themselves and other plugins via the resolveId
, load
, and transform
hooks. This meta-data should always be JSON.stringifyable and will be persisted in the cache e.g. in watch mode.
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.
For any other kind of inter-plugin communication, we recommend the pattern below. Note that api
will never conflict with any upcoming plugin hooks.
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 = options.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);
}
}
}
}
ES modules are an official standard and the clear path forward for JavaScript code structure, whereas CommonJS modules are an idiosyncratic legacy format that served as a stopgap solution before ES modules had been proposed. ES modules allow static analysis that helps with optimizations like tree-shaking and scope-hoisting, and provide advanced features like circular references and live bindings.
Tree-shaking, also known as "live code inclusion", is Rollup's process of eliminating code that is not actually used in a given project. It is a form of dead code elimination but can be much more efficient than other approaches with regard to output size. The name is derived from the abstract syntax tree of the modules (not the module graph). The algorithm first marks all relevant statements and then "shakes the syntax tree" to remove all dead code. It is similar in idea to the mark-and-sweep garbage collection algorithm. Even though this algorithm is not restricted to ES modules, they make it much more efficient as they allow Rollup to treat all modules together as a big abstract syntax tree with shared bindings.
Rollup strives to implement the specification for ES modules, not necessarily the behaviors of Node.js, NPM, require()
, and CommonJS. Consequently, loading of CommonJS modules and use of Node's module location resolution logic are both implemented as optional plugins, not included by default in the Rollup core. Just npm install
the commonjs and node-resolve plugins and then enable them using a rollup.config.js
file and you should be all set. If the modules import JSON files, you will also need the json plugin.
There are two primary reasons:
Philosophically, it's because Rollup is essentially a polyfill of sorts for native module loaders in both Node and browsers. In a browser, import foo from 'foo'
won't work, because browsers don't use Node's resolution algorithm.
On a practical level, it's just much easier to develop software if these concerns are neatly separated with a good API. Rollup's core is quite large, and everything that stops it getting larger is a good thing. Meanwhile, it's easier to fix bugs and add features. By keeping Rollup lean, the potential for technical debt is small.
Please see this issue for a more verbose explanation.
By default when creating multiple chunks, imports of dependencies of entry chunks will be added as empty imports to the entry chunks themselves. Example:
// input
// main.js
import value from './other-entry.js';
console.log(value);
// other-entry.js
import externalValue from 'external';
export default 2 * externalValue;
// output
// main.js
import 'external'; // this import has been hoisted from other-entry.js
import value from './other-entry.js';
console.log(value);
// other-entry.js
import externalValue from 'external';
var value = 2 * externalValue;
export default value;
This does not affect code execution order or behaviour, but it will speed up how your code is loaded and parsed. Without this optimization, a JavaScript engine needs to perform the following steps to run main.js
:
main.js
. At the end, an import to other-entry.js
will be discovered.other-entry.js
. At the end, an import to external
will be discovered.external
.main.js
.With this optimization, a JavaScript engine will discover all transitive dependencies after parsing an entry module, avoiding the waterfall:
main.js
. At the end, imports to other-entry.js
and external
will be discovered.other-entry.js
and external
. The import of external
from other-entry.js
is already loaded and parsed.main.js
.There may be situations where this optimization is not desired, in which case you can turn it off via the output.hoistTransitiveImports
option. This optimization is also never applied when using the output.preserveModules
option.
Even though Rollup will usually try to maintain exact module execution order when bundling, there are two situations when this is not always the case: code-splitting and external dependencies. The problem is most obvious with external dependencies, see the following example:
// main.js
import './polyfill.js';
import 'external';
console.log('main');
// polyfill.js
console.log('polyfill');
Here the execution order is polyfill.js
→ external
→ main.js
. Now when you bundle the code, you will get
import 'external';
console.log('polyfill');
console.log('main');
with the execution order external
→ polyfill.js
→ main.js
. This is not a problem caused by Rollup putting the import
at the top of the bundle—imports are always executed first, no matter where they are located in the file. This problem can be solved by creating more chunks: If dep.js
ends up in a different chunk than main.js
, correct execution order will be preserved. However there is not yet an automatic way to do this in Rollup. For code-splitting, the situation is similar as Rollup is trying to create as few chunks as possible while making sure no code is executed that is not needed.
For most code this is not a problem, because Rollup can guarantee:
If module A imports module B and there are no circular imports, then B will always be executed before A.
This is however a problem for polyfills, as those usually need to be executed first but it is usually not desired to place an import of the polyfill in every single module. Luckily, this is not needed:
Rollup is already used by many major JavaScript libraries, and can also be used to build the vast majority of applications. However if you want to use code-splitting or dynamic imports with older browsers, you will need an additional runtime to handle loading missing chunks. We recommend using the SystemJS Production Build as it integrates nicely with Rollup's system format output and is capable of properly handling all the ES module live bindings and re-export edge cases. Alternatively, an AMD loader can be used as well.
At some point, it's likely that your project will depend on packages installed from NPM into your node_modules
folder. Unlike other bundlers such as Webpack and Browserify, Rollup doesn't know "out of the box" how to handle these dependencies - we need to add some configuration.
Let's add a simple dependency called the-answer, which exports the answer to the question of life, the universe and everything:
npm install the-answer
# or `npm i the-answer`
If we update our src/main.js
file…
// src/main.js
import answer from 'the-answer';
export default function () {
console.log('the answer is ' + answer);
}
…and run Rollup…
npm run build
…we'll see a warning like this:
(!) Unresolved dependencies
https://github.com/rollup/rollup/wiki/Troubleshooting#treating-module-as-external-dependency
the-answer (imported by main.js)
The resulting bundle.js
will still work in Node.js, because the import
declaration gets turned into a CommonJS require
statement, but the-answer
does not get included in the bundle. For that, we need a plugin.
The @rollup/plugin-node-resolve plugin teaches Rollup how to find external modules. Install it…
npm install --save-dev @rollup/plugin-node-resolve
…and add it to your config file:
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [resolve()]
};
This time, when you npm run build
, no warning is emitted — the bundle contains the imported module.
Some libraries expose ES modules that you can import as-is — the-answer
is one such module. But at the moment, the majority of packages on NPM are exposed as CommonJS modules instead. Until that changes, we need to convert CommonJS to ES2015 before Rollup can process them.
The @rollup/plugin-commonjs plugin does exactly that.
Note that most of the times @rollup/plugin-commonjs
should go before other plugins that transform your modules — this is to prevent other plugins from making changes that break the CommonJS detection. An exception for this rule is the Babel plugin, if you're using it then place it before the commonjs one.
Let's say that you're building a library that has a peer dependency, such as React or Lodash. If you set up externals as described above, your rollup will bundle all imports:
import answer from 'the-answer';
import _ from 'lodash';
You can finely tune which imports are bundled and which are treated as external. For this example, we'll treat lodash
as external, but not the-answer
.
Here is the config file:
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [
resolve({
// pass custom options to the resolve plugin
customResolveOptions: {
moduleDirectory: 'node_modules'
}
})
],
// indicate which modules should be treated as external
external: ['lodash']
};
Voilà, lodash
will now be treated as external, and not be bundled with your library.
The external
key accepts either an array of module names, or a function which takes the module name and returns true if it should be treated as external. For example:
export default {
// ...
external: id => /lodash/.test(id)
};
You might use this form if you're using babel-plugin-lodash to cherry-pick lodash
modules. In this case, Babel will convert your import statements to look like this:
import _merge from 'lodash/merge';
The array form of external
does not handle wildcards, so this import will only be treated as external in the functional form.
Many developers use Babel in their projects in order to use the latest JavaScript features that aren't yet supported by browsers and Node.js.
The easiest way to use both Babel and Rollup is with @rollup/plugin-babel. First, install the plugin:
npm i -D @rollup/plugin-babel @rollup/plugin-node-resolve
Add it to rollup.config.js
:
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [resolve(), babel({ babelHelpers: 'bundled' })]
};
Before Babel will actually compile your code, it needs to be configured. Create a new file, src/.babelrc.json
:
{
"presets": ["@babel/env"]
}
We're putting our .babelrc.json
file in src
, rather than the project root. This allows us to have a different .babelrc.json
for things like tests, if we need that later – See the Babel documentation for more information on both project wide and file relative configuration.
Now, before we run rollup, we need to install babel-core
and the env
preset:
npm i -D @babel/core @babel/preset-env
Running Rollup now will create a bundle - except we're not actually using any ES2015 features. Let's change that by editing src/main.js
:
// src/main.js
import answer from 'the-answer';
export default () => {
console.log(`the answer is ${answer}`);
};
Run Rollup with npm run build
, and check the bundle:
'use strict';
var index = 42;
var main = function () {
console.log('the answer is ' + index);
};
module.exports = main;
Rollup returns Promises which are understood by gulp so integration is relatively painless.
The syntax is very similar to the configuration file, but the properties are split across two different operations corresponding to the JavaScript API:
const gulp = require('gulp');
const rollup = require('rollup');
const rollupTypescript = require('@rollup/plugin-typescript');
gulp.task('build', () => {
return rollup
.rollup({
input: './src/main.ts',
plugins: [rollupTypescript()]
})
.then(bundle => {
return bundle.write({
file: './dist/library.js',
format: 'umd',
name: 'library',
sourcemap: true
});
});
});
You may also use the async/await
syntax:
const gulp = require('gulp');
const rollup = require('rollup');
const rollupTypescript = require('@rollup/plugin-typescript');
gulp.task('build', async function () {
const bundle = await rollup.rollup({
input: './src/main.ts',
plugins: [rollupTypescript()]
});
await bundle.write({
file: './dist/library.js',
format: 'umd',
name: 'library',
sourcemap: true
});
});
eval
If you get stuck, please try discussing the issue on the Rollup Discord or posting a question to Stackoverflow. If you've found a bug, or Rollup can't meet your needs, please try raising an issue. Lastly, you may try contacting @RollupJS on Twitter.
eval
You probably already know that 'eval
is evil', at least according to some people. But it's particularly harmful with Rollup, because of how it works – unlike other module bundlers, which wrap each module in a function, Rollup puts all your code in the same scope.
That's more efficient, but it means that the shared scope is 'polluted' whenever you use eval
, whereas with a different bundler, modules that didn't use eval would not be polluted. A minifier can't mangle variable names in polluted code, because it can't guarantee that the code to be evaluated doesn't reference those variable names.
Furthermore, it poses a security risk in that a malicious module could access another module's private variables with eval('SUPER_SEKRIT')
.
Luckily, unless you really do intend for the evaluated code to have access to local variables (in which case you're probably doing something wrong!), you can achieve the same effect in one of two ways:
Simply 'copying' eval
provides you with a function that does exactly the same thing, but which runs in the global scope rather than the local one:
var eval2 = eval;
(function () {
var foo = 42;
eval('console.log("with eval:",foo)'); // logs 'with eval: 42'
eval2('console.log("with eval2:",foo)'); // throws ReferenceError
})();
new Function
Using the Function constructor generates a function from the supplied string. Again, it runs in the global scope. If you need to call the function repeatedly, this is much, much faster than using eval
.
Sometimes, you'll end up with code in your bundle that doesn't seem like it should be there. For example, if you import a utility from lodash-es
, you might expect that you'll get the bare minimum of code necessary for that utility to work.
But Rollup has to be conservative about what code it removes in order to guarantee that the end result will run correctly. If an imported module appears to have side-effects, either on bits of the module that you're using or on the global environment, Rollup plays it safe and includes those side-effects.
Because static analysis in a dynamic language like JavaScript is hard, there will occasionally be false positives. Lodash is a good example of a module that looks like it has lots of side-effects, even in places that it doesn't. You can often mitigate those false positives by importing submodules (e.g. import map from 'lodash-es/map'
rather than import { map } from 'lodash-es'
).
Rollup's static analysis will improve over time, but it will never be perfect in all cases – that's just JavaScript.
Occasionally you will see an error message like this:
'foo' is not exported by bar.js (imported by baz.js)
Import declarations must have corresponding export declarations in the imported module. For example, if you have import a from './a.js'
in a module, and a.js doesn't have an export default
declaration, or import {foo} from './b.js'
, and b.js doesn't export foo
, Rollup cannot bundle the code.
This error frequently occurs with CommonJS modules converted by @rollup/plugin-commonjs, which makes a reasonable attempt to generate named exports from the CommonJS code but won't always succeed, because the freewheeling nature of CommonJS is at odds with the rigorous approach we benefit from in JavaScript modules. It can be solved by using the namedExports option, which allows you to manually fill in the information gaps.
In a JavaScript module, this
is undefined
at the top level (i.e., outside functions). Because of that, Rollup will rewrite any this
references to undefined
so that the resulting behaviour matches what will happen when modules are natively supported.
There are occasional valid reasons for this
to mean something else. If you're getting errors in your bundle, you can use options.context
and options.moduleContext
to change this behaviour.
You'll see this warning if you generate a sourcemap with your bundle (sourcemap: true
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.
Rollup will only resolve relative module IDs by default. This means that an import statement like this…
import moment from 'moment';
…won't result in moment
being included in your bundle – instead, it will be an external dependency that is required at runtime. If that's what you want, you can suppress this warning with the external
option, which makes your intentions explicit:
// rollup.config.js
export default {
entry: 'src/index.js',
dest: 'bundle.js',
format: 'cjs',
external: ['moment'] // <-- suppresses the warning
};
If you do want to include the module in your bundle, you need to tell Rollup how to find it. In most cases, this is a question of using @rollup/plugin-node-resolve.
Some modules, like events
or util
, are built in to Node.js. If you want to include those (for example, so that your bundle runs in the browser), you may need to include rollup-plugin-polyfill-node.
For large projects, you may run into an EMFILE error when running Rollup in watch mode on macOS. If you experience this, disabling FSEvents may eliminate the problem:
// rollup.config.js
export default {
...,
watch: {
chokidar: {
useFsEvents: false
}
}
};
Type: (string | RegExp)[] | RegExp | string | (id: string, parentId: string, isResolved: boolean) => boolean
CLI: -e
/--external <external-id,another-external-id,...>
Either a function that takes an id
and returns true
(external) or false
(not external), or an Array
of module IDs, or regular expressions to match module IDs, that should remain external to the bundle. Can also be just a single ID or regular expression. The matched IDs should be either:
import "dependency.js"
as external, use "dependency.js"
while to mark import "dependency"
as external, use "dependency"
.// rollup.config.js
import path from 'path';
export default {
...,
external: [
'some-externally-required-library',
path.resolve( __dirname, 'src/some-local-file-that-should-not-be-bundled.js' ),
/node_modules/
]
};
Note that if you want to filter out package imports, e.g. import {rollup} from 'rollup'
, via a /node_modules/
regular expression, you need something like @rollup/plugin-node-resolve to resolve the imports to node_modules
first.
When given as a command line argument, it should be a comma-separated list of IDs:
rollup -i src/main.js ... -e foo,bar,baz
When providing a function, it is called with three parameters (id, parent, isResolved)
that can give you more fine-grained control:
id
is the id of the module in questionparent
is the id of the module doing the importisResolved
signals whether the id
has been resolved by e.g. pluginsWhen creating an iife
or umd
bundle, you will need to provide global variable names to replace your external imports via the output.globals
option.
If a relative import, i.e. starting with ./
or ../
, is marked as "external", rollup will internally resolve the id to an absolute file system location so that different imports of the external module can be merged. When the resulting bundle is written, the import will again be converted to a relative import. Example:
// input
// src/main.js (entry point)
import x from '../external.js';
import './nested/nested.js';
console.log(x);
// src/nested/nested.js
// the import would point to the same file if it existed
import x from '../../external.js';
console.log(x);
// output
// the different imports are merged
import x from '../external.js';
console.log(x);
console.log(x);
The conversion back to a relative import is done as if output.file
or output.dir
were in the same location as the entry point or the common base directory of all entry points if there is more than one.
Type: string | string [] | { [entryName: string]: string }
CLI: -i
/--input <filename>
The bundle's entry point(s) (e.g. your main.js
or app.js
or index.js
). If you provide an array of entry points or an object mapping names to entry points, they will be bundled to separate output chunks. Unless the output.file
option is used, generated chunk names will follow the output.entryFileNames
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. The following will generate at least two entry chunks with the names entry-a.js
and entry-b/index.js
, i.e. the file index.js
is placed in the folder entry-b
:
// rollup.config.js
export default {
...,
input: {
a: 'src/main-a.js',
'b/index': 'src/main-b.js'
},
output: {
...,
entryFileNames: 'entry-[name].js'
}
};
The option can be omitted if some plugin emits at least one chunk (using this.emitFile
) by the end of the buildStart
hook.
When using the command line interface, multiple inputs can be provided by using the option multiple times. When provided as the first options, it is equivalent to not prefix them with --input
:
rollup --format es --input src/entry1.js --input src/entry2.js
# is equivalent to
rollup src/entry1.js src/entry2.js --format es
Chunks can be named by adding an =
to the provided value:
rollup main=src/entry1.js other=src/entry2.js --format es
File names containing spaces can be specified by using quotes:
rollup "main entry"="src/entry 1.js" "src/other entry.js" --format es
Type: string
CLI: -d
/--dir <dirname>
The directory in which all generated chunks are placed. This option is required if more than one chunk is generated. Otherwise, the file
option can be used instead.
Type: string
CLI: -o
/--file <filename>
The file to write to. Will also be used to generate sourcemaps, if applicable. Can only be used if not more than one chunk is generated.
Type: string
CLI: -f
/--format <formatspecifier>
Default: "es"
Specifies the format of the generated bundle. One of the following:
amd
– Asynchronous Module Definition, used with module loaders like RequireJScjs
– CommonJS, suitable for Node and other bundlers (alias: commonjs
)es
– Keep the bundle as an ES module file, suitable for other bundlers and inclusion as a <script type=module>
tag in modern browsers (alias: esm
, module
)iife
– A self-executing function, suitable for inclusion as a <script>
tag. (If you want to create a bundle for your application, you probably want to use this.). "iife" stands for "immediately-invoked Function Expression"umd
– Universal Module Definition, works as amd
, cjs
and iife
all in onesystem
– Native format of the SystemJS loader (alias: systemjs
)Type: { [id: string]: string } | ((id: string) => string)
CLI: -g
/--globals <external-id:variableName,another-external-id:anotherVariableName,...>
Specifies id: variableName
pairs necessary for external imports in umd
/iife
bundles. For example, in a case like this…
import $ from 'jquery';
…we want to tell Rollup that jquery
is external and the jquery
module ID equates to the global $
variable:
// rollup.config.js
export default {
...,
external: ['jquery'],
output: {
format: 'iife',
name: 'MyBundle',
globals: {
jquery: '$'
}
}
};
/*
var MyBundle = (function ($) {
// code goes here
}($));
*/
Alternatively, supply a function that will turn an external module ID into a global variable name.
When given as a command line argument, it should be a comma-separated list of id:variableName
pairs:
rollup -i src/main.js ... -g jquery:$,underscore:_
To tell Rollup that a local file should be replaced by a global variable, use an absolute id:
// rollup.config.js
import path from 'path';
const externalId = path.resolve( __dirname, 'src/some-local-file-that-should-not-be-bundled.js' );
export default {
...,
external: [externalId],
output: {
format: 'iife',
name: 'MyBundle',
globals: {
[externalId]: 'globalVariable'
}
}
};
Type: string
CLI: -n
/--name <variableName>
Necessary for iife
/umd
bundles that exports values in which case it is the global variable name representing your bundle. Other scripts on the same page can use this variable name to access the exports of your bundle.
// rollup.config.js
export default {
...,
output: {
file: 'bundle.js',
format: 'iife',
name: 'MyBundle'
}
};
// var MyBundle = (function () {...
Namespaces are supported i.e. your name can contain dots. The resulting bundle will contain the setup necessary for the namespacing.
rollup -n "a.b.c"
/* ->
this.a = this.a || {};
this.a.b = this.a.b || {};
this.a.b.c = ...
*/
Type: OutputPlugin | (OutputPlugin | void)[]
Adds a plugin just to this output. See Using output plugins for more information on how to use output-specific plugins and Plugins on how to write your own. For plugins imported from packages, remember to call the imported plugin function (i.e. commonjs()
, not just commonjs
). Falsy plugins will be ignored, which can be used to easily activate or deactivate plugins.
Not every plugin can be used here. output.plugins
is limited to plugins that only use hooks that run during bundle.generate()
or bundle.write()
, i.e. after Rollup's main analysis is complete. If you are a plugin author, see output generation hooks to find out which hooks can be used.
The following will add minification to one of the outputs:
// rollup.config.js
import { terser } from 'rollup-plugin-terser';
export default {
input: 'main.js',
output: [
{
file: 'bundle.js',
format: 'es'
},
{
file: 'bundle.min.js',
format: 'es',
plugins: [terser()]
}
]
};
Type: Plugin | (Plugin | void)[]
See Using plugins for more information on how to use plugins and Plugins on how to write your own (try it out, it's not as difficult as it may sound and very much extends what you can do with Rollup). For plugins imported from packages, remember to call the imported plugin function (i.e. commonjs()
, not just commonjs
). Falsy plugins will be ignored, which can be used to easily activate or deactivate plugins.
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
const isProduction = process.env.NODE_ENV === 'production';
export default (async () => ({
input: 'main.js',
plugins: [resolve(), commonjs(), isProduction && (await import('rollup-plugin-terser')).terser()],
output: {
file: 'bundle.js',
format: 'cjs'
}
}))();
(This example also demonstrates how to use an async IIFE and dynamic imports to avoid unnecessary module loading, which can be surprisingly slow.)
Type: RollupCache | false
The cache
property of a previous bundle. Use it to speed up subsequent builds in watch mode — Rollup will only reanalyse the modules that have changed. Setting this option explicitly to false
will prevent generating the cache
property on the bundle and also deactivate caching for plugins.
const rollup = require('rollup');
let cache;
async function buildWithCache() {
const bundle = await rollup.rollup({
cache // is ignored if falsy
// ... other input options
});
cache = bundle.cache; // store the cache object of the previous build
return bundle;
}
buildWithCache()
.then(bundle => {
// ... do something with the bundle
})
.then(() => buildWithCache()) // will use the cache of the previous build
.then(bundle => {
// ... do something with the bundle
});
Type: boolean | "ifRelativeSource"
CLI: --makeAbsoluteExternalsRelative
/--no-makeAbsoluteExternalsRelative
Default: true
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 Rollup core.
For true
, an external import like import "/Users/Rollup/project/relative.js"
would be converted to a relative path. When converting an absolute path to a relative path, Rollup does not take the file
or 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 modules that were included in the bundle. Assuming that the common parent directory of all modules is "/Users/Rollup/project"
, the import from above would likely be converted to import "./relative.js"
in the output. If the output chunk is itself nested in a sub-directory by choosing e.g. chunkFileNames: "chunks/[name].js"
, the import would be "../relative.js"
.
As stated before, this would also apply to originally relative imports like import "./relative.js"
that are resolved to an absolute path before they are marked as external by the external
option.
One common problem is that this mechanism will also apply to imports like import "/absolute.js'"
, resulting in unexpected relative paths in the output.
For this case, choosing "ifRelativeSource"
will check if the original import was a relative import and only then convert it to a relative import in the output. Choosing false
will keep all paths as absolute paths in the output.
Note that when a relative path is directly marked as "external" using the external
option, then it will be the same relative path in the output. When it is resolved first via a plugin or Rollup core and then marked as external, the above logic will apply.
Type: number
CLI: --maxParallelFileReads <number>
Default: 20
Limits the number of files rollup will open in parallel when reading modules. Without a limit or with a high enough value, builds can fail with an "EMFILE: too many open files". This dependes on how many open file handles the os allows.
Type: (warning: RollupWarning, defaultHandler: (warning: string | RollupWarning) => void) => void;
A function that will intercept warning messages. If not supplied, warnings will be deduplicated and printed to the console. When using the --silent
CLI option, this handler is the only way to get notified about warnings.
The function receives two arguments: the warning object and the default handler. Warnings objects have, at a minimum, a code
and a message
property, allowing you to control how different kinds of warnings are handled. Other properties are added depending on the type of warning.
// rollup.config.js
export default {
...,
onwarn (warning, warn) {
// skip certain warnings
if (warning.code === 'UNUSED_EXTERNAL_IMPORT') return;
// throw on others
if (warning.code === 'NON_EXISTENT_EXPORT') throw new Error(warning.message);
// Use default for everything else
warn(warning);
}
};
Many warnings also have a loc
property and a frame
allowing you to locate the source of the warning:
// rollup.config.js
export default {
...,
onwarn ({ loc, frame, message }) {
if (loc) {
console.warn(`${loc.file} (${loc.line}:${loc.column}) ${message}`);
if (frame) console.warn(frame);
} else {
console.warn(message);
}
}
};
Type: string | ((assetInfo: AssetInfo) => string)
CLI: --assetFileNames <pattern>
Default: "assets/[name]-[hash][extname]"
The pattern to use for naming custom emitted assets to include in the build output, or a function that is called per asset 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 name and content of the asset.[name]
: The file name of the asset excluding any extension.Forward slashes /
can be used to place files in sub-directories. When using a function, assetInfo
is a reduced version of the one in generateBundle
without the fileName
. See also output.chunkFileNames
, output.entryFileNames
.
Type: string | (() => string | Promise<string>)
CLI: --banner
/--footer <text>
A string to prepend/append to the bundle. You can also supply a function that returns a Promise
that resolves to a string
to generate it asynchronously (Note: banner
and footer
options will not break sourcemaps).
// rollup.config.js
export default {
...,
output: {
...,
banner: '/* my-library version ' + version + ' */',
footer: '/* follow me on Twitter! @rich_harris */'
}
};
See also output.intro/output.outro
.
Type: string | ((chunkInfo: ChunkInfo) => string)
CLI: --chunkFileNames <pattern>
Default: "[name]-[hash].js"
The pattern to use for naming shared chunks created when code-splitting, or a function that is called per chunk to return such a pattern. Patterns support the following placeholders:
[format]
: The rendering format defined in the output options, e.g. es
or cjs
.[hash]
: A hash based on the content of the chunk and the content of all its dependencies.[name]
: The name of the chunk. This can be explicitly set via the output.manualChunks
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. When using a function, chunkInfo
is a reduced version of the one in generateBundle
without properties that depend on file names. See also output.assetFileNames
, output.entryFileNames
.
Type: boolean
CLI: --compact
/--no-compact
Default: false
This will minify the wrapper code generated by rollup. Note that this does not affect code written by the user. This option is useful when bundling pre-minified code.
Type: string | ((chunkInfo: ChunkInfo) => string)
CLI: --entryFileNames <pattern>
Default: "[name].js"
The pattern to use for chunks created from entry points, or a function that is called per entry chunk to return such a pattern. Patterns support the following placeholders:
[format]
: The rendering format defined in the output options, e.g. es
or cjs
.[hash]
: A hash based on the content of the entry point and the content of all its dependencies.[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. When using a function, chunkInfo
is a reduced version of the one in generateBundle
without properties that depend on file names. See also output.assetFileNames
, output.chunkFileNames
.
This pattern will also be used when setting the output.preserveModules
option. Here a different set of placeholders is available, though:
[format]
: The rendering format defined in the output options.[name]
: The file name (without extension) of the file.[ext]
: The extension of the file.[extname]
: The extension of the file, prefixed by .
if it is not empty.[assetExtname]
: The extension of the file, prefixed by .
if it is not empty and it is not one of js
, jsx
, ts
or tsx
.Type: boolean
CLI: --extend
/--no-extend
Default: false
Whether to extend the global variable defined by the name
option in umd
or iife
formats. 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 = {})
.
Type: boolean
CLI: --hoistTransitiveImports
/--no-hoistTransitiveImports
Default: true
By default when creating multiple chunks, transitive imports of entry chunks will be added as empty imports to the entry chunks. See "Why do additional imports turn up in my entry chunks when code-splitting?" for details and background. Setting this option to false
will disable this behaviour. This option is ignored when using the output.preserveModules
option as here, imports will never be hoisted.
Type: boolean
CLI: --inlineDynamicImports
/--no-inlineDynamicImports
Default: false
This will inline dynamic imports instead of creating new chunks to create a single bundle. Only possible if a single input is provided. Note that this will change the execution order: A module that is only imported dynamically will be executed immediately if the dynamic import is inlined.
Type: "auto" | "esModule" | "default" | "defaultOnly" | boolean | ((id: string) => "auto" | "esModule" | "default" | "defaultOnly" | boolean)
CLI: --interop <value>
Default: true
Controls how Rollup handles default, namespace and dynamic imports from external dependencies in formats like CommonJS that do not natively support these concepts. Note that even though true
is the current default value, this value is deprecated and will be replaced by "auto"
in the next major version of Rollup. In the examples, we will be using the CommonJS format, but the interop similarly applies to AMD, IIFE and UMD targets as well.
To understand the different values, assume we are bundling the following code for a cjs
target:
import ext_default, * as external from 'external1';
console.log(ext_default, external.bar, external);
import('external2').then(console.log);
Keep in mind that for Rollup, import * as ext_namespace from 'external'; console.log(ext_namespace.bar);
is completely equivalent to import {bar} from 'external'; console.log(bar);
and will produce the same code. In the example above however, the namespace object itself is passed to a global function as well, which means we need it as a properly formed object.
"esModule"
assumes that required modules are transpiled ES modules where the required value corresponds to the module namespace, and the default export is the .default
property of the exported object:
var external = require('external1');
console.log(external['default'], external.bar, external);
Promise.resolve()
.then(function () {
return require('external2');
})
.then(console.log);
When esModule
is used, Rollup adds no additional interop helpers and also supports live-bindings for default exports.
"default"
assumes that the required value should be treated as the default export of the imported module, just like when importing CommonJS from an ES module context in Node. In contrast to Node, though, named imports are supported as well which are treated as properties of the default import. To create the namespace object, Rollup injects helpers:
var external = require('external1');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(
n,
k,
d.get
? d
: {
enumerable: true,
get: function () {
return e[k];
}
}
);
}
});
}
n['default'] = e;
return Object.freeze(n);
}
var external__namespace = /*#__PURE__*/ _interopNamespaceDefault(external);
console.log(external, external.bar, external__namespace);
Promise.resolve()
.then(function () {
return /*#__PURE__*/ _interopNamespaceDefault(require('external2'));
})
.then(console.log);
"auto"
combines both "esModule"
and "default"
by injecting helpers that contain code that detects at runtime if the required value contains the __esModule
property. Adding this property is a standard implemented by Rollup, Babel and many other tools to signify that the required value is the namespace of a transpiled ES module:
var external = require('external1');
function _interopNamespace(e) {
if (e && e.__esModule) {
return e;
} else {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(
n,
k,
d.get
? d
: {
enumerable: true,
get: function () {
return e[k];
}
}
);
}
});
}
n['default'] = e;
return Object.freeze(n);
}
}
var external__namespace = /*#__PURE__*/ _interopNamespace(external);
console.log(external__namespace['default'], external.bar, external__namespace);
Promise.resolve()
.then(function () {
return /*#__PURE__*/ _interopNamespace(require('external2'));
})
.then(console.log);
Note how Rollup is reusing the created namespace object to get the default
export. If the namespace object is not needed, Rollup will use a simpler helper:
// input
import ext_default from 'external';
console.log(ext_default);
// output
var ext_default = require('external');
function _interopDefault(e) {
return e && e.__esModule ? e : { default: e };
}
var ext_default__default = /*#__PURE__*/ _interopDefault(ext_default);
console.log(ext_default__default['default']);
"defaultOnly"
is similar to "default"
except for the following:
es
and system
formats. That way it is ensures that the es
version of the code is able to import non-builtin CommonJS modules in Node correctly.export * from 'external';
are not prohibited, they are ignored and will cause Rollup to display a warning because they would not have an effect if there are no named exports.Here is what Rollup will create from the example code. Note that we removed external.bar
from the code as otherwise, Rollup would have thrown an error because, as stated before, this is equivalent to a named import.
var ext_default = require('external1');
function _interopNamespaceDefaultOnly(e) {
return Object.freeze({ __proto__: null, default: e });
}
var ext_default__namespace = /*#__PURE__*/ _interopNamespaceDefaultOnly(ext_default);
console.log(ext_default, ext_default__namespace);
Promise.resolve()
.then(function () {
return /*#__PURE__*/ _interopNamespaceDefaultOnly(require('external2'));
})
.then(console.log);
When a function is supplied, Rollup will pass each external id to this function once to control the interop type per dependency.
As an example if all dependencies are CommonJs, the following config will ensure that named imports are only permitted from Node builtins:
// rollup.config.js
import builtins from 'builtins';
const nodeBuiltins = new Set(builtins());
export default {
// ...
output: {
// ...
interop(id) {
if (nodeBuiltins.has(id)) {
return 'default';
}
return 'defaultOnly';
}
}
};
true
is equivalent to "auto"
except that it uses a slightly different helper for the default export that checks for the presence of a default
property instead of the __esModule
property.
☢️ This value is deprecated and will be removed in a future Rollup version.
false
is equivalent to using default
when importing a default export and esModule
when importing a namespace.
☢️ This value is deprecated and will be removed in a future Rollup version.
There are some additional options that have an effect on the generated interop code:
output.externalLiveBindings
to false
will generate simplified namespace helpers as well as simplified code for extracted default imports.output.freeze
to false
will prevent generated interop namespace objects from being frozen.Type: string | (() => string | Promise<string>)
CLI: --intro
/--outro <text>
Similar to output.banner/output.footer
, except that the code goes inside any format-specific wrapper.
export default {
...,
output: {
...,
intro: 'const ENVIRONMENT = "production";'
}
};
Type: { [chunkAlias: string]: string[] } | ((id: string, {getModuleInfo, getModuleIds}) => string | void)
Allows the creation of custom shared common chunks. When using the object form, each property represents a chunk that contains the listed modules and all their dependencies if they are part of the module graph unless they are already in another manual chunk. The name of the chunk will be determined by the property key.
Note that it is not necessary for the listed modules themselves to be part of the module graph, which is useful if you are working with @rollup/plugin-node-resolve
and use deep imports from packages. For instance
manualChunks: {
lodash: ['lodash']
}
will put all lodash modules into a manual chunk even if you are only using imports of the form import get from 'lodash/get'
.
When using the function form, each resolved module id will be passed to the function. If a string is returned, the module and all its dependency will be added to the manual chunk with the given name. For instance this will create a vendor
chunk containing all dependencies inside node_modules
:
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor';
}
}
Be aware that manual chunks can change the behaviour of the application if side effects are triggered before the corresponding modules are actually used.
When using the function form, manualChunks
will be passed an object as second parameter containing the functions getModuleInfo
and getModuleIds
that work the same way as this.getModuleInfo
and this.getModuleIds
on the plugin context.
This can be used to dynamically determine into which manual chunk a module should be placed depending on its position in the module graph. For instance consider a scenario where you have a set of components, each of which dynamically imports a set of translated strings, i.e.
// Inside the "foo" component
function getTranslatedStrings(currentLanguage) {
switch (currentLanguage) {
case 'en':
return import('./foo.strings.en.js');
case 'de':
return import('./foo.strings.de.js');
// ...
}
}
If a lot of such components are used together, this will result in a lot of dynamic imports of very small chunks: Even though we known that all language files of the same language that are imported by the same chunk will always be used together, Rollup does not have this information.
The following code will merge all files of the same language that are only used by a single entry point:
manualChunks(id, { getModuleInfo }) {
const match = /.*\.strings\.(\w+)\.js/.exec(id);
if (match) {
const language = match[1]; // e.g. "en"
const dependentEntryPoints = [];
// we use a Set here so we handle each module at most once. This
// prevents infinite loops in case of circular dependencies
const idsToHandle = new Set(getModuleInfo(id).dynamicImporters);
for (const moduleId of idsToHandle) {
const { isEntry, dynamicImporters, importers } = getModuleInfo(moduleId);
if (isEntry || dynamicImporters.length > 0) dependentEntryPoints.push(moduleId);
// The Set iterator is intelligent enough to iterate over elements that
// are added during iteration
for (const importerId of importers) idsToHandle.add(importerId);
}
// If there is a unique entry, we put it into into a chunk based on the entry name
if (dependentEntryPoints.length === 1) {
return `${dependentEntryPoints[0].split('/').slice(-1)[0].split('.')[0]}.strings.${language}`;
}
// For multiple entries, we put it into a "shared" chunk
if (dependentEntryPoints.length > 1) {
return `shared.strings.${language}`;
}
}
}
Type: boolean
CLI: --minifyInternalExports
/--no-minifyInternalExports
Default: true
for formats es
and system
or if output.compact
is true
, false
otherwise
By default for formats es
and system
or if output.compact
is true
, Rollup will try to export internal variables as single letter variables to allow for better minification.
Example
Input:
// main.js
import './lib.js';
// lib.js
import('./dynamic.js');
export const value = 42;
// dynamic.js
import { value } from './lib.js';
console.log(value);
Output with output.minifyInternalExports: true
:
// main.js
import './main-5532def0.js';
// main-5532def0.js
import('./dynamic-402de2f0.js');
const importantValue = 42;
export { importantValue as i };
// dynamic-402de2f0.js
import { i as importantValue } from './main-5532def0.js';
console.log(importantValue);
Output with output.minifyInternalExports: false
:
// main.js
import './main-5532def0.js';
// main-5532def0.js
import('./dynamic-402de2f0.js');
const importantValue = 42;
export { importantValue };
// dynamic-402de2f0.js
import { importantValue } from './main-5532def0.js';
console.log(importantValue);
Even though it appears that setting this option to true
makes the output larger, it actually makes it smaller if a minifier is used. In this case, export { importantValue as i }
can become e.g. export{a as i}
or even export{i}
, while otherwise it would produce export{ a as importantValue }
because a minifier usually will not change export signatures.
Type: { [id: string]: string } | ((id: string) => string)
Maps external module IDs to paths. External ids are ids that cannot be resolved or ids explicitly provided by the external
option. Paths supplied by output.paths
will be used in the generated bundle instead of the module ID, allowing you to, for example, load dependencies from a CDN:
// app.js
import { selectAll } from 'd3';
selectAll('p').style('color', 'purple');
// ...
// rollup.config.js
export default {
input: 'app.js',
external: ['d3'],
output: {
file: 'bundle.js',
format: 'amd',
paths: {
d3: 'https://d3js.org/d3.v4.min'
}
}
};
// bundle.js
define(['https://d3js.org/d3.v4.min'], function (d3) {
d3.selectAll('p').style('color', 'purple');
// ...
});
Type: boolean
CLI: --preserveModules
/--no-preserveModules
Default: false
Instead of creating as few chunks as possible, this mode will create separate chunks for all modules using the original module names as file names. Requires the output.dir
option. Tree-shaking will still be applied, suppressing files that are not used by the provided entry points or do not have side effects when executed. This mode can be used to transform a file structure to a different module format.
Note that when transforming to cjs
or amd
format, each file will by default be treated as an entry point with output.exports
set to auto
. This means that e.g. for cjs
, a file that only contains a default export will be rendered as
// input main.js
export default 42;
// output main.js
('use strict');
var main = 42;
module.exports = main;
assigning the value directly to module.exports
. If someone imports this file, they will get access to the default export via
const main = require('./main.js');
console.log(main); // 42
As with regular entry points, files that mix default and named exports will produce warnings. You can avoid the warnings by forcing all files to use named export mode via output.exports: "named"
. In that case, the default export needs to be accessed via the .default
property of the export:
// input main.js
export default 42;
// output main.js
('use strict');
Object.defineProperty(exports, '__esModule', { value: true });
var main = 42;
exports.default = main;
// consuming file
const main = require('./main.js');
console.log(main.default); // 42
Type: string
CLI: --preserveModulesRoot <directory-name>
A directory path to input modules that should be stripped away from output.dir
path while output.preserveModules
is true
.
For example, given the following configuration:
export default {
input: ['src/module.js', `src/another/module.js`],
output: [
{
format: 'es',
dir: 'dist',
preserveModules: true,
preserveModulesRoot: 'src'
}
]
};
The preserveModulesRoot
setting ensures that the input modules will be output to the paths dist/module.js
and dist/another/module.js
.
This option is particularly useful while using plugins such as @rollup/plugin-node-resolve
, which may cause changes in the output directory structure. This can happen when third-party modules are not marked external
, or while developing in a monorepo of multiple packages that rely on one another and are not marked external
.
Type: boolean | 'inline' | 'hidden'
CLI: -m
/--sourcemap
/--no-sourcemap
Default: false
If true
, a separate sourcemap file will be created. If "inline"
, the sourcemap will be appended to the resulting output
file as a data URI. "hidden"
works like true
except that the corresponding sourcemap comments in the bundled files are suppressed.
Type: boolean
CLI: --sourcemapExcludeSources
/--no-sourcemapExcludeSources
Default: false
If true
, the actual code of the sources will not be added to the sourcemaps making them considerably smaller.
Type: string
CLI: --sourcemapFile <file-name-with-path>
The location of the generated bundle. If this is an absolute path, all the sources
paths in the sourcemap will be relative to it. The map.file
property is the basename of sourcemapFile
, as the location of the sourcemap is assumed to be adjacent to the bundle.
sourcemapFile
is not required if output
is specified, in which case an output filename will be inferred by adding ".map" to the output filename for the bundle.
Type: (relativeSourcePath: string, sourcemapPath: string) => string
A transformation to apply to each path in a sourcemap. relativeSourcePath
is a relative path from the generated .map
file to the corresponding source file while sourcemapPath
is the fully resolved path of the generated sourcemap file.
import path from 'path';
export default {
input: 'src/main',
output: [
{
file: 'bundle.js',
sourcemapPathTransform: (relativeSourcePath, sourcemapPath) => {
// will replace relative paths with absolute paths
return path.resolve(path.dirname(sourcemapPath), relativeSourcePath);
},
format: 'es',
sourcemap: true
}
]
};
Type: boolean
CLI: --validate
/--no-validate
Default: false
Re-parses each generated chunk to detect if the generated code is valid JavaScript. This can be useful to debug output generated by plugins that use the renderChunk
hook to transform code.
If the code is invalid, a warning will be issued. Note that no error is thrown so that you can still inspect the generated output. To promote this warning to an error, you can watch for it in an onwarn
handler.
Type: "strict" | "allow-extension" | "exports-only" | false
CLI: --preserveEntrySignatures <strict|allow-extension>
/--no-preserveEntrySignatures
Default: "strict"
Controls if Rollup tries to ensure that entry chunks have the same exports as the underlying entry module.
"strict"
, Rollup will create exactly the same exports in the entry chunk as there are in the corresponding entry module. If this is not possible because additional internal exports need to be added to a chunk, Rollup will instead create a "facade" entry chunk that reexports just the necessary bindings from other chunks but contains no code otherwise. This is the recommended setting for libraries."allow-extension"
will create all exports of the entry module in the entry chunk but may also add additional exports if necessary, avoiding a "facade" entry chunk. This setting makes sense for libraries where a strict signature is not required."exports-only"
behaves like "strict"
if the entry module has exports, otherwise it behaves like "allow-extension"
.false
will not add any exports of an entry module to the corresponding chunk and does not even include the corresponding code unless those exports are used elsewhere in the bundle. Internal exports may be added to entry chunks, though. This is the recommended setting for web apps where the entry chunks are to be placed in script tags as it may reduce both the number of chunks and possibly the bundle size.Example
Input:
// main.js
import { shared } from './lib.js';
export const value = `value: ${shared}`;
import('./dynamic.js');
// lib.js
export const shared = 'shared';
// dynamic.js
import { shared } from './lib.js';
console.log(shared);
Output for preserveEntrySignatures: "strict"
:
// main.js
export { v as value } from './main-50a71bb6.js';
// main-50a71bb6.js
const shared = 'shared';
const value = `value: ${shared}`;
import('./dynamic-cd23645f.js');
export { shared as s, value as v };
// dynamic-cd23645f.js
import { s as shared } from './main-50a71bb6.js';
console.log(shared);
Output for preserveEntrySignatures: "allow-extension"
:
// main.js
const shared = 'shared';
const value = `value: ${shared}`;
import('./dynamic-298476ec.js');
export { shared as s, value };
// dynamic-298476ec.js
import { s as shared } from './main.js';
console.log(shared);
Output for preserveEntrySignatures: false
:
// main.js
import('./dynamic-39821cef.js');
// dynamic-39821cef.js
const shared = 'shared';
console.log(shared);
At the moment, the only way to override this setting for individual entry chunks is to use the plugin API and emit those chunks via this.emitFile
instead of using the input
option.
Type: boolean
CLI: --strictDeprecations
/--no-strictDeprecations
Default: false
When this flag is enabled, Rollup will throw an error instead of showing a warning when a deprecated feature is used. Furthermore, features that are marked to receive a deprecation warning with the next major version will also throw an error when used.
This flag is intended to be used by e.g. plugin authors to be able to adjust their plugins for upcoming major releases as early as possible.
You probably don't need to use these options unless you know what you are doing!
Type: AcornOptions
Any options that should be passed through to Acorn's parse
function, such as allowReserved: true
. Cf. the Acorn documentation for more available options.
Type: AcornPluginFunction | AcornPluginFunction[]
A single plugin or an array of plugins to be injected into Acorn. For instance to use JSX syntax, you can specify
import jsx from 'acorn-jsx';
export default {
// … other options …
acornInjectPlugins: [jsx()]
};
in your rollup configuration. Note that this is different from using Babel in that the generated output will still contain JSX while Babel will replace it with valid JavaScript.
Type: string
CLI: --context <contextVariable>
Default: undefined
By default, the context of a module – i.e., the value of this
at the top level – is undefined
. In rare cases you might need to change this to something else, like 'window'
.
Type: ((id: string) => string) | { [id: string]: string }
Same as context
, but per-module – can either be an object of id: context
pairs, or an id => context
function.
Type: { id?: string, autoId?: boolean, basePath?: string, define?: string }
Note id
can only be used for single-file builds, and cannot be combined with autoId
/basePath
.
output.amd.id
Type: string
CLI: --amd.id <amdId>
An ID to use for AMD/UMD bundles:
// rollup.config.js
export default {
...,
format: 'amd',
amd: {
id: 'my-bundle'
}
};
// -> define('my-bundle', ['dependency'], ...
output.amd.autoId
Type: boolean
CLI: --amd.autoId
Set the ID to the chunk ID (with the '.js' extension removed).
// rollup.config.js
export default {
...,
format: 'amd',
amd: {
autoId: true
}
};
// -> define('main', ['dependency'], ...
// -> define('dynamic-chunk', ['dependency'], ...
output.amd.basePath
Type: string
CLI: --amd.basePath
The path that will be prepended to the auto generated ID. This is useful if the build is going to be placed inside another AMD project, and is not at the root.
Only valid with output.amd.autoId
.
// rollup.config.js
export default {
...,
format: 'amd',
amd: {
autoId: true
basePath: 'some/where'
}
};
// -> define('some/where/main', ['dependency'], ...
// -> define('some/where/dynamic-chunk', ['dependency'], ...
output.amd.define
Type: string
CLI: --amd.define <defineFunctionName>
A function name to use instead of define
:
// rollup.config.js
export default {
...,
format: 'amd',
amd: {
define: 'def'
}
};
// -> def(['dependency'],...
Type: boolean
CLI: --esModule
/--no-esModule
Default: true
Whether to add a __esModule: true
property when generating exports for non-ES formats. 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. By default, Rollup adds this property when using named exports mode for a chunk. See also output.interop
.
Type: string
CLI: --exports <exportMode>
Default: 'auto'
What export mode to use. Defaults to auto
, which guesses your intentions based on what the input
module exports:
default
– if you are only exporting one thing using export default ...
; note that this can cause issues when generating CommonJS output that is meant to be interchangeable with ESM output, see belownamed
– if you are using named exportsnone
– if you are not exporting anything (e.g. you are building an app, not a library)As this is only an output transformation, you can only choose default
if a default export is the only export for all entry chunks. Likewise, you can only choose none
if there are no exports, otherwise Rollup 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:
// 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:
// 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:
// 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');
Note: There are some tools such as Babel, TypeScript, Webpack, and @rollup/plugin-commonjs
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"
.
To alert you to this, Rollup will generate a warning when you encounter such a situation and did not select an explicit value for output.exports
.
Type: boolean
CLI: --externalLiveBindings
/--no-externalLiveBindings
Default: true
When set to false
, Rollup will not generate code to support live bindings for external imports but instead assume that exports do not change over time. This will enable Rollup to generate more optimized code. Note that this can cause issues when there are circular dependencies involving an external dependency.
This will avoid most cases where Rollup generates getters in the code and can therefore be used to make code IE8 compatible in many cases.
Example:
// input
export { x } from 'external';
// CJS output with externalLiveBindings: true
('use strict');
Object.defineProperty(exports, '__esModule', { value: true });
var external = require('external');
Object.defineProperty(exports, 'x', {
enumerable: true,
get: function () {
return external.x;
}
});
// CJS output with externalLiveBindings: false
('use strict');
Object.defineProperty(exports, '__esModule', { value: true });
var external = require('external');
exports.x = external.x;
Type: boolean
CLI: --freeze
/--no-freeze
Default: true
Whether to Object.freeze()
namespace import objects (i.e. import * as namespaceImportObject from...
) that are accessed dynamically.
Type: boolean | string
CLI: --indent
/--no-indent
Default: true
The indent string to use, for formats that require code to be indented (amd
, iife
, umd
, system
). Can also be false
(no indent), or true
(the default – auto-indent)
// rollup.config.js
export default {
...,
output: {
...,
indent: false
}
};
Type: boolean
CLI: --namespaceToStringTag
/--no-namespaceToStringTag
Default: false
Whether to add spec compliant .toString()
tags to namespace objects. If this option is set,
import * as namespace from './file.js';
console.log(String(namespace));
will always log [object Module]
;
Type: boolean
CLI: --noConflict
/--no-noConflict
Default: false
This will generate an additional noConflict
export to UMD bundles. When called in an IIFE scenario, this method will return the bundle exports while restoring the corresponding global variable to its previous value.
Type: boolean
CLI: --preferConst
/--no-preferConst
Default: false
Generate const
declarations for exports rather than var
declarations.
Type: boolean | (string) => string
CLI: --sanitizeFileName
/no-sanitizeFileName
Default: true
Set to false
to disable all chunk name sanitizations (removal of \0
, ?
and *
characters).
Alternatively set to a function to allow custom chunk name sanitization.
Type: boolean
CLI: --strict
/--no-strict
Default: true
Whether to include the 'use strict' pragma at the top of generated non-ES bundles. Strictly speaking, ES modules are always in strict mode, so you shouldn't disable this without good reason.
Type: boolean
CLI: --systemNullSetters
/--no-systemNullSetters
Default: false
When outputting the system
module format, this will replace empty setter functions with null
as an output simplification. This is only supported in SystemJS 6.3.3 and above.
Type: boolean
CLI: --preserveSymlinks
Default: false
When set to false
, symbolic links are followed when resolving a file. When set to true
, instead of being followed, symbolic links are treated as if the file is where the link is. To illustrate, consider the following situation:
// /main.js
import { x } from './linked.js';
console.log(x);
// /linked.js
// this is a symbolic link to /nested/file.js
// /nested/file.js
export { x } from './dep.js';
// /dep.js
export const x = 'next to linked';
// /nested/dep.js
export const x = 'next to original';
If preserveSymlinks
is false
, then the bundle created from /main.js
will log "next to original" as it will use the location of the symbolically linked file to resolve its dependencies. If preserveSymlinks
is true
, however, it will log "next to linked" as the symbolic link will not be resolved.
Type: boolean
CLI: --shimMissingExports
/--no-shimMissingExports
Default: false
If this option is provided, bundling will not fail if bindings are imported from a file that does not define these bindings. Instead, new variables will be created for these bindings with the value undefined
.
Type: boolean | "smallest" | "safest" | "recommended" | { annotations?: boolean, correctVarValueBeforeDeclaration?: boolean, moduleSideEffects?: ModuleSideEffectsOption, preset?: "smallest" | "safest" | "recommended", propertyReadSideEffects?: boolean | 'always', tryCatchDeoptimization?: boolean, unknownGlobalSideEffects?: boolean }
CLI: --treeshake
/--no-treeshake
Default: true
Whether to apply tree-shaking and to fine-tune the tree-shaking process. Setting this option to false
will produce bigger bundles but may improve build performance. You may also choose one of three presets that will automatically be updated if new options are added:
"smallest"
will choose option values for you to minimize output size as much as possible. This should work for most code bases as long as you do not rely on certain patterns, which are currently:treeshake.propertyReadSideEffects: false
)treeshake.moduleSideEffects: false
)treeshake.tryCatchDeoptimization: false
)treeshake.unknownGlobalSideEffects: false
, treeshake.correctVarValueBeforeDeclaration: false
)"recommended"
should work well for most usage patterns. Some semantic issues may be swallowed, though (treeshake.unknownGlobalSideEffects: false
, treeshake.correctVarValueBeforeDeclaration: false
)"safest"
tries to be as spec compliant as possible while still providing some basic tree-shaking capabilities.true
is equivalent to not specifying the option and will always choose the default value (see below).If you discover a bug caused by the tree-shaking algorithm, please file an issue! Setting this option to an object implies tree-shaking is enabled and grants the following additional options:
treeshake.annotations
Type: boolean
CLI: --treeshake.annotations
/--no-treeshake.annotations
Default: true
If false
, ignore hints from pure annotations, i.e. comments containing @__PURE__
or #__PURE__
, when determining side effects of function calls and constructor invocations. These annotations need to immediately precede the call invocation to take effect. The following code will be completely removed unless this option is set to false
, in which case it will remain unchanged.
/*@__PURE__*/ console.log('side-effect');
class Impure {
constructor() {
console.log('side-effect');
}
}
/*@__PURE__*/ new Impure();
treeshake.correctVarValueBeforeDeclaration
Type: boolean
CLI: --treeshake.correctVarValueBeforeDeclaration
/--no-treeshake.correctVarValueBeforeDeclaration
Default: false
In some edge cases if a variable is accessed before its declaration assignment and is not reassigned, then Rollup may incorrectly assume that variable is constant throughout the program, as in the example below. This is not true if the variable is declared with var
, however, as those variables can be accessed before their declaration where they will evaluate to undefined
. Choosing true
will make sure Rollup does not make any assumptions about the value of variables declared with var
. Note though that this can have a noticeable negative impact on tree-shaking results.
// everything will be tree-shaken unless treeshake.correctVarValueBeforeDeclaration === true
let logBeforeDeclaration = false;
function logIfEnabled() {
if (logBeforeDeclaration) {
log();
}
var value = true;
function log() {
if (!value) {
console.log('should be retained, value is undefined');
}
}
}
logIfEnabled(); // could be removed
logBeforeDeclaration = true;
logIfEnabled(); // needs to be retained as it displays a log
treeshake.moduleSideEffects
Type: boolean | "no-external" | string[] | (id: string, external: boolean) => boolean
CLI: --treeshake.moduleSideEffects
/--no-treeshake.moduleSideEffects
/--treeshake.moduleSideEffects no-external
Default: true
If false
, assume modules and external dependencies from which nothing is imported do not have other side effects like mutating global variables or logging without checking. For external dependencies, this will suppress empty imports:
// input file
import { unused } from 'external-a';
import 'external-b';
console.log(42);
// output with treeshake.moduleSideEffects === true
import 'external-a';
import 'external-b';
console.log(42);
// output with treeshake.moduleSideEffects === false
console.log(42);
For non-external modules, false
will not include any statements from a module unless at least one import from this module is included:
// input file a.js
import { unused } from './b.js';
console.log(42);
// input file b.js
console.log('side-effect');
const ignored = 'will still be removed';
// output with treeshake.moduleSideEffects === true
console.log('side-effect');
console.log(42);
// output with treeshake.moduleSideEffects === false
console.log(42);
You can also supply a list of modules with side effects or a function to determine it for each module individually. The value "no-external"
will only remove external imports if possible and is equivalent to the function (id, external) => !external
;
If a module that has this flag set to false
reexports a variable from another module and this variable is used, the question if the reexporting module is scanned for side effects depends on how the variable is reexported:
// input file a.js
import { foo } from './b.js';
console.log(foo);
// input file b.js
// direct reexports will ignore side effects
export { foo } from './c.js';
console.log('this side-effect is ignored');
// input file c.js
// indirect reexports will include side effects
import { foo } from './d.js';
foo.mutated = true;
console.log('this side-effect and the mutation are retained');
export { foo };
// input file d.js
export const foo = 42;
// output with treeshake.moduleSideEffects === false
const foo = 42;
foo.mutated = true;
console.log('this side-effect and the mutation are retained');
console.log(foo);
Note that despite the name, this option does not "add" side effects to modules that do not have side effects. If it is important that e.g. an empty module is "included" in the bundle because you need this for dependency tracking, the plugin interface allows you to designate modules as being excluded from tree-shaking via the resolveId
, load
or transform
hook.
treeshake.preset
Type: "smallest" | "safest" | "recommended"
CLI: --treeshake <value>
Allows choosing one of the presets listed above while overriding some of the options.
export default {
treeshake: {
preset: 'smallest',
propertyReadSideEffects: true
}
// ...
};
treeshake.propertyReadSideEffects
Type: boolean | 'always'
CLI: --treeshake.propertyReadSideEffects
/--no-treeshake.propertyReadSideEffects
Default: true
If true
, retain unused property reads that Rollup can determine to have side-effects. This includes accessing properties of null
or undefined
or triggering explicit getters via property access. Note that this does not cover destructuring assignment or getters on objects passed as function parameters.
If false
, assume reading a property of an object never has side effects. Depending on your code, disabling this option can significantly reduce bundle size but can potentially break functionality if you rely on getters or errors from illegal property access.
If 'always'
, assume all member property accesses, including destructuring, have side effects. This setting is recommended for code relying on getters with side effects. It typically results in larger bundle size, but smaller than disabling treeshake
altogether.
// Will be removed if treeshake.propertyReadSideEffects === false
const foo = {
get bar() {
console.log('effect');
return 'bar';
}
};
const result = foo.bar;
const illegalAccess = foo.quux.tooDeep;
treeshake.tryCatchDeoptimization
Type: boolean
CLI: --treeshake.tryCatchDeoptimization
/--no-treeshake.tryCatchDeoptimization
Default: true
By default, Rollup assumes that many builtin globals of the runtime behave according to the latest specs when tree-shaking and do not throw unexpected errors. In order to support e.g. feature detection workflows that rely on those errors being thrown, Rollup will by default deactivate tree-shaking inside try-statements. If a function parameter is called from within a try-statement, this parameter will be deoptimized as well. Set treeshake.tryCatchDeoptimization
to false
if you do not need this feature and want to have tree-shaking inside try-statements.
function otherFn() {
// even though this function is called from a try-statement, the next line
// will be removed as side-effect-free
Object.create(null);
}
function test(callback) {
try {
// calls to otherwise side-effect-free global functions are retained
// inside try-statements for tryCatchDeoptimization: true
Object.create(null);
// calls to other function are retained as well but the body of this
// function may again be subject to tree-shaking
otherFn();
// if a parameter is called, then all arguments passed to that function
// parameter will be deoptimized
callback();
} catch {}
}
test(() => {
// will be ratained
Object.create(null);
});
// call will be retained but again, otherFn is not deoptimized
test(otherFn);
treeshake.unknownGlobalSideEffects
Type: boolean
CLI: --treeshake.unknownGlobalSideEffects
/--no-treeshake.unknownGlobalSideEffects
Default: true
Since accessing a non-existing global variable will throw an error, Rollup does by default retain any accesses to non-builtin global variables. Set this option to false
to avoid this check. This is probably safe for most code-bases.
// input
const jQuery = $;
const requestTimeout = setTimeout;
const element = angular.element;
// output with unknownGlobalSideEffects == true
const jQuery = $;
const element = angular.element;
// output with unknownGlobalSideEffects == false
const element = angular.element;
In the example, the last line is always retained as accessing the element
property could also throw an error if angular
is e.g. null
. To avoid this check, set treeshake.propertyReadSideEffects
to false
as well.
These options reflect new features that have not yet been fully finalized. Availability, behaviour and usage may therefore be subject to change between minor versions.
Type: number
CLI: --experimentalCacheExpiry <numberOfRuns>
Default: 10
Determines after how many runs cached assets that are no longer used by plugins should be removed.
Type: boolean
CLI: --perf
/--no-perf
Default: false
Whether to collect performance timings. When used from the command line or a configuration file, detailed measurements about the current bundling process will be displayed. When used from the JavaScript API, the returned bundle object will contain an additional getTimings()
function that can be called at any time to retrieve all accumulated measurements.
getTimings()
returns an object of the following form:
{
"# BUILD": [ 698.020877, 33979632, 45328080 ],
"## parse modules": [ 537.509342, 16295024, 27660296 ],
"load modules": [ 33.253778999999994, 2277104, 38204152 ],
...
}
For each key, the first number represents the elapsed time while the second represents the change in memory consumption, and the third represents the total memory consumption after this step. The order of these steps is the order used by Object.keys
. Top level keys start with #
and contain the timings of nested steps, i.e. in the example above, the 698ms of the # BUILD
step include the 538ms of the ## parse modules
step.
Type: { buildDelay?: number, chokidar?: ChokidarOptions, clearScreen?: boolean, exclude?: string, include?: string, skipWrite?: boolean } | false
Default: {}
Specify options for watch mode or prevent this configuration from being watched. Specifying false
is only really useful when an array of configurations is used. In that case, this configuration will not be built or rebuilt on change in watch mode, but it will be built when running Rollup regularly:
// rollup.config.js
export default [
{
input: 'main.js',
output: { file: 'bundle.cjs.js', format: 'cjs' }
},
{
input: 'main.js',
watch: false,
output: { file: 'bundle.es.js', format: 'es' }
}
];
These options only take effect when running Rollup with the --watch
flag, or using rollup.watch
.
Type: number
CLI: --watch.buildDelay <number>
Default: 0
Configures how long Rollup will wait for further changes until it triggers a rebuild in milliseconds. By default, Rollup does not wait but there is a small debounce timeout configured in the chokidar instance. Setting this to a value greater than 0
will mean that Rollup will only trigger a rebuild if there was no change for the configured number of milliseconds. If several configurations are watched, Rollup will use the largest configured build delay.
Type: ChokidarOptions
An optional object of watch options that will be passed to the bundled chokidar instance. See the chokidar documentation to find out what options are available.
Type: boolean
CLI: --watch.clearScreen
/--no-watch.clearScreen
Default: true
Whether to clear the screen when a rebuild is triggered.
Type: string | RegExp | (string | RegExp)[]
CLI: --watch.exclude <files>
Prevent files from being watched:
// rollup.config.js
export default {
...,
watch: {
exclude: 'node_modules/**'
}
};
Type: string | RegExp | (string | RegExp)[]
CLI: --watch.include <files>
Limit the file-watching to certain files. Note that this only filters the module graph but does not allow adding additional watch files:
// rollup.config.js
export default {
...,
watch: {
include: 'src/**'
}
};
Type: boolean
CLI: --watch.skipWrite
/--no-watch.skipWrite
Default: false
Whether to skip the bundle.write()
step when a rebuild is triggered.
☢️ These options have been deprecated and may be removed in a future Rollup version.
Use the output.inlineDynamicImports
output option instead, which has the same signature.
Use the output.manualChunks
output option instead, which has the same signature.
Use the output.preserveModules
output option instead, which has the same signature.
Use the renderDynamicImport
plugin hook instead.
Type: string
CLI: --dynamicImportFunction <name>
Default: import
This will rename the dynamic import function to the chosen name when outputting ES bundles. This is useful for generating code that uses a dynamic import polyfill such as this one.
Use treeshake.moduleSideEffects: 'no-external'
instead.
Type: boolean | string[] | (id: string) => boolean | null
CLI: --treeshake.pureExternalModules
/--no-treeshake.pureExternalModules
Default: false
If true
, assume external dependencies from which nothing is imported do not have other side effects like mutating global variables or logging.
// input file
import { unused } from 'external-a';
import 'external-b';
console.log(42);
// output with treeshake.pureExternalModules === false
import 'external-a';
import 'external-b';
console.log(42);
// output with treeshake.pureExternalModules === true
console.log(42);
You can also supply a list of external ids to be considered pure or a function that is called whenever an external import could be removed.