Originally posted on my blog.
Front-End development has become extremely interesting and fun to do with the beginning of the ECMAScript and NPM era. There is a lot of packages and tools out there that we can use in our projects that can make our life easier. One of these tools is rollup.js.
Let's start the article with a short introduction and find out what rollup actually is and what it does for us and our application.
The official statement:
Rollup is a module bundler for JavaScript which compiles small pieces of code into something larger and more complex, such as a library or application. It uses the new standardized format for code modules included in the ES6 revision of JavaScript, instead of previous idiosyncratic solutions such as CommonJS and AMD.
Let's break down the statement above.
Rollup is a module bundler for JavaScript which compiles small pieces of code into something larger
Developing an application is a lot easier if we split it into logically independent smaller pieces. That way we reduce the overall complexity of our code during development thus making it more approachable and maintainable. It is easier and faster for someone to join the team if he/she can focus on the smaller part instead of analyzing the entire application logic and trying to isolate a specific code block. This can dramatically increase the possibility of errors after injecting a new piece of code in the middle of it which is something we do not want.
Rollup helps us solve the use case described above. It takes our small pieces and bundles them all together into a single code base. To do this, we can use the command line or a specific configuration file called rollup.config.js
.
In this article, I will cover a configuration file approach.
It uses the new standardized format for code modules included in the ES6
This is very neat. What this does is that enables us to write the import/export statements within our JavaScript files. We can import data, constants, functions, entire logic blocks...and all this we can write in the next generation of JavaScript and let rollup (and its plugins) worry about creating the browser readable output. It's possible to specify the output format, which we will see later in this post.
Just to summarize and answer the WHAT and WHY questions. Rollup is a JavaScript bundler (also can minify the output with a plugin) and we need it if we want to use the new syntactic sugar like import
and export
from the ECMAScript specification.
Note that the code below assumes that Node.js and NPM package manager had already been installed and that your application had been initialized with npm init
command.
Installing Rollup
To install rollup and save it as development dependency we should run the following command:
npm install rollup --save-dev
The command above will install the rollup node package and update the package.json
file located in our application root folder.
"devDependencies": {
"rollup": "^1.10.0" // the version might be different in your case depending on the time reading this
}
Next, create a new file called rollup.config.js
in the application root folder. Inside, add the following.
export default {
input: './src/main.js',
output: {
file: './build/bundle.min.js',
format: 'iife',
name: 'bundle'
}
}
Let’s see what each of these configuration options does for us:
input
- This is a required setup and it represents the file we want rollup to process. It should be the main entry point of the application where we import everything else required by it-
output
- It's an object like configuration where we set up the result of our processing. Minimum of the configuration is to include the:2.1
file
- This is the location where our bundle will be created. It represents the file to write to. Usually under thebuild
ordist
folder. The folder and the file will be generated automatically by rollup2.2
format
- Rollup supports several output formats. In our example, we will use an immediately-invoked function expression (iife)2.3
name
- Global variable name representing the created bundle
Other formats can be found here, section
output.format
Test the configuration
Now when we have our setup, we can test if everything works.
First, create a source folder, src
. This folder will contain our application source files. Inside of it, create the application entry point, a file called main.js
and the index.html
page.
Next, let's create a test module. In the src
folder, create a subfolder modules
and a file within called MyModule.js
. Inside, add the following:
const sayHello = (message) => {
alert(message);
}
export default sayHello;
In the main.js
file add the import statement and use the imported function:
import sayHello from './modules/MyModule';
sayHello('Hello from Rollup');
Open the package.json
file and add the following script under the script setting:
"scripts": {
"build": "rollup -c"
}
and run the following command:
npm run build
This will create a new folder called build
in our project that contains the generated bundle.min.js
file. We can see that the bundle was created properly by adding it as a reference to our index.html
page and opening it in the browser.
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<head>
<title>Rollup Example</title>
</head>
<body>
</body>
<script src="../build/bundle.min.js"></script>
</html>
If everything was done properly, an alert should popup immediately after opening the page.
At this point, only modern browsers will work without errors. To get this working with browsers that don’t support ECMAScript features, we need to include a couple of plugins.
Next Generation of JavaScript
Installing babel
In order to properly parse our module and make it compatible with older browsers, we should include babel to compile the output. If you are not familiar with it, babel is a JavaScript compiler and makes the next-gen JavaScript code cross-browser compatible by compiling it to the older version of it.
In order to continue with the example, we need to install the required packages:
npm install @babel/core @babel/preset-env rollup-plugin-babel --save-dev
The command above will update our dev dependencies like so:
// the versions might be different in your case depending on the time reading this
"devDependencies": {
"@babel/core": "^7.4.3",
"@babel/preset-env": "^7.4.3",
"rollup": "^1.10.0",
"rollup-plugin-babel": "^4.3.2"
}
Next, we need to create a babel configuration file .babelrc
in the application folder with the following content:
{
"presets": [
"@babel/env"
]
}
After these actions, babel is configured and ready for usage. Considering that this article is about rollup, visit the official babel site for more information.
Updating rollup.config.js
The above changes alone will do nothing because we did not tell rollup that it needs to use the newly installed packages. We do this by updating the rollup.config.js
file as shown below:
import babel from 'rollup-plugin-babel';
export default {
input: './src/main.js',
output: {
file: './build/bundle.min.js',
format: 'iife',
name: 'bundle'
},
plugins: [
babel({
exclude: 'node_modules/**'
})
]
}
We left the input
and output
configurations like they were before, added an import statement to include the rollup-plugin-babel
and introduced the plugins
config option. Plugins are used to customize rollup behavior. In this case, we want it to compile our ECMAScript into its predecessor.
Also, we've excluded the node_modules
folder to avoid third-party scripts and libraries being compiled. Now, we are ready to run our build command again:
npm run build
The expected result is that our bundle now should have different content which is cross-browser compatible.
The bundle.min.js
without babel:
(function () {
'use strict';
const sayHello = (message) => {
alert(message);
};
sayHello('Hello from Rollup');
}());
and with babel:
(function () {
'use strict';
var sayHello = function sayHello(message) {
alert(message);
};
sayHello('Hello from Rollup');
}());
Clearly, we can see the difference. Reserved word const
is no longer present and it has been converted to var
. Also, our arrow function
has been converted to a cross-browser compatible version.
After opening index.html
page in the browser, the result should be the same and a popup message should again be displayed.
Handling non-ES modules
So far our project was working without any node module dependency and the only module imported was the test one we've created. However, in the real world, this is rarely the case and our app would require a non-ES module.
Supporting the CommonJS modules is not provided out of the box by rollup, therefore we need a couple more plugins. In order to make our project to work with the node modules dependencies, we need to install the following packages:
npm install rollup-plugin-node-resolve rollup-plugin-commonjs --save-dev
The rollup-plugin-node-resolve
plugin allows us to load the third-party modules and the rollup-plugin-commonjs
plugin converts them into the ES6 version.
Our package.json
file should look like this:
// the versions might be different in your case depending on the time reading this
"devDependencies": {
"@babel/core": "^7.4.3",
"@babel/preset-env": "^7.4.3",
"rollup": "^1.10.0",
"rollup-plugin-babel": "^4.3.2",
"rollup-plugin-commonjs": "^9.3.4",
"rollup-plugin-node-resolve": "^4.2.3"
}
Updating rollup.config.js - part 2
Again, rollup needs to know that it needs to use the new plugins. We configure them the same way we did for the rollup-plugin-babel
plugin:
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
export default {
input: './src/main.js',
output: {
file: './build/bundle.min.js',
format: 'iife',
name: 'bundle'
},
plugins: [
babel({
exclude: 'node_modules/**'
}),
resolve(),
commonjs()
]
}
Installing the Third-Party Library
Now we are ready to install and use our first third-party dependency. lodash
for example. To install it, run the following command:
npm install lodash --save-dev
Our package.json
file should look like this:
"devDependencies": {
"@babel/core": "^7.4.3",
"@babel/preset-env": "^7.4.3",
"lodash": "^4.17.11",
"rollup": "^1.10.0",
"rollup-plugin-babel": "^4.3.2",
"rollup-plugin-commonjs": "^9.3.4",
"rollup-plugin-node-resolve": "^4.2.3"
}
Updating rollup.config.js - part 3
In order to use it, we again need to tweak the rollup.config.js
file a little bit. We need to tell the rollup that we are using an external library with a global variable _
. This is required since we are going to import it in our main.js
file. Update the config like so:
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
export default {
input: './src/main.js',
output: {
file: './build/bundle.min.js',
format: 'iife',
name: 'bundle',
globals: {
'lodash': '_',
}
},
plugins: [
babel({
exclude: 'node_modules/**'
}),
resolve(),
commonjs()
]
}
By adding the globals
configuration we made sure that rollup knows what to do with the external import.
Next, we should test to see if everything is working fine by trying to use the lodash library. For example, let's use the _concat
function.
Update the main.js
file like so:
import sayHello from './modules/MyModule';
import _ from 'lodash';
const arr = _.concat([1, 2, 3], 4, [5]);
sayHello('Hello from Rollup and lodash: ' + arr);
and run the build
command:
npm run build
The created bundle.min.js
should contain both modules. The test module we've created and the externally imported lodash
module.
If we run the index.html
page at this point we should see an alert with a different message. It should print the Hello from Rollup and lodash: 1,2,3,4,5
without problems.
Compressing the Output
It is not uncommon that production environments require a minified version of the final bundle. This is needed for various reasons like reduced size, loading speed, network delivery...etc. In order to do minify it, we need to install another plugin called rollup-plugin-uglify
:
npm install rollup-plugin-uglify --save-dev
Next, tell the rollup that it needs to use it by updating the rollup.config.js
for the 4th time in this example:
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import { uglify } from 'rollup-plugin-uglify';
export default {
input: './src/main.js',
output: {
file: './build/bundle.min.js',
format: 'iife',
name: 'bundle',
globals: {
'lodash': '_',
}
},
plugins: [
babel({
exclude: 'node_modules/**'
}),
resolve(),
commonjs(),
uglify()
]
}
and run the build command:
npm run build
Now, if we take a look at our bundle.min.js
file the code should be a lot less readable :) If you compare the file before and after minification there should be an obvious size difference.
Comming Up
In the next rollup article, I will cover importing of the CSS and HTML files.
Thank you for reading and see you in the next post.
Top comments (17)
lodash
exports as CommonJS (via UMD), so there's no need to configure rollup to grab it offwindow
... unless you're demonstrating how this can be done, and if that's the case, it might be helpful to point out that's why you did what you did and that normally (i.e. most modern packages) you'd justnpm / yarn install
your package and not have to muck with your bundler config at all.Also, no need to install all of lodash and blow up your bundle size with all its functions if you're just going to use a couple of functions from it; e.g.
lodash.concat
and all the other lodash functions are published individually.But then again, why use
_.concat
at all when your browser can already concat arrays pretty well without a library?Hi,
note that commonjs must be invoked before babel.
"When using @rollup/plugin-babel with @rollup/plugin-commonjs in the same Rollup configuration, it's important to note that @rollup/plugin-commonjs must be placed before this plugin in the plugins array for the two to work together properly."
github.com/rollup/plugins/tree/mas...
I'm confused, I don't see how to include the global css file (from .scss). I have a "main.scss" file that imports a bunch of helper scss files (colors, typogrpahy) etc.. and I want to bundle "main.scss" and have it in my main page so all my components get the "base" styles. I went to the other link (rollup cheatsheet) but I am not seeing you include a global.css file anywhere.. I"m confused as to where the solution is for installing a global css file.
I'm confused why you think the post is supposed to teach you how to configure rollup to bundle your css files... and why were you working with css files as late as October of 2020? en.wikipedia.org/wiki/CSS-in-JS
Good :)
Thanks 😊
hope to see the next article, and can you include multi input configure and css/less/sass html files import
Hi, I didn't post it on dev.to, but I've created a rollup cheat sheet that includes the CSS handling. You can check it out here. It's a shortened version of this post and, as an addition, it includes the CSS configuration.
Regarding the HTML, you can see the plugin in action on this repo.
Sure, will include css/sass/html combination.
A year later, but still very useful article. Thanks a lot
No problem :)
Your IIFE output config doesn't work since the IIFE format also requires the
name
option to be set.Yes, I didn't update the article, but it's updated here though.
I will update this one too. Thanks for pointing out. In earlier versions, the name wasn't required.
EDIT: The
name
has been added to theoutput
objectNice one mate, awesome article :)
Thanks! Glad you find it useful
how run development mode by rollup?
Awesome write up. Exactly what I was looking for!