Webpack vs. Browserify: The Ultimate Showdown
When using perk you have the option of either Webpack or Browserify. This in itself isn't that different from other frameworks, but my reasoning for including both might be. For other technology decisions I picked what I thought was the best tool for the job. I chose knex over sequelize. I chose Sass over Less or Stylus. For the module loader, specifically, I thought it was important to use both.
When creating Perk I wanted it to be the most enjoyable framework for developers to use. This guided my decisions for many of the technical choices. When choosing a module loader there were a couple important factors that I took into account when evaluating different options.
- Speed - bundling my front-end javascript assets should be fast during development so that I'm not sitting around twiddling my thumbs while I wait for a small change to be re-bundled.
- Size - when I deploy my code, I want my javascript bundle to be as small as possible so that it downloads quickly for visitors to my website.
The Test
When deciding whether to pick Browserify or Webpack I ran some tests to determine which tool best fulfilled those requirements. Here are some details of the test that I ran:
- Test ran on my 2.7 GHz MacBook Pro (Retina, 13-inch, Early 2015, 8 GB of memory) while it was plugged in.
- Used a real codebase that included React with JSX and a few external modules (moment, howhap-fetch, react, react-dom, react-router).
- Had a total of 36 front-end JavaScript files.
- I invoked both Webpack and Browserify programatically, not via their respective cli tools.
For each test I ran the bundler 100 times and recorded the amount of time each bundle took to build and the final bundle size. Here are my results:
Bundler | Minify | Type | Fastest (ms) | Slowest (ms) | Mean (ms) | Median (ms) | Bundle Size (bytes) |
---|---|---|---|---|---|---|---|
Webpack | No | Fresh | 2780 | 4485 | 3333 | 3351 | 8883424 |
Webpack | No | Rebuild | 1321 | 1874 | 1597 | 1604 | 8890934 |
Webpack | Yes | Fresh | 2724 | 5254 | 2976 | 2944 | 3397280 |
Browserify | No | Fresh | 2288 | 4921 | 2493 | 2451 | 3015873 |
Browserify | No | Rebuild | 2226 | 2903 | 2444 | 2428 | 3015640 |
Browserify | Yes | Fresh | 10721 | 13905 | 11755 | 11794 | 2227159 |
The type column represents whether the bundle was created from scratch (Fresh) with no pre-existing bundle or if it was created from a pre-existing bundle (Rebuild). For speed implications I mostly ignored the "Fresh" bundles because that will only ever happen on the first bundle. Every subsequent bundle will be working from the previous bundle.
Conclusions
By running this simple little experiment it was clear to me that I needed both Browserify and Webpack. Webpack is insanely fast, making for a fantastic developer experience. When webpack re-builds a pre-existing bundle it does it on average 42% faster than Browserify, meaning that you're not sitting around refreshing the page waiting to see your change while you're developing.
However, Browserify wins hands down in terms of an optimized final bundle. Minified Browserify bundles are 42% smaller than minified Webpack bundles.
For these reasons Perk uses Webpack by default in development environments and Browserify by default for production builds.
Try it yourself
The code that I used to run these tests can be found here. To run your own test on your own machine with your own project files:
- Clone the repo
- Put your front-end JavaScript files into /public/scripts. The main entry point of the app should be called
main.js
- Install any necessary dependencies via npm
- Run the following commands to run the tests. Adjust the n parameter to change the number of runs.
node --use_strict build/test.js --loader=webpack -n=100
(Webpack, not minified, fresh)node --use_strict build/test.js --loader=webpack -n=100 --watch
(Webpack, not minified, rebuild)node --use_strict build/test.js --loader=webpack -n=100 --minify
(Webpack, minified, fresh)node --use_strict build/test.js --loader=browserify -n=100
(Browserify, not minified, fresh)node --use_strict build/test.js --loader=browserify -n=100 --watch
(Browserify, not minified, rebuild)node --use_strict build/test.js --loader=browserify -n=100 --minify
(Browserify, minified, fresh)