Connect with us

Technology

An Introduction to the Rollup.js JavaScript Bundler – SitePoint


Rollup.js is a next-generation JavaScript module bundler from Wealthy Harris, the creator of Svelte. It compiles a number of supply recordsdata right into a single bundle.

The advantages embrace:

  • improvement is less complicated to handle when utilizing smaller, self-contained supply recordsdata
  • the supply will be linted, prettified, and syntax-checked throughout bundling
  • tree-shaking removes unused features
  • transpiling to ES5 for backward compatibility is feasible
  • a number of output recordsdata will be generated — for instance, your library could possibly be offered in ES5, ES6 modules, and Node.js-compatible CommonJS
  • manufacturing bundles will be minified and have logging eliminated

Different bundler choices, corresponding to webpack, Snowpack, and Parcel, try and magically deal with every little thing: HTML templating, picture optimization, CSS processing, JavaScript bundling, and extra. This works effectively once you’re proud of the default settings, however customized configurations will be tough and processing is slower.

Rollup.js primarily concentrates on JavaScript (though there are plugins for HTML templates and CSS). It has a frightening variety of choices, nevertheless it’s simple to get began and bundling is quick. This tutorial explains the way to use typical configurations inside your individual initiatives.

Set up Rollup.js

Rollup.js requires Node.js v8.0.0 or above and will be put in globally with:

npm set up rollup --global

This allows the rollup command to be run in any undertaking listing containing JavaScript recordsdata — corresponding to a PHP, WordPress, Python, Ruby or different undertaking.

Nevertheless, in the event you’re on a bigger staff making a Node.js undertaking, it may be preferable to put in Rollup.js regionally to make sure all builders are utilizing the identical model. Presuming you might have an present Node.js bundle.json file inside a undertaking folder, run:

npm set up rollup --save-dev

You gained’t be capable to run the rollup command straight, however npx rollup can be utilized. Alternatively, rollup instructions will be added to the bundle.json "scripts" part. For instance:

"scripts": {
  "watch": "rollup ./src/essential.js --file ./construct/bundle.js --format es --watch",
  "construct": "rollup ./src/essential.js --file ./construct/bundle.js --format es",
  "assist": "rollup --help"
},

These scripts will be executed with npm run <scriptname> — for instance, npm run watch.

The examples beneath particularly use npx rollup, since it’s going to work no matter whether or not rollup is put in regionally or globally.

Instance Information

Instance recordsdata and Rollup.js configurations will be downloaded from GitHub. It’s a Node.js undertaking, so run npm set up after cloning and look at the README.md file for directions. Notice that Rollup.js and all plugins are put in regionally.

Alternatively, you may create the supply recordsdata manually after initializing a brand new Node.js undertaking with npm init. The next ES6 modules create a real-time digital clock used to display Rollup.js processing.

src/essential.js is the primary entry level script. It locates a DOM aspect and runs a operate each second, which units its content material to the present time:

import * as dom from './lib/dom.js';
import { formatHMS } from './lib/time.js';


const clock = dom.get('.clock');

if (clock) {

  console.log('initializing clock');

  
  setInterval(() => {

    clock.textContent = formatHMS();

  }, 1000);

}

src/lib/dom.js is a small DOM utility library:




export operate get(selector, doc = doc) {
  return doc.querySelector(selector);
}


export operate getAll(selector, doc = doc) {
  return doc.querySelectorAll(selector);
}

and src/lib/time.js supplies time formatting features:




operate timePad(n) {
  return String(n).padStart(2, '0');
}


export operate formatHM(d = new Date()) {
  return timePad(d.getHours()) + ':' + timePad(d.getMinutes());
}


export operate formatHMS(d = new Date()) {
  return formatHM(d) + ':' + timePad(d.getSeconds());
}

The clock code will be added to an online web page by creating an HTML aspect with a clock class and loading the script as an ES6 module:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Rollup.js testing</title>
<meta identify="viewport" content material="width=device-width,initial-scale=1" />
<script sort="module" src="./src/essential.js"></script>
</head>
<physique>

  <h1>Clock</h1>

  <time class="clock"></time>

