DEV Community

Marcin Wosinek
Marcin Wosinek

Posted on • Updated on

Rollup 2 in a simple html+js use case

In this series, I'll take a look on a simple usecase of js+html application, build with various js bundlers. In earlier articles, we've seen how far we can get without any bundler and how it goes wepback & esbuild. Here we will take look on rollup.js.

Rollup 2

Rollup seems to be in an interesting point - on many metrics just after webpack - second most popular, second oldest:

npm trends for bundlers


but in the same time, seems it's not generating as much excitement as some newer tools - like discussed previously esbuild. But it's still worth taking a look - just because of it's popularity, you can come across it in some project.

The app

application screenshot

same as other articles of this series, simple app with 1 component with template & data in separate files.


The main html file is simple:

<!-- index.html -->
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Contact App</title>
    <link rel="shortcut icon" href="#" />

    <script type="module" src="./dist/index.js"></script>
    <link rel="stylesheet" href="style.css" />
Enter fullscreen mode Exit fullscreen mode

the source file, ./dist/index.js has to be match to what we set as output in rollup.config.js.

Main js file:

// src/index.js
import "./contact-list/contact-list";
Enter fullscreen mode Exit fullscreen mode

no surprise here, rollup behaves in the same way we are already accustomed by other bundlers.

The component

The component is broken down into 3 files. By default, rollup supports JS files only. For JSON & HTML, we will need to install a plugin & set up configuration.

// src/contact-list/contact-list.js
import template from "./contact-list.html";
import contacts from "./data.json";

const contactList = document.createElement("div");

contactList.className = "contact-list";

contacts.forEach((entry) => {
  const element = document.createElement("div");
  element.className = "contact";

  element.innerHTML = template;

  element.querySelector(".name").innerHTML =;
  element.querySelector(".phone").innerHTML =;


Enter fullscreen mode Exit fullscreen mode

So far, each bundler works with the same application code - that's very good for migrations if we ever decide going from building with one tool to some other.

Even for JSON files, rollup needs an aditional library - a json plugin. The installation & configuration will be covered below.

src/contact-list/data.json, the data file:

    "name": "Christopher L Sanders",
    "phone": "769-232-1807"
    "name": "Frances J Nolte",
    "phone": "901-287-0419"
Enter fullscreen mode Exit fullscreen mode

HTML files, where the source of the biggest confusion for me. Looks that I'm very used to webpack's html-loader, and it's way of thinking. The rollup's core html plugin seems to do slightly different thing. In the end I got my template as a string into js by a combination of @rollup/plugin-babel & babel's plugin babel-plugin-transform-html-import-to-string. This solution felt pretty over engineered to me - I'm either very off with how I approached the problem, or I was trying to force rollup to behave in a way it would rather not. I guess, in cases when you use reacts' jsx or tsx, it feels much smoother, because you don't move template out of js.

<!-- src/contact-list/contact-list.html -->
<h2 class="name">name</h2>

<p class="phone">phone</p>
Enter fullscreen mode Exit fullscreen mode

Build dependencies & configuration

For a successful build of the above code, we need quite a few things. To install them all:

$  npm install --save-dev @babel/preset-env @rollup/plugin-babel @rollup/plugin-json rollup babel-plugin-transform-html-import-to-string
Enter fullscreen mode Exit fullscreen mode

The configuration:

// rollup.config.js
import { babel } from "@rollup/plugin-babel";
import json from "@rollup/plugin-json";

const config = {
  input: "src/index.js",
  output: {
    format: "esm",
    file: "dist/index.js",
  plugins: [
      exclude: "node_modules/**",
      presets: ["@babel/preset-env"],
      plugins: ["babel-plugin-transform-html-import-to-string"],
      extensions: [".js", ".html"],

export default config;
Enter fullscreen mode Exit fullscreen mode

That is a bit disappoiting - especially if you heard horror storries about wepback confiuration, here even simple usecase requires a lot of configuration.

For easy access to build script, you can add following line to package.json:

  "scripts": {
    // other scripts
    "build": "rollup -c rollup.config.js"
Enter fullscreen mode Exit fullscreen mode

succesful build:

$ npm run build

> rollup@1.0.0 build
> rollup -c rollup.config.js

src/index.js → dist/index.js...
babelHelpers: 'bundled' option was used by default. It is recommended to configure this option explicitly, read more here:
created dist/index.js in 301ms
Enter fullscreen mode Exit fullscreen mode

Complete code & application example

If you want to see the application in action in the browser you can see it here:

and for the working code example you can go here:

Top comments (0)