RollupJS is a next-generation JavaScript module bundler

RollupJS is a next-generation JavaScript module bundler

  • 2016-08-05
  • 1751

You most likely have used, or at least heard of, Webpack or Browserify by this point, both of which are JavaScript module bundlers. Rollup is also a module bundler which allows you to write your application or library using the ES2015 import / export syntax and package it up into a single file.

If you’ve never used a module bundler, you might be wondering: what do I even need this for? The most straightforward answer is that ES2015 modules are currently not supported in browsers or Node.js. However, there are a number of other benefits that you get from bundling your modules into a single file including faster load times and tree-shaking which we will talk about in a second.

So why should you bother learning how to use yet another module bundler? Rollup works differently than Webpack and Browserify. When you require a module, everything gets imported, whether your application uses it or not. With ES2015 modules, you can import only the parts that you actually need, like so:

import { checkout } from './git_utils.js'
checkout('src/index.js')

as opposed to requiring the entire module:

var gitUtils = require('./git_utils.js')
gitUtils.checkout('src/index.js')

Using a process called tree-shaking, Rollup can then statically analyze your code and include only the parts you use from the modules you import, resulting in a smaller bundle. Webpack 2 is also going to support tree-shaking, however there is another fundamental difference between how Rollup and other module bundlers like Webpack and Browserify work.

Webpack and Browserify wrap each module in a function, bundle those functions, and include a module loader. Instead Rollup allows all modules to share a single scope - no need for a module loader or the additional overhead that comes from wrapping them. You can have a look at a more in-depth example here, if you would like more details.

Enough of the technical background, let’s jump into some examples of how we can use Rollup to bundle our ES2015 modules!

Module Bundling via the CLI

The simplest way to use Rollup is via it’s command line interface. Let’s start off by globally installing Rollup using NPM:

npm install -g rollup

Now let’s create a very simple project to illustrate how to use Rollup. Create a directory called rollup-demo:

mkdir rollup-demo && cd rollup-demo

Inside this directory we’ll create a src folder that will contain 2 files, main.js, the main entry point for our application, and logger.js, a simple utility to print a log message. src/logger.js will looks like so:

 // src/logger.js
    var messageLevel = {
      'info': '[INFORMATION]',
      'warn': '[WARNING]',
      'error': '[ERROR]'
    }

    export default function (message, level) {
      console.log(messageLevel[level] + ' ' + message)
    }

and src/main.js:

    // src/main.js
    import log from './logger.js'

    log('I Rollup, I Rollup, I Rollup', 'info')

You should have a folder structure that looks like this:

Rollup.js Demo Folder Structure

If you try to run main.js in the browser or using Node.js, you’ll get a syntax error since ES2015 import / export syntax is not yet supported. This is when Rollup comes in handy! From the rollup-demo folder, we can specify the entry point for our application (src/main.js) and an output file (dist/bundle.js), then let Rollup work it’s magic:

rollup src/main.js --output dist/bundle.js

You can now run the bundled code using Node and see the output:

    node dist/bundle.js    

[INFORMATION] I Rollup, I Rollup, I Rollup

If you have a look at dist/bundle.js, you can see all the code from main.js and logger.js nicely bundled together, which can now be included as a single file in a <script> tag or executed with Node:

    var messageLevel = {
      'info': '[INFORMATION]',
      'warn': '[WARNING]',
      'error': '[ERROR]'
    }

    function log (message, level) {
      console.log(messageLevel[level] + ' ' + message)
    }

    log('I Rollup, I Rollup, I Rollup', 'info')

Specifying an Output Format

Let’s go back to src/main.js from the previous example and instead of just executing the log function that we’re importing, we will create a function and export it (similar to what a library would do):


    // src/main.js
    import log from './logger.js'

    function main () {
      log('I Rollup, I Rollup, I Rollup', 'info')  
    }

    //export default main

Now that we’re exporting the main function using the ES2015 export syntax, we will have to specify the format of the target platform we wish to use the bundle with. Let’s build the module so that it can be required and run using Node.

