Frontend Development 11 min read

Why Choose Rollup? A Practical Guide to Bundling JavaScript Libraries

This article introduces Rollup as a modern JavaScript bundler, explains its advantages over CommonJS and Webpack, demonstrates quick-start commands for browsers, Node.js, and UMD formats, covers tree‑shaking with ES modules, and provides a complete TypeScript‑React library setup with configuration and publishing steps.

MaoDou Frontend Team
MaoDou Frontend Team
MaoDou Frontend Team
Why Choose Rollup? A Practical Guide to Bundling JavaScript Libraries

Overview

Rollup is a front‑end module bundler that can compile small pieces of code into larger, complex bundles such as libraries or applications.

Rollup uses the modern ES6 module format instead of older solutions like CommonJS and AMD.

Rollup is widely used for bundling JavaScript libraries.

Quick Start

rollup-starter-lib

rollup-starter-app

For the browser

<code># compile to a <script> containing a self‑executing function ('iife')
$ rollup main.js --file bundle.js --format iife</code>

For Node.js

<code># compile to a CommonJS module ('cjs')
$ rollup main.js --file bundle.js --format cjs</code>

For browsers and Node.js

<code># UMD format requires a bundle name
$ rollup main.js --file bundle.js --format umd --name "myBundle"</code>

For ES module

<code>$ rollup ./src/main.js --file ./dist/bundle.js --format es</code>

Why Rollup

Tree‑shaking

Also called live code inclusion.

Using Rollup with ES6 import/export allows static analysis of modules and removal of unused code.

Why ES Modules are preferred over CommonJS:

ES Modules are the official standard with a clear development direction.

CommonJS is a legacy temporary solution that existed before ES Modules.

ES Modules enable static analysis and tree‑shaking optimizations.

ES Modules provide advanced features such as circular references and dynamic binding.

<code>// Using CommonJS, you must import the whole library
var utils = require('utils');
var query = 'Rollup';
utils.ajax('https://api.example.com?search=' + query).then(handleResponse);

// Using ES6 modules, you can import only what you need
import { ajax } from 'utils';
var query = 'Rollup';
ajax('https://api.example.com?search=' + query).then(handleResponse);
</code>

Use Rollup in a CommonJS module

Rollup natively supports ES modules; CommonJS support requires the rollup-plugin-commonjs plugin.

You also need rollup-plugin-node-resolve so Rollup can locate external modules, similar to how Webpack and Browserify work.

Most npm packages are published as CommonJS, so installing both plugins is recommended, and the CommonJS plugin should run before other plugins.

Use it over Webpack?

Many open‑source projects prefer Rollup over Webpack.

Webpack has massive adoption and a huge ecosystem, but Rollup is lighter for library builds.

Facebook uses Rollup for the React build process.

Libraries such as Vue, Ember, Preact, D3, Three.js, Moment, and many others also use Rollup.

Rollup aims to efficiently build flat, distributable JavaScript libraries by fully leveraging ES Modules; however, it does not support code‑splitting or HMR and requires plugins for CommonJS.

Webpack supports code‑splitting, provides a browser‑friendly require , and is better for on‑demand loading, though it can be slower for large bundles.

Conclusion

Use Webpack for applications, and Rollup for libraries.

If you need code‑splitting, many static assets, and heavy CommonJS dependencies, choose Webpack.

If your codebase consists of ES Modules intended as reusable libraries, choose Rollup.

pkg.module

In the future, ES Modules ( import / export ) will become the universal standard, but current browsers and Node.js still require UMD or CommonJS builds.

Adding "module": "dist/my-library.es.js" to package.json improves support for both UMD and ES Module consumers.

Both Webpack and Rollup use pkg.module to generate more efficient code and perform tree‑shaking where possible.

Example: Create a TypeScript and React Module

ALL JS LIBRARIES SHOULD BE AUTHORED IN TYPESCRIPT

Install

<code>$ yarn add typescript rollup rollup-plugin-typescript2 rollup-plugin-commonjs rollup-plugin-peer-deps-external rollup-plugin-node-resolve --dev
$ yarn add react @types/react --dev
$ yarn add react-dom @types/react-dom --dev</code>

tsconfig.json

<code>{
  "compilerOptions": {
    "outDir": "build",
    "module": "esnext",
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "sourceMap": true,
    "allowJs": false,
    "jsx": "react",
    "declaration": true,
    "moduleResolution": "node",
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "resolveJsonModule": true,
    "downlevelIteration": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "build"]
}</code>

rollup.config.js

<code>import typescript from "rollup-plugin-typescript2";
import commonjs from "rollup-plugin-commonjs";
import external from "rollup-plugin-peer-deps-external";
import resolve from "rollup-plugin-node-resolve";
import pkg from "./package.json";

export default {
  input: "src/index.tsx",
  output: [
    { file: pkg.main, format: "cjs", sourcemap: true },
    { file: pkg.module, format: "es", sourcemap: true }
  ],
  external: [
    ...Object.keys(pkg.dependencies || {}),
    ...Object.keys(pkg.peerDependencies || {})
  ],
  plugins: [
    commonjs({ include: ["node_modules/**"] }),
    external(),
    resolve(),
    typescript({
      rollupCommonJSResolveHack: true,
      exclude: "**/__tests__/**",
      clean: true
    })
  ]
};
</code>

package.json

<code>{
  "name": "...",
  "version": "...",
  "description": "...",
  "author": "...",
  "main": "build/index.js",
  "module": "build/index.es.js",
  "jsnext:main": "build/index.es.js",
  "types": "build/index.d.ts",
  "license": "...",
  "repository": "...",
  "keywords": ["...", "..."],
  "scripts": {
    "build": "rollup -c",
    "start": "rollup -c -w",
    "prepare": "npm run build"
  },
  "files": ["build"],
  "peerDependencies": {
    "react": ">=16.8.0",
    "react-dom": ">=16.8.0"
  },
  "dependencies": {
    ...
  },
  "devDependencies": {
    "@types/react": "^16.8.23",
    "@types/react-dom": "^16.8.4",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "rollup": "^1.16.6",
    "rollup-plugin-commonjs": "^10.0.1",
    "rollup-plugin-node-resolve": "^5.2.0",
    "rollup-plugin-peer-deps-external": "^2.2.0",
    "rollup-plugin-typescript2": "^0.21.2",
    "typescript": "^3.5.2"
  }
}
</code>

Developing locally

<code># In the library directory
$ yarn link   # creates a global link to the library

# In the example project that will use the library
$ yarn link your-package-name   # links the global link to the project

# Fix duplicate React issue
$ npm link ../example/node_modules/react
</code>
TypeScriptReactTree ShakingRollupES modulesWebpack comparisonJavaScript bundler
MaoDou Frontend Team
Written by

MaoDou Frontend Team

Open-source, innovative, collaborative, win‑win – sharing frontend tech and shaping its future.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.