</physique>
</html>

Rollup.js supplies choices for optimizing the JavaScript supply recordsdata.

Rollup.js Fast Begin

The next command will be run from the basis of the undertaking folder to course of src/essential.js and its dependencies:

npx rollup ./src/essential.js --file ./construct/bundle.js --format iife

A single script at construct/bundle.js is output. It comprises all code, however discover that unused dependencies such because the getAll() operate in src/lib/dom.js have been eliminated:

(operate () {
  'use strict';

  

  
  operate get(selector, doc = doc) {
    return doc.querySelector(selector);
  }

  

  
  operate timePad(n) {
    return String(n).padStart(2, '0');
  }

  
  operate formatHM(d = new Date()) {
    return timePad(d.getHours()) + ':' + timePad(d.getMinutes());
  }

  
  operate formatHMS(d = new Date()) {
    return formatHM(d) + ':' + timePad(d.getSeconds());
  }

  
  const clock = get('.clock');

  if (clock) {

    console.log('initializing clock');

    setInterval(() => {

      clock.textContent = formatHMS();

    }, 1000);

  }

}());

The HTML <script> can now be modified to reference the bundled file:

<script sort="module" src="./construct/bundle.js"></script>

Notice: sort="module" is now not mandatory, so the script ought to work in older browsers which assist early ES6 implementations. You must also add a defer attribute to make sure the script runs after the DOM is prepared (this happens by default in ES6 modules).

Rollup.js gives quite a few command-line flags. The next sections describe probably the most helpful choices.

Rollup.js Assist

Rollup’s command-line choices will be considered with the --help or -h flag:

npx rollup --help

The Rollup.js model will be output with --version or -v:

npx rollup --version

Output File

The --file (or -o) flag defines the output bundle file, which is ready to ./construct/bundle.js above. If no file is specified, the ensuing bundle is distributed to stdout.

JavaScript Formatting

Rollup.js supplies a number of --format (or -f) choices to configure the ensuing bundle:

Except you’re utilizing a particular module system, iife would be the most suitable choice for client-side JavaScript. es6 will produce a barely smaller bundle, however be cautious of worldwide variables and features which might battle with different libraries.

Output a Supply Map

A supply map supplies a reference again to the supply recordsdata to allow them to be examined in browser developer instruments. This makes it simpler to set breakpoints or find issues when errors happen.

An exterior supply map will be created by including a --sourcemap flag to the rollup command:

npx rollup ./src/essential.js --file ./construct/bundle.js --format iife --sourcemap

This creates a further ./construct/bundle.js.map file. You’ll be able to view it, though it’s principally gibberish and never meant for human consumption! The map is referenced as a remark on the finish of ./construct/bundle.js:


Alternatively, you may create an inline supply map with --sourcemap inline. Moderately than producing a further file, a base64-encoded model of the supply map is appended to ./construct/bundle.js:


After producing the supply map, you may load an instance web page which references the script. Open your developer instruments and navigate to the Sources tab in Chrome-based browsers or the Debugger tab in Firefox. You’ll see the unique src code and line numbers.

Watch Information and Robotically Bundle

The --watch (or -w) flag screens your supply recordsdata for adjustments and routinely builds the bundle. The terminal display screen is cleared on each run, however you may disable this with --no-watch.clearScreen:

npx rollup ./src/essential.js --file ./construct/bundle.js --format iife --watch --no-watch.clearScreen

Create a Configuration File

Command-line flags can rapidly turn into unwieldy. The examples above are already lengthy and also you’ve not begun so as to add plugins!

Rollup.js can use a JavaScript configuration file to outline bundling choices. The default identify is rollup.config.js and it needs to be positioned within the root of your undertaking (usually, the listing the place you run rollup from).

The file is an ES module which exports a default object that units Rollup.js choices. The next code replicates the instructions used above:



export default {

  enter: './src/essential.js',

  output: {
    file: './construct/bundle.js',
    format: 'iife',
    sourcemap: true
  }

}

Notice: sourcemap: true defines an exterior sourcemap. Use sourcemap: 'inline' for an inline sourcemap.