Since Node uses the CommonJS module system, we can bundle our modules with the --format <format>, where <format> in our case is cjs:

rollup src/main.js --output dist/bundle.js --format cjs

Now you can start the interactive Node shell and try it out:

   node
    > var myLib = require('./dist/bundle.js')
    > myLib()
    # [INFORMATION] I Rollup, I Rollup, I Rollup

The other target formats supported by rollup:

  • amd
  • cjs
  • es6
  • iife
  • umd

You can see them in action on Rollup’s site.

JavaScript Config Files

Another way to use Rollup is through config files written in plain old JavaScript for a better workflow and greater flexibility.

Let’s create a rollup.config.js file in the root of our project folder:

Rollup Config File Folder Structure


    // rollup.config.js
    export default {
      entry: 'src/main.js',
      format: 'cjs',
      dest: 'dist/bundle.js'
    }

The above config is equivalent to the command we ran in the previous section:

rollup src/main.js --output dist/bundle.js --format cjs

Let’s go ahead and run Rollup, pointing it to the config file we just created:

rollup --config

Rollup will automatically use the config file in the root of our project that we created and spit out the bundle in the dist/bundle.js file, as before.

How to Use Rollup with Babel

Rollup has a growing list of plugins which give you the ability to customize Rollup’s behaviour during the bundling process.

Transpiling code written in ES2015, or later, to JavaScript supported by various environments today using Babel is quite common. Thankfully, this can easily be done with Rollup using the rollup-plugin-babel plugin, so let’s initialize an empty package.json and install the plugin in our rollup-demo folder:

  npm init -y
    npm install --save-dev rollup-plugin-babel

We save the plugin to our dev-dependencies as we don’t actually rely on it in our actual application, only for transpiling our application code during the bundling process.

Going back to our Rollup config file, rollup.config.js, we can tell Rollup to use the Babel plugin we just installed to transpile our code:

   // rollup.config.js
    import babel from 'rollup-plugin-babel'

    export default {
      entry: 'src/main.js',
      format: 'cjs',
      dest: 'dist/bundle.js',
      plugins: [ babel() ]
    }

Super simple, right? All we need to do is import the plugin we just installed and tell Rollup which plugins we need to use by specifying them in the plugins array.

The next step is to configure Babel itself which is just as straightforward! We want to tell Babel that we’re writing our code in ES2015 and would like to transpile that to JavaScript supported by today’s browsers and Node.js. We can do so using Babel presets, so let’s install the es2015-preset for Rollup:

 npm install --save-dev babel-preset-es2015-rollup

To tell Babel to use this specific preset we just installed, we need to create a .babelrc file in the root of our project directory:

    // .babelrc
    {
      "presets": ["es2015-rollup"]
    }

and now we can start writing some ES2015 code! Just as a visual reference, this is what our directory should look like:

Rollup Babel Folder Structure

Let’s go into logger.js and change a few lines to ES2015 to prove this worked:

 // src/logger.js
    let messageLevel = {
      'info': '[INFORMATION]',
      'warn': '[WARNING]',
      'error': '[ERROR]'
    }

    export default function (message, level) {
      console.log(`${messageLevel[level]} ${message}`)
    }

We’re using the ES2015 let declaration instead of var as well as template strings in our console.log() statement.

We can run Rollup as we did before:

 rollup -c # shorthand for rollup --config

and you should now see the transpiled output in dist/bundle.js:


    // dist/bundle.js
    'use strict';

    var messageLevel = {
      'info': '[INFORMATION]',
      'warn': '[WARNING]',
      'error': '[ERROR]'
    };

    function log (message, level) {
      console.log(messageLevel[level] + ' ' + message);
    }

    function main() {
      log('I Rollup, I Rollup, I Rollup', 'info');
    }

    module.exports = main;

Rolling Up

Hopefully this tutorial gave you a taste of Rollup and how you can start using it in your own projects. I believe that Rollup does a great job at creating smaller bundles with less overhead than Webpack. However, I see Webpack being better suited for larger applications and Rollup more geared towards bundling libraries.