2018 is a great year for JavaScript and development in general! The clientside framework options abound with Vue, Angular, and React.
Serverside options include Koa, vanilla Node, Express, Hapi, Total, Restify, and AWS Lambda.
To top it all off, the coterminous developments in build and transpilation tools have significantly widened the field. While, old timers like Gulp, Grunt, and Browserify remain relevant, we'll take a close look at Parcel, Rollup, and the newly released webpack 4!
OK, let's set up our package.json
by adding Babel, which will be used, in some capacity, by each of the three tested build tools:
Shared babel
dependencies:
"babel-loader": "=7.1.4",
"babel-plugin-external-helpers": "=6.22.0",
"babel-preset-env": "=1.6.1",
"babel-preset-react": "=6.24.1",
"babel-preset-stage-0": "=6.24.1"
Babel provides transpilation support for translating newer ES6
and ES7
syntax into 2018 web-browser compliant ES5
. Babel provides this support for other JavaScript dialects through babel-presets
along with polyfills
and shims
.
Once we've added Babel, we need to supplement our project with the following .babelrc
in our project root:
{
"presets": ["env", "react", "stage-0"]
}
Parcel was recently released and provides an incredibly light-weight, almost configuration-free, build tool. We add the following parcel
dependencies to our package.json
:
"parcel-bundler": "=1.7.1"
The core difference here between Parcel and webpack 4 is that we directly set the index.js
file into the script.scr
of our index.html
or view rather than the compiled bundle.
In other words, we would put:
<script src="../reactAppSrc/index.js"></script>
Rather than:
<script src="built/vendor.min.js"></script>
<script src="built/built.min.js"></script>
We can then run the following command to transpile our dependencies:
$ parcel index.html
For production
builds:
$ parcel build public/parcel.index.html
The magic behind Parcel is that it will automatically build a dependency and script tree then proceed to transpile, minify, and bundle those assets as needed without any human configuration required.
Parcel also caches both its build processes, vastly decreasing build time on subsequent runs.
Rollup represents another recent addition and alternative. Users who've used webpack will find Rollup's configuration familiar and easy to set up:
We add the following Rollup dependencies:
"rollup": "=0.58.2",
"rollup-plugin-babel": "=3.0.4",
"rollup-plugin-uglify": "=3.0.0"
For Development
:
$ rollup -c rollup/rollup.dev.config.js --external all
import babel from 'rollup-plugin-babel';
export default {
entry: 'reactAppSrc/rollup.index.js',
dest: 'public/built/main.min.js',
format: 'iife',
plugins: [
babel({
babelrc: false,
exclude: 'node_modules/**',
presets: [
"react",
[
"es2015",
{
"modules": false
}
]
],
"plugins": [
"external-helpers"
]
})
],
};
For Production
:
$ rollup -c rollup/rollup.prod.config.js --external all
import babel from 'rollup-plugin-babel';
import uglify from 'rollup-plugin-uglify'
export default {
entry: 'reactAppSrc/rollup.index.js',
dest: 'public/built/main.min.js',
format: 'iife',
sourceMap: 'inline',
plugins: [
babel({
babelrc: false,
exclude: 'node_modules/**',
presets: [
"react",
[
"es2015",
{
"modules": false
}
]
],
"plugins": [
"external-helpers"
]
}),
uglify()
],
};
webpack dependencies:
"webpack": "=4.6.0",
"webpack-cli": "=2.0.15"
The release of webpack 4 continues to see significant improvements and simplified configuration:
'use strict'
const path = require('path'),
webpack = require('webpack')
module.exports = {
mode: 'production',
entry: './reactAppSrc/index.js',
output: {
path: path.resolve(__dirname, '../public/built/'),
filename: '[name].min.js',
},
resolve: {
extensions: ['.js', '.jsx'],
},
module: {
rules: [
{
test: /\.jsx$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
},
plugins: []
}
Here, we just need to switch the mode
attribute by running one of the following two commands:
$ webpack --config webpack/webpack.dev.config.js --progress --profile --colors
$ webpack --config webpack/webpack.prod.config.js --progress --profile --colors
All three libraries were tested and built on the following Dell 15 XPS 2016 with specs:
Intel Core i7-6700HQ Quad-Core (8 Logical Cores) at 2.60 GHz 32 GB RAM Windows 10 Pro + Linux Subsystem and Cygwin NVIDIA 960M GPU 256GB m2 PCIe SSD 15.6" FHD Screen
Results divided into Development
and Production
modes:
Tool | Dev Build Time One | Dev Build Time Two | Dev Build Time Three | Dev Build Time Avg |
---|---|---|---|---|
Parcel | 14.92 s | 5.22 s | 4.36 s | 8.16 avg s |
Rollup | 0.570 s | 0.482 s | 0.487 s | 0.513 avg s |
Webpack | 3.608 s | 3.328 s | 3.844 s | 3.59 avg s |
Best: Rollup (0.513 avg s)
Production
mode:
Tool | Prod Build Time One | Prod Build Time Two | Prod Build Time Three | Prod Build Time Avg |
---|---|---|---|---|
Parcel | 738.509 s | 35.364 s | 35.592 s | 269.82 avg s |
Rollup | 0.712 s | 0.665 s | 0.714 s | 0.697 avg s |
Webpack | 3.636 s | 3.805 s | 4.305 s | 3.915 avg s |
Best: Rollup (0.697 avg s)
Above, we compare raw build time alone, but there are several other highly relevant considerations:
mode
attribute (which will enforce minification when set to 'production' automatically now).Overall, Parcel's a fantastic choice for small projects since it requires zero configuration.
webpack 4 represents a great improvement in the tradition of a tried and true workhorse. It's also largely interchangeable with webpack 3 configuration which simplifies migration.
The big winner is Rollup which represents the next generation of build tools in terms of its performance (build time), intermediate configuration (less complicated than webpack but more involved than Parcel), and optional but out-of-the-box features likes source maps, and not using a .babelrc.
For brand new projects, I'd strongly encourage taking a look at Rollup!
Check out GitHub for the all the code used in this article!