Common problem: you are writing a library that you want to reuse in Node and maybe in a browser. You want the client apps to be able to include only the used parts, and not your entire code. How do you do this?
A great tool for this is Rollup. If your library uses ES2015 modules
(think import
and export
keywords), then Rollup can perform static analysis and determine
which pieces are reachable and can drop everything else, making the tiny output bundle.
Write the library
First let us write a sample library, for example named try-rollup
with two functions add
and mul
. Our single index.js
will export both
1 | // try-rollup index.js |
We can bundle this module so it is usable as a plain Node module for distribution. This is
simple enough to use "rollup" from the command line. In addition, I will set
the main file in my package.json
to point at the created bundle.
1 | { |
Command npm run build
creates an output file that looks almost like the input file index.js
,
but is compatible with Node CommonJS require
call
1 | // dist/index.js |
The most important field in package.json
is module
that points back at our original ES6 source
file index.js
. When we distribute our library we include the CommonJS bundle and the entry file
index.js
(by listing them both in files
list).
The users of our library try-rollup
can use Rollup
or Webpack v2 to bundle their code and the tools can go back to the original ES6 code and do the
application tree-shaking again, see
Rollup module doc.
Use the library
Let us write a small Node client application called try-rollup-user
that uses try-rollup
.
For simplicity I will install try-rollup
from the file system folder, without publishing to the
public NPM registry. I also need Rollup again. Because the module try-rollup
goes into
node_modules
folder, I will need a Rollup plugin to actually find it (since Rollup supports
many different module definitions).
In our case it is node-resolve plugin
1 | npm i -D rollup rollup-plugin-node-resolve ../try-rollup |
The package.json
shows the build command - now I need to use the
[Rollup config file][https://rollupjs.org/#using-config-files]
to configure the build step
1 | { |
To execute the result we point Node at the output file build/index.js
.
The Rollup config file just reads the entry file and uses the Node resolve plugin for any
module installed using npm install
command.
1 | // rollup.config.js |
Bundle and run
Let us say our app is very simple and only uses mul
function from try-rollup
and nothing else.
1 | // index.js |
The build step generates tree-shaken file in CommonJS format
1 | // "npm run build" which runs "rollup -c" |
That is it - Rollup finds node_modules/try-rollup
, loads package.json
, finds the module
property and looks at the original ES6 source files, which can be analyzed and tree-shaken.
This is how we get mul
from try-rollup
and nothing else in the output file.
Bonus - Bundle ES6
You can roll and distribute 2 bundles: one with CommonJS code and another one with ES6 modules
without distributing your entire source. This is especially helpful if your library depends
on other ES6 libraries and can benefit from tree-shaking itself. Make sure to save your
dependencies as devDependencies
because we will include them in the generated bundle.
Because Rollup does not support multiple bundles right away (but you can write separate Rollup
commands of course), I will use my tool rollem.
Here is the rollem.config.js
file that defines two output bundles: one in CommonJS format,
another in ES6 format.
1 | // rollem.config.js |
We are only going to distribute these bundles, and not the original files (see files
list)
1 | { |
1 | $ npm run build |
We can install and use the new try-rollup
just like before - nothing changes in the client code
except the install gets just three files:
1 | $ ls -lR node_modules/try-rollup |
Tree-shaking all the way!
Double bonus - Multiple targets using Rollup
Rich Harris, the author of Rollup, pointed that you can output
multiple formats from same entry point using rollup.config.js
, even reusing the filenames
defined in the package file.
1 | // rollup.config.js |
This is my favorite syntax :)