Rollup — A new JS Module Bundler

Gautam Paul
5 min readOct 6, 2021
Rollup JS

We developers are very curious by nature. We have seen things like Grunt, Gulp & Webpack. We have a new kid in the block now. Let’s take a close look before we dismiss it as another tool !

Introduction

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 standardised 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 favourite libraries.

Official Site : https://rollupjs.org

Installation

Install a stable Node version. Open terminal & type this command:

npm install rollup — global

These commands assume the entry point to your application is named main.js, and all imports get 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”

Creating Your First Bundle

Now let’s create a new project. Open terminal & type this command:

mkdir my-project
cd my-project

We will need an entry point. Let’s create a new file called src/main.js:

File : src/main.js

import hello from ‘./hello.js’;
export default function () {
console.log(hello);
}

Then, let us create the hello.js module that our entry point imports:

File : src/hello.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 hello = ‘hello world!’;const main = function () {
console.log(hello);
};
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!’

Your first bundle with Rollup is ready for use.

Tree-Shaking

In addition to enabling the use of ES modules, Rollup also statically analyzes the code and supports tree shaking. This allows you to build on top of existing tools and modules without adding extra dependencies or bloating the size of your project.

With CommonJS, the entire tool or library must be imported. With ES modules, instead of importing the whole utils object, we can just import the one function we need.

Rollup includes only the bare minimum which results in lighter, faster, and less complicated libraries and applications. The approach can utilise explicit import and export statements and it is more effective than simply running an automated minifier to detect unused variables in the compiled output code.

Code Splitting

Rollup can automatically splits code into chunks like dynamic loading or multiple entry points. Also Rollup can explicitly split modules into separate chunks via the output.manualChunks option.

Let’s modify src/main.js to load src/hello.js dynamically instead of statically:

File : src/main.js

export default function () {
import(‘./hello.js’).then(({ default: hello }) => console.log(hello));
}

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 & output.entryFileNames options.

You can still run your code as before with the same output, albeit a little slower as loading and parsing of ./hello.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/hello.js just like we did in the original example:

// src/main2.js

import hello from ‘./hello.js’;
export default function () {
console.log(hello);
}

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.

Compatibility

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.

Conclusion

With ES6 revision of JavaScript, we can now import and export functions and data so they can be shared between separate scripts. The specification is only implemented in modern browsers and not finalised in Node.js. Rollup allows you to write your code using the new module system. It will then compile it back down to existing supported formats such as CommonJS modules, AMD modules and IIFE-style scripts. Rollup makes your code future-proof.

--

--

Gautam Paul

Engineering Director / Software Architect / Writer