Rollup-based dev environment for JavaScript (part 1)



  • We will need Node.js current or, at least, lts, as well as an up-to-date package manager such as yarn or npm. In my examples, I will use npm.
  • Our app directory should be created with a package.json file (npm init), directories public/, public/js/ and src/ .
  • Commands should be run from the root of the app directory unless specified otherwise.

Directory structure

  • Web server root will be public/
  • Rollup will output our builds in public/js/
  • source code will go in src/


Babel will convert our ES201* + JSX + Flow codebase into code comprehensible by our targets: the browsers and platforms we want to support.
It uses plugins and presets to do its job, and can be configured in a .babelrc file in your app directory.

npm install --save-dev @babel/cli @babel/core @babel/plugin-proposal-class-properties @babel/plugin-syntax-dynamic-import @babel/plugin-transform-runtime @babel/preset-env @babel/preset-flow @babel/preset-react
  • preset-env is configured to target browsers with at least .25% global usage, except opera mini,
  • we specifically need dynamic import (for code splitting), object rest spread and class properties (commonly used with React class components).


Rollup is a module bundler which will transform, tree-shake and regroup our ES modules into optimized chunks to be fed to (in our case) browsers.

npm install --save-dev rollup rollup-plugin-babel rollup-plugin-commonjs rollup-plugin-clear rollup-plugin-node-builtins rollup-plugin-node-globals rollup-plugin-node-resolve rollup-plugin-replace rollup-plugin-terser
rollup -c --prod --mini # will build for production
rollup -c # will build for development


Notice the namedExports property in the commonJS plugin. When we import (with the ES2015 syntax) named exports from CJS modules, Rollup does its best to find the right value, but sometimes fails to do so (in my experience anyway). In that case, you need to explicitly define exports here.


src/index.jsx will be our “entrypoint”. Some might call it “main.jsx” or “app.jsx” but you get the point: this is where execution should start.
You can have multiple entrypoints (read more in the Rollup docs).


We use 2 output formats : ESM (ES modules) for browsers that support dynamic import, system for those that don’t.

Code splitting

When Rollup sees a dynamic import("...") statement in your code, it will automatically create a separate “chunk” in your bundle.
Additionally, React provides an API for lazily loading components, you can read about it here.


There are many others plugins (for livereload, etc.). If you want to try some, start here.

Loading our bundles from index.html

Right now, ES dynamic import support is far from the norm. It is supported on Chrome, but still behind a flag in Firefox 66, and will never make it to IE11.
This means we need to have a fallback: thus, SystemJS.


Flow is a static type checker. If you haven’t used one before, the main idea is that a type checker doesn’t seem very time efficient to present you, but it’s a life saver to future you (meaning: when refactoring).

npm install --save-dev flow-bin
npm install -g flow-typed
flow-typed install # will create a flow-typed/ directory


Serve will be our http server. Again, there are many alternatives, but we need something that can provide some configuration over headers and redirects (in the case of an SPA).

npm install --save-dev serve


We can use npm scripts to alias some of our most useful commands. This will be helpful later when we setup CI/CD.
Add this in the “scripts” section of package.json:

npm run build # production build
npm run watch # dev loop
npm run serve # then browse to http://localhost:5000



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store