Introduction
React is one of the most popular libraries out there to create interactive UIs in today's fast-paced and modern technological world. One of the core features of React that makes it intuitive enough to work with is JSX. JSX is simply a syntax extension to JavaScript, which has to be processed by some kind of a tool before the code could be sent to a browser for execution.
This preprocessing of JSX is the job of transpilers, the most common one being Babel. However, almost no one uses Babel as a standalone tool — more often than not, it's used together with a bundler.
Now what on Earth is a bundler?
Well, from the perspective of a web application, a bundler tool is simply a means of taking all the multiple JavaScript files involved in building the application and then bundling them together into one single JavaScript file to be served to the client.
This, as you can reason, improves the network latency of the app, and also improves the loading times of the app. In this article, we'll see how to install and set up Rollup, a bundler tool, to help us build React applications.
What is Rollup?
You might've heard of Webpack as a bundler from discussions on the setup of React. Rollup is a lightweight alternative to Webpack.
At its core, Rollup is a bundler software that helps us bundle JavaScript modules together.
Its distinctive feature is that it's designed to work with ECMAScript modules.
The official website of Rollup, rollupjs.org is a really nice source of information for bundling in general and for Rollup's setup.
Rollup may be lighter in weight and complexity than Webpack, but by no means is it an elementary bundler. No. Rollup is definitely a complex module bundler software that comes equipped with numerous bells and whistles for different kinds of bundling concerns.
It's surely worth a try.
The React application
Before we dive into exploring how to get Rollup set up to bundle a React application, let's first define some starting code that'll eventually get bundled in the following sections.
Go ahead and create a project1
directory anywhere on your operating system where you find it convenient to access, usually which is just the Desktop.
Then create the following set of files in it:
If you've worked with React before, you'll surely know that this file setup is simply meant to neatly structure our React application.
All the source files go in the src
directory while the public-facing files go in the public
directory.
The node_modules
directory is created automatically by Node, while the package.json
file (and package-lock.json
) is necessary to describe the project and all of its package dependencies.
Quite basic.
Here's the code of the index.js
file:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
ReactDOM.createRoot(document.querySelector('#root')).render(
<App/>
);
It simply loads another file's exported App
component and renders it inside a #root
DOM element.
Here's the code of App.js
:
import React from 'react';
function App() {
return (
<h1>Rollup is amazing!</h1>
);
}
export default App;
And here's the code of index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Project 1</title>
</head>
<body>
<div id="root"></div>
<script src="bundle.js"></script>
</body>
</html>
Take note of the <script>
tag at the end of <body>
here. It refers to a file called bundle.js
in the public
directory, which as of yet doesn't exist.
Our bundling process will end up with a bundle.js
file in public
which'll eventually allow us to run the React application.
Here's the content of the package.json
file:
{
"name": "project1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@babel/core": "^7.21.3",
"@babel/preset-react": "^7.18.6",
}
}
As is apparent by this file, we are assuming that we have the following packages already installed in our setup: react
and react-dom
for React, and @babel/core
and @babel/preset-react
to be able to convert JSX in normal JavaScript code.
With this setup understood, let's now move over to installing Rollup.
Installing Rollup and its plugins
Installing Rollup is superbly simple.
Navigate to the project1
directory that you created above and run the following command:
.../project1> npm install rollup --save-dev
This installs the rollup
package as a developer dependency (because of the --save-dev
flag).
We install rollup
as --save-dev
since it isn't used while running the application — rather it's only used when building the app and, likewise, it's only required by a developer working with the application's code.
Anyways, moving on, with rollup
installed, now we have to install four Rollup plugins that'll help us bundle our React applications.
These plugins are described as follows:
@rollup/plugin-node-resolve
When we have an absolute import in a module file such as import 'react'
, we technically want the underlying bundler to know how to extract the desired package from the node_modules
directory. This is known as Node's module resolution algorithm.
Rollup, by default, doesn't know of or use this algorithm to resolve absolute imports.
In order to get it to do so, we need the node-resolve
plugin which tells Rollup how to find packages/modules in the node_modules
directory.
@rollup/plugin-commonjs
By design, Rollup is meant to work with ECMAScript modules, i.e. the ones with import
and export
keywords. It's not designed to be paired with CommonJS modules, like the react
package.
To be able to process CommonJS modules using Rollup, we ought to tell it that it needs to parse a CommonJS module. And this is done via the commonjs
plugin.
@rollup/plugin-babel
As we stated at the start of this article, React uses JSX which ought to be processed before it could be run. The de facto JSX preprocessor in use across the globe is Babel.
To use Babel along with Rollup, we need the babel
plugin which automatically loads Babel and runs it based upon a .babelrc.json
file at the project's root or based upon configurations sent into the plugin right at the time of its invocation (which we'll see shortly below).
@rollup/plugin-replace
There is a special processing that needs to be done in order to be able to work with React packages. That is, the react
package has a statement in it that refers to a property env
on a global variable called process
.
If you're experienced with Node.js, you'll realize that this statement won't work in the browser as it accesses the process
variable which is only available in Node.js. In order to get our React program to run without any errors in the browser, we need to replace this statement with a dummy value. That's what the replace
plugin is used for.
With the purpose of each of these plugins clear, let's go on and install all four of them.
Here's the command to run:
.../project1> npm install @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-babel @rollup/plugin-replace --save-dev
As with the rollup
package, don't forget to include the --save-dev
flag while installing these plugins, as they're all tied to Rollup which itself is a dev dependency.
With all the plugins installed, we are now left with configuring Rollup. And that means to create a rollup.config.mjs
file at the project's root.
Configuring Rollup
Go ahead and create a rollup.config.mjs
file at the root of the project's directory.
Rollup uses this configuration file before it performs the bundling process. The structure of the file is really simple. The default export of the file, which is merely a pure object, specifies all of the settings that we want to have in our bundling routine.
Here is a description of some of the most common properties of this exported object:
-
input
specifies the path of the input file. -
output
specifies an object containing two properties:file
that tells about the destination file path andformat
that provides the format of the output file. Possible values for format are 'iife', 'umd', 'cjs', etc. - The
plugins
property is a list of all plugins to use in our Rollup setup.
Let's now get our rollup.config.mjs
set up:
import nodeResolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import replace from '@rollup/plugin-replace';
export default {
input: 'src/index.js',
output: {
file: 'public/bundle.js',
format: 'iife'
},
plugins: [
nodeResolve({
extensions: ['.js']
}),
babel({
babelHelpers: 'bundled',
presets: ['@babel/preset-react'],
extensions: ['.js']
}),
commonjs(),
replace({
preventAssignment: false,
'process.env.NODE_ENV': '"development"'
})
]
}
Here's what's happening here:
Firstly, since the input file is index.js
in the src
directory, the value of input becomes 'src/index.js'
.
Secondly, since we want the bundled file to be called bundle.js
in the public
directory, the value of the file
property of output
becomes 'public/bundle.js'
. The format
is chosen as 'iife'
because it's pretty basic of a setting.
Moving on, next we have a sequence of all the plugins to load in order to correctly bundle the React application.
With this configuration file set up, go on and add a build
script in the package.json
file to be able to quickly and conveniently run the rollup
command for the bundling:
{
"name": "project1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "rollup -c -w",
"test": "echo \"Error: no test specified\" && exit 1"
},
...
}
In the command rollup -c -w
, the -c
flag tells Rollup that there is a configuration file it should use to understand the desired bundling process, while the -w
flag instructs it to watch all the files involved in the bundling and then automatically rerun the bundling process as soon as any one of them changes.
Now, let's run this build
command and let the magic happen:
.../project1> npm run build
Once the bundling is complete, we could open up the index.html
file in the browser to see the app running. But before we do that, let's install the serve
package so that the public
directory is served on a localhost server.
Technically, React could be used without spinning up a localhost server, but it's a recommendation, the absense of which raises a warning in the console, and so we'll do it. It's really simple, thanks to the serve
package.
Run the following command to install serve
:
.../project1> npm install serve
Next up, define the start
script in package.json
to the string 'serve ./public'
, in order to run the serve
command, serving up the public
directory:
{
"name": "project1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "rollup -c -w",
"start": "serve ./public",
"test": "echo \"Error: no test specified\" && exit 1"
},
...
}
Now when we execute the npm start
command, the serve
package would fire up, serving the public
directory over localhost.
Let's get that done:
.../project1> npm start
And now we could view our application in the browser by navigating to localhost:3000.
Perfect.
In the end
So this was it for setting up Rollup to be able to work with React applications. Rollup is, without any doubt whatsoever, an awesome tool to use as an alternative to Webpack, which can get really complex at times.
What's best about using Rollup is that it gets frequent updates and has an active developer community behind it and so we could expect some nice oven-freshness in this lightweight bundler tool.
If you want to ramp up your Rollup's setup, you could create a task in VSCode to call the npm build
command via a quick keyboard shortcut. VSCode is really configurable and that's something we as developers must leverage.
Have a great time coding in React. 🙂
And don't forget to check out the list of some awesome courses on programming at CodeGuage, crafted comprehensively and absolutely free to learn from.
Top comments (0)