ā† Return home

Bundle your React app with Rollup.js

Promo

According to Tooling.Report maintained by GoogleChromeLabs , Rollup.js performs better than other bundlers.

Screenshot 2020-11-24 at 4.50.30 PM

In this blog post, we will see how to bundle a React.js app with rollup.js.

Let's start

Make sure that you have installed a node.js version in your machine. Nvm makes things easier and allows us to have multiple versions of node.js in our machine.

Let's install the latest stable nodejs version:

1nvm install stable
2Now using node v15.3.0 (npm v7.0.14)

Cool! We're ready to go.

Setup your project:

1mkdir react-rollup-app
2cd react-rollup-app
3npm init

The above command will create the initial package.json. We're going to enhance this file later.

package.json

1{
2  "name": "react-rollup-app",
3  "version": "1.0.0",
4  "description": "A react app bundled with rollup.js",
5  "main": "index.js",
6  "scripts": {
7    "test": "echo \"Error: no test specified\" && exit 1"
8  },
9  "author": "John Dusaitis",
10  "license": "MIT"
11}

Create the html file which will host your React.js app.

index.html

1<!doctype html>
2<html lang="en">
3  <head>
4    <meta charset="utf-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6    <title>Your React app bundled with Rollup.js</title>
7  </head>
8  <body>
9    <div id="app"></div>
10  </body>
11</html>

Open it with your browser:

image1-01

That's a good start, but soon or later you'll need a web server to load other static files such as javascript and css files.

How rollup.js works?

It's pretty simple:

  1. It takes an input file with your code
  2. It performs some actions to your code based on the provided plugins you gave
  3. It produces one or more output files

Give me a dead simple example

OK, fair! Let's change the body background colour of our page.

src/index.js

1document.body.style.backgroundColor = "yellow";

Install rollup and some plugins for development

Rollup.js comes with a variety of plugins and one of them can play as web server to host all your static files. We will also need another one which reloads the page after each edit of our javascript files.

Install rollup and the above 2 plugins:

npm i rollup rollup-plugin-serve rollup-plugin-livereload --save-dev

Create the rollup configuration file:

rollup.config.dev.js

1import serve from 'rollup-plugin-serve';
2import livereload from 'rollup-plugin-livereload';
3
4export default {
5  input: 'src/index.js',
6  plugins: [
7    serve({
8      open: true,
9      verbose: true,
10      contentBase: ['', 'dist'],
11      historyApiFallback: true,
12      host: 'localhost',
13      port: 3000
14    }),
15    livereload({ watch: 'dist' })
16  ],
17  output: {
18    file: 'dist/bundle.js',
19    format: 'iife',
20    sourcemap: true
21  }
22};

In our case the output file dist/bunlde.js will be used by our index.html to run the javascript code.

Include it to your index.html file:

index.html

1<!doctype html>
2<html lang="en">
3  <head>
4    <meta charset="utf-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6    <title>Your React app bundled with Rollup.js</title>
7  </head>
8  <body>
9    <div id="app"></div>
10    <script src="/dist/bundle.js"></script>
11  </body>
12</html>

Add the build:dev script to package.json

package.json

1{
2  ...
3  "scripts": {
4    "build:dev": "rollup -c rollup.config.dev.js -w"
5  }
6  ...
7}

and run the command npm run build:dev.

This command, will load our yellow page to localhost:3000.

Screenshot 2020-11-24 at 7.08.06 PM

So far, so good. Now it's time to run some React code.

Setup your React code

Install the react and react-dom libs:

npm i react react-dom

Create your first React component:

src/App.jsx

1import React, { useState } from 'react';
2
3const App = () => {
4  const [counter, setCounter] = useState(0)
5  return (
6    <div>
7      <h4>A react page bundled with Rollup.js</h4>
8      <br />
9      <h1>Counter: {counter}</h1>
10      <br />
11      <button onClick={()=>{setCounter(counter+1)}}>+ Increase</button>
12      <br />
13      <button onClick={()=>{setCounter(counter-1)}}>- Decrease</button>
14    </div>
15  );
16};
17
18export default App;

Edit the src/index.js to run the react code.

src/index.js

1import React from 'react';
2import ReactDOM from 'react-dom';
3import App from './App';
4
5const root = document.querySelector('#app');
6
7ReactDOM.render(<App />, root);

Run the build script again:

npm run build:dev

Screenshot 2020-11-25 at 1.42.38 AM

Hmmm, error No #1. <App /> Unexpected token..

This happens because JSX is not valid JavaScript and must be transpiled to valid JavaScript. Babel is one of the most popular JavaScript tranpilers out there.

Babel also allow us to write modern JavaScript. It converts ES6/ES7 to older versions such as ES5 which are compatible with old browsers.

Install babel and the related react-preset.

npm i babel @babel/preset-react @rollup/plugin-babel --save-dev

Edit the rollup.config.dev.js