You should utilize this configuration file when working rollup by setting the --config (or -c) flag:

npx rollup --config

A file identify will be handed in the event you named the configuration one thing apart from than rollup.config.js. This may be sensible when you might have a number of configurations maybe situated in a config listing. For instance:

npx rollup --config ./config/rollup.easy.js

Automated Bundling

watch choices will be set inside the configuration file. For instance:



export default {

  enter: './src/essential.js',

  watch: {
    embrace: './src/**',
    clearScreen: false
  },

  output: {
    file: './construct/bundle.js',
    format: 'iife',
    sourcemap: true
  }

}

Nevertheless, it’s nonetheless mandatory so as to add a --watch flag when calling rollup:

npx rollup --config --watch

Course of A number of Bundles

The configuration file above returns a single object to course of one enter file and its dependencies. It’s also possible to return an array of objects to outline a number of enter and output operations:



export default [

  {

    input: './src/main.js',

    output: {
      file: './build/bundle.js',
      format: 'iife',
      sourcemap: true
    }

  },

  {

    input: './src/another.js',

    output: {
      file: './build/another.js',
      format: 'es'
    }

  },

]

It could be sensible to outline an array even when returning a single object. It will make it simpler to append additional processes later.

Utilizing Surroundings Variables

The configuration file is JavaScript, so settings will be modified in accordance with any environmental issue. For instance, it’s your decision script bundling to be barely totally different when working in your improvement machine or a manufacturing server.

The next configuration detects the NODE_ENV setting variable and removes the supply map when it’s set to manufacturing:


const dev = (course of.env.NODE_ENV !== 'manufacturing');

console.log(`working in ${ dev ? 'improvement' : 'manufacturing' } mode`);

const sourcemap = dev ? 'inline' : false;

export default [

  {

    input: './src/main.js',

    watch: {
      clearScreen: false
    },

    output: {
      file: './build/bundle.js',
      format: 'iife',
      sourcemap
    }

  }

]

The worth of NODE_ENV will be set from the command line on macOS or Linux:

NODE_ENV=manufacturing

That is the Home windows cmd immediate:

set NODE_ENV=manufacturing

For Home windows Powershell:

$env:NODE_ENV="manufacturing"

Nevertheless, Rollup.js additionally means that you can briefly set/override setting variables within the --environment flag. For instance:

npx rollup --config --environment VAR1,VAR2:value2,VAR3:x

course of.env can then be examined in your configuration file:

  • course of.env.VAR1 is true
  • course of.env.VAR2 is value2
  • course of.env.VAR3 is x

The configuration script above defaults to improvement mode, however manufacturing mode (and not using a supply map) will be triggered with:

npx rollup --config --environment NODE_ENV:manufacturing

Rollup.js Plugins

Rollup.js has an intensive vary of plugins to complement the bundling and output course of. You’ll discover numerous choices to inject code, compile TypeScript, lint recordsdata, and even set off HTML and CSS processing.

Utilizing a plugin is much like different Node.js initiatives. You will need to set up the plugin module, then reference it in a plugin array within the Rollup.js configuration file. The next sections describe a number of of the most-used plugins.

Use npm Modules

Many JavaScript libraries are packaged as CommonJS modules which will be put in utilizing npm. Rollup.js can embrace such scripts in bundles with the next plugins:

  1. node-resolve, which locates the module within the undertaking’s node_modules listing, and
  2. plugin-commonjs, which converts CommonJS modules to ES6 when mandatory.

Set up them in your undertaking:

npm set up @rollup/plugin-node-resolve @rollup/plugin-commonjs --save-dev

Moderately than utilizing the time formatting features in src/lib/time.js, you possibly can add a extra complete date/time dealing with library corresponding to day.js. Set up it with npm:

npm set up dayjs --save-dev

Then modify src/essential.js accordingly:

import * as dom from './lib/dom.js';
import dayjs from 'dayjs';


const clock = dom.get('.clock');

if (clock) {

  console.log('initializing clock');

  setInterval(() => {

    clock.textContent = dayjs().format('HH:mm:ss');

  }, 1000);

}