1import serve from 'rollup-plugin-serve';
2import livereload from 'rollup-plugin-livereload';
3import babel from '@rollup/plugin-babel';
4
5export default {
6  input: 'src/index.js',
7  plugins: [
8    babel({
9      presets: ['@babel/preset-react']
10    }),
11    serve({
12      open: true,
13      verbose: true,
14      contentBase: ['', 'dist'],
15      historyApiFallback: true,
16      host: 'localhost',
17      port: 3000
18    }),
19    livereload({ watch: 'dist' })
20  ],
21  output: {
22    file: 'dist/bundle.js',
23    format: 'iife',
24    sourcemap: true
25  }
26};

Run again the build script:

npm run build:dev

Screenshot 2020-11-25 at 2.06.22 AM

Error No #2. (!) Unresolved dependencies . The packages react and react-dom cannot be found.

To overcome this issue, we need another rollup plugin. The @rollup/plugin-node-resolve.

npm i @rollup/plugin-node-resolve --save-dev

add it to rollup.config.dev.js:

1import serve from 'rollup-plugin-serve';
2import livereload from 'rollup-plugin-livereload';
3import babel from '@rollup/plugin-babel';
4import { nodeResolve } from '@rollup/plugin-node-resolve';
5
6export default {
7  input: 'src/index.js',
8  plugins: [
9    nodeResolve({
10       extensions: ['.js', '.jsx']
11    }),
12    babel({
13      presets: ['@babel/preset-react']
14    }),
15    serve({
16      open: true,
17      verbose: true,
18      contentBase: ['', 'dist'],
19      historyApiFallback: true,
20      host: 'localhost',
21      port: 3000
22    }),
23    livereload({ watch: 'dist' })
24  ],
25  output: {
26    file: 'dist/bundle.js',
27    format: 'iife',
28    sourcemap: true
29  }
30};

Run again the build script:

npm run build:dev

Screenshot 2020-11-25 at 2.24.14 AM

Error No #3, name exports, this time. Let's fix it.

For this we need the @rollup/plugin-commonjs plugin which converts CommonJS modules to ES6.

npm i @rollup/plugin-commonjs --save-dev

add it to rollup.config.dev.js:

1import serve from 'rollup-plugin-serve';
2import livereload from 'rollup-plugin-livereload';
3import babel from '@rollup/plugin-babel';
4import { nodeResolve } from '@rollup/plugin-node-resolve';
5import commonjs from '@rollup/plugin-commonjs';
6
7export default {
8  input: 'src/index.js',
9  plugins: [
10    nodeResolve({
11       extensions: ['.js', '.jsx']
12    }),
13    babel({
14      presets: ['@babel/preset-react']
15    }),
16    commonjs({
17      include: ['node_modules/**']
18    }),
19    serve({
20      open: true,
21      verbose: true,
22      contentBase: ['', 'dist'],
23      historyApiFallback: true,
24      host: 'localhost',
25      port: 3000
26    }),
27    livereload({ watch: 'dist' })
28  ],
29  output: {
30    file: 'dist/bundle.js',
31    format: 'iife',
32    sourcemap: true
33  }
34};

Let's run the build script again:

npm run build:dev

Screenshot 2020-11-25 at 2.49.14 AM

The build was successful. But, there's a last error in the page.

Screenshot 2020-11-25 at 2.54.25 AM

Error No #4, Uncaught ReferenceError: process is not defined. In order to fix this issue, we need a last plugin. The @rollup/plugin-replace which replaces strings in files while bundling.

npm i @rollup/plugin-replace --save-dev

Include it to the rollup config file:

rollup.config.dev.js

1import serve from 'rollup-plugin-serve';
2import livereload from 'rollup-plugin-livereload';
3import babel from '@rollup/plugin-babel';
4import { nodeResolve } from '@rollup/plugin-node-resolve';
5import commonjs from '@rollup/plugin-commonjs';
6import replace from '@rollup/plugin-replace';
7
8export default {
9  input: 'src/index.js',
10  plugins: [
11    replace({
12      'process.env.NODE_ENV': JSON.stringify('development')
13    }),
14    nodeResolve({
15       extensions: ['.js', '.jsx']
16    }),
17    babel({
18      presets: ['@babel/preset-react']
19    }),
20    commonjs({
21      include: ['node_modules/**']
22    }),
23    serve({
24      open: true,
25      verbose: true,
26      contentBase: ['', 'dist'],
27      historyApiFallback: true,
28      host: 'localhost',
29      port: 3000
30    }),
31    livereload({ watch: 'dist' })
32  ],
33  output: {
34    file: 'dist/bundle.js',
35    format: 'iife',
36    sourcemap: true
37  }
38};

Let's run the build script again:

npm run build:dev

Screenshot 2020-11-25 at 3.06.29 AM

šŸš€ Congrats! You have your first React & Rollup.js app is up and running. šŸš€

Find the full source code at my github repo.

And the live working example at https://dusaitis.co/react-rollup-app/index.html

Thanks for reading.

Would you like to get updates for new stories?