rollup.config.js have to be up to date to incorporate and use the plugins in a brand new plugins array:


import { nodeResolve as resolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';

const
  dev = (course of.env.NODE_ENV !== 'manufacturing'),
  sourcemap = dev ? 'inline' : false;

console.log(`working in ${ dev ? 'improvement' : 'manufacturing' } mode`);

export default [

  {

    input: './src/main.js',

    watch: {
      clearScreen: false
    },

    plugins: [
      resolve({
        browser: true
      }),
      commonjs()
    ],

    output: {
      file: './construct/bundle.js',
      format: 'iife',
      sourcemap
    }

  }

];

Run Rollup.js as earlier than:

npx rollup --config

You’ll now discover day.js code has been included inside construct/bundle.js.

When you’re pleased it’s working, revert src/essential.js again to the unique native code library, because it’s used within the following sections. Your rollup.config.js doesn’t want to vary.

Substitute Tokens

It’s typically helpful to cross configuration variables at construct time so that they turn into hard-coded within the bundled script. For instance, you possibly can create a JSON file with design tokens that specify colours, fonts, spacing, selectors, or some other tweaks that may be utilized to HTML, CSS, or JavaScript.

The Rollup.js change plugin can change any reference in your scripts. Set up it with:

npm set up @rollup/plugin-replace --save-dev

Modify rollup.config.js to import the plugin and outline a tokens object which is handed to the change() operate within the plugins array. On this instance, you may modify the clock selector (__CLOCKSELECTOR__), replace time interval (__CLOCKINTERVAL__), and time formatting operate (__CLOCKFORMAT__):


import { nodeResolve as resolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import change from '@rollup/plugin-replace';

const
  dev = (course of.env.NODE_ENV !== 'manufacturing'),
  sourcemap = dev ? 'inline' : false,

  
  tokens = {
    __CLOCKSELECTOR__: '.clock',
    __CLOCKINTERVAL__: 1000,
    __CLOCKFORMAT__: 'formatHMS'
  };

console.log(`working in ${ dev ? 'improvement' : 'manufacturing' } mode`);

export default [

  {

    input: './src/main.js',

    watch: {
      clearScreen: false
    },

    plugins: [
      replace(tokens),
      resolve({
        browser: true
      }),
      commonjs()
    ],

    output: {
      file: './construct/bundle.js',
      format: 'iife',
      sourcemap
    }

  }

];

src/essential.js have to be modified to make use of these tokens. Alternative strings will be utilized wherever — whilst operate names or import references:

import * as dom from './lib/dom.js';
import { __CLOCKFORMAT__ } from './lib/time.js';


const clock = dom.get('__CLOCKSELECTOR__');

if (clock) {

  console.log('initializing clock');

  setInterval(() => {

    clock.textContent = __CLOCKFORMAT__();

  }, __CLOCKINTERVAL__);

}

Run npx rollup --config and also you’ll uncover that construct/bundle.js is equivalent to earlier than, however it may possibly now be modified by altering the Rollup.js configuration file.

Transpile to ES5

Trendy JavaScript works in trendy browsers. Sadly, that doesn’t embrace older functions corresponding to IE11. Many builders use options corresponding to Babel to transpile ES6 to a backward-compatible ES5 various.

I’ve combined emotions about creating ES5 bundles:

  1. In December 2020, IE11’s market share was lower than 1%. Inclusivity is nice, however is it extra helpful to focus on accessibility and efficiency somewhat than a decade-old browser?
  2. Legacy browsers will be supported if progressive enhancement is adopted. These browsers could not run any JavaScript, however the website can nonetheless provide a degree of HTML and CSS performance.
  3. ES5 bundles will be significantly bigger than ES6. Ought to trendy browsers obtain a much less environment friendly script?

Transferring towards the longer term, I counsel you bundle ES6 solely and have older (slower) browsers depend on HTML and CSS alone. That gained’t at all times be potential — corresponding to when you might have a fancy software with a big proportion of IE11 customers. In these conditions, contemplate creating each ES6 and ES5 bundles and serve the suitable script.

Rollup.js gives a plugin which makes use of Bublé to transpile to ES5. The undertaking is in upkeep mode however nonetheless works effectively.

Notice: right here’s a quote from the undertaking repository: “Bublé was created when ES2015 was nonetheless the longer term. These days, all trendy browsers assist all of ES2015 and (in some circumstances) past. Except it’s worthwhile to assist IE11, you most likely don’t want to make use of Bublé to transform your code to ES5.”

Set up the plugin so you may output each ES6 and ES5 modules:

npm set up @rollup/plugin-buble --save-dev

Earlier than modifying the configuration, the String padStart() operate utilized in src/lib/time.js shouldn’t be carried out in older browsers. A easy polyfill can be utilized by including the next code to a brand new src/lib/polyfill.js file:


if (!String.prototype.padStart) {

  String.prototype.padStart = operate padStart(len, str) ;

}

This polyfill shouldn’t be required in ES6, so that you require a solution to inject it into the ES5 code solely. Thankfully, you might have already put in the change plugin so this may be adopted for the duty.

Add a __POLYFILL__ token to the highest of src/essential.js:

__POLYFILL__
import * as dom from './lib/dom.js';
import { __CLOCKFORMAT__ } from './lib/time.js';


Then set it within the Rollup.js configuration within the ES5 "plugins" array:


import change from '@rollup/plugin-replace';
import { nodeResolve as resolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import buble from '@rollup/plugin-buble';


const
  dev = (course of.env.NODE_ENV !== 'manufacturing'),
  sourcemap = dev ? 'inline' : false,

  enter = './src/essential.js',

  watch = { clearScreen: false },

  tokens = {
    __CLOCKSELECTOR__: '.clock',
    __CLOCKINTERVAL__: 1000,
    __CLOCKFORMAT__: 'formatHMS'
  };

console.log(`working in ${ dev ? 'improvement' : 'manufacturing' } mode`);

export default [

  {
    
    input,
    watch,

    plugins: [
      replace({
        ...tokens,
        __POLYFILL__: '' 
      }),
      resolve({ browser: true }),
      commonjs()
    ],

    output: {
      file: './construct/bundle.mjs',
      format: 'iife',
      sourcemap
    }

  },

  {
    
    enter,
    watch,

    plugins: [
      replace({
        ...tokens,
        __POLYFILL__: "import './lib/polyfill.js';" 
      }),
      resolve({ browser: true }),
      commonjs(),
      buble()
    ],

    output: {
      file: './construct/bundle.js',
      format: 'iife',
      sourcemap
    }

  }

];

Run npx rollup --config to construct each the ES6 construct/bundle.mjs and ES5 construct/bundle.js scripts. The HTML file have to be modified accordingly:

<script sort="module" src="./construct/bundle.mjs"></script>
<script nomodule src="./construct/bundle.js" defer></script>

Trendy browsers will load and run the ES6 contained in ./construct/bundle.mjs. Older browsers will load and run the ES5 (plus polyfill) script contained in ./construct/bundle.js.

Transpiling with Babel

Bublé is less complicated, quicker, and fewer fussy, however Babel can be utilized in the event you require a particular possibility. Set up the next plugins:

npm set up @rollup/plugin-babel @babel/core @babel/preset-env --save-dev

Then embrace Babel in your configuration file:

import { getBabelOutputPlugin } from '@rollup/plugin-babel';

Then append this code to your plugins array:

    plugins: [
      getBabelOutputPlugin({
        presets: ['@babel/preset-env']
      })
    ],

The output.format should even be modified to es or cjs earlier than working.

Minify Output

The fabulous Terser minifier can compact code by optimizing statements and eradicating whitespace, feedback, and different pointless characters. The outcomes will be dramatic. Even on this small instance, the Rollup.js output (which has already created a smaller bundle) will be lowered by an extra 60%.

Set up the Rollup.js Terser plugin with:

npm set up rollup-plugin-terser --save-dev

Then import it on the high of your Rollup.js configuration file:

import { terser } from 'rollup-plugin-terser';

Terser is an output plugin which is processed after Rollup.js has accomplished its main bundling duties. Due to this fact, terser() choices are outlined inside a plugins array inside the output object. The ultimate configuration file:


import change from '@rollup/plugin-replace';
import { nodeResolve as resolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import buble from '@rollup/plugin-buble';
import { terser } from 'rollup-plugin-terser';


const
  dev = (course of.env.NODE_ENV !== 'manufacturing'),
  sourcemap = dev ? 'inline' : false,

  enter = './src/main-replace.js',

  watch = { clearScreen: false },

  tokens = {
    __CLOCKSELECTOR__: '.clock',
    __CLOCKINTERVAL__: 1000,
    __CLOCKFORMAT__: 'formatHMS'
  };

console.log(`working in ${ dev ? 'improvement' : 'manufacturing' } mode`);

export default [

  {
    
    input,
    watch,

    plugins: [
      replace({
        ...tokens,
        __POLYFILL__: '' 
      }),
      resolve({ browser: true }),
      commonjs()
    ],

    output: {
      file: './construct/bundle.mjs',
      format: 'iife',
      sourcemap,
      plugins: [
        terser({
          ecma: 2018,
          mangle: { toplevel: true },
          compress: {
            module: true,
            toplevel: true,
            unsafe_arrows: true,
            drop_console: !dev,
            drop_debugger: !dev
          },
          output: { quote_style: 1 }
        })
      ]
    }

  },

  {
    
    enter,
    watch,

    plugins: [
      replace({
        ...tokens,
        __POLYFILL__: "import './lib/polyfill.js';" 
      }),
      resolve({ browser: true }),
      commonjs(),
      buble()
    ],

    output: {
      file: './construct/bundle.js',
      format: 'iife',
      sourcemap,
      plugins: [
        terser({
          ecma: 2015,
          mangle: { toplevel: true },
          compress: {
            toplevel: true,
            drop_console: !dev,
            drop_debugger: !dev
          },
          output: { quote_style: 1 }
        })
      ]
    }

  }

];

The Terser configuration differs for ES5 and ES6 primarily to focus on totally different editions of the ECMAScript normal. In each circumstances, console and debugger statements are eliminated when the NODE_ENV setting variable is ready to manufacturing.

The ultimate manufacturing construct can due to this fact be created with:

npx rollup --config --environment NODE_ENV:manufacturing

The ensuing file sizes:

  • ES6 ./construct/bundle.mjs: 294 bytes from an unique bundle of 766 bytes (62% discount)
  • ES5 ./construct/bundle.js: 485 bytes from an unique bundle of 1,131 bytes (57% discount)

Your Subsequent Steps with Rollup.js

Few builders might want to enterprise past the command-line choices above, however Rollup.js has just a few different methods …

Rollup.js JavaScript API

Bundling will be triggered from Node.js code utilizing the Rollup.js JavaScript API. The API makes use of related parameters to the configuration file so you may create an asynchronous operate to deal with bundling. This could possibly be used inside a Gulp.js job or some other course of:

const rollup = require('rollup');

async operate construct() {

  
  const bundle = await rollup.rollup({
    
  });

  
  const { output } = await bundle.generate({
    
  });

  
  await bundle.write({
    
  });

  
  await bundle.shut();
}


construct();

Alternatively, you need to use a rollup.watch() operate to set off handler features when supply recordsdata are modified.

Create Your Personal Rollup.js Plugins

Rollup.js gives many plugins, however you can even create your individual. All plugins export a operate which is named with plugin-specific choices set within the Rollup.js configuration file. The operate should return an object containing:

  1. a single identify property
  2. numerous construct hook features, corresponding to buildStart or buildEnd, that are referred to as when particular bundling occasions happen, and/or
  3. numerous output era hooks, corresponding to renderStart or writeBundle, that are referred to as after the bundle has been generated.

I like to recommend navigating to the GitHub repository of any plugin to look at the way it works.

Rollup Revolution

Rollup.js takes a short while to arrange, however the ensuing configuration can be appropriate for a lot of of your initiatives. It’s splendid if you would like a quicker and extra configurable JavaScript bundler.

Fast hyperlinks:

Click to comment

Leave a Reply

Your email address will not be published. Required fields are marked *