Browserify VS Webpack - JS Drama
While on the one hand, Substack talks about how bundling features into a single project hurts Semver and hurts competition, Pete Hunt is sick of this ‘modularity shaming’ and points out that the Webpack codebase is extremely modular.
I see some good points on either side of the story, but I think the major difference between the two projects is something else entirely:
Compatibility with node.js
Browserify was born to make your Node code in the browser. Till date it only supports the node flavour of commons (including JSON support) and provides in-built shims for many node core modules. Everything else is a different package. Need to watch files for incremental compilation? Use Watchify. Need Bundle splitting? Use Factor-Bundle. Need AMD support? Use deAMDify.
Browserify pushes all features that don’t fit into it’s philosophy of running Node code in the browser into transforms and plug-ins.
At the same time, Browserify expects to be used only in a Node.js project. It recommends making small modules and posting them on NPM, and putting any configuration into the package.json file.
Webpack is a very different beast. It learnt from tools such as Browserify, and Require.js and it never tries to actually be compatible with node.js. It is built, from the ground up, to help you manage static assets for the front-end. So, while in Browserify, to read strings from static files, you would use BRFS, which uses the native readFile function in Node, in Webpack, the common thing is to just overload the require function and use a loader that loads files that have names that match a certain pattern.
Webpack also doesn’t have any preference for commonjs over AMD. It supports all modules formats out of the box. So you could write your entire project with AMD, and still use Webpack. Obviously, that code isn’t going to work in Node without some work.
Differences in Philosophy
These differences can have far reaching consequences. Webpack for example applies loaders to all files that match, unless you manually exclude the node_modules folder. Browserify, by default, will not apply any transform to files in the node_modules folder by default.
This is actually an interesting detail when comparing the two systems. Browserify is a smaller more 'modular’ tool that can and should be composed with many plug-ins and transforms. Webpack, brings more features and puts them in core. But Browserify is more convention driven than webpack.
Webpack, for all its size and features is actually pretty flexible in its usage. You can use it in various ways as long as you’re willing to write a long enough config file.
If you only use commonjs and don’t use webpack for managing any CSS or images, then you could, use it like browserify and maintain compatibility with node. But webpack doesn’t try to conform.
Browserify on the other hand, being smaller and more established is easy to pick up. And if you conform to some of its conventions, you have write very little or no configuration to make it work.
So, Browserify is much more likely to work with minimal configuration but will force you into a small set of conventions. Webpack on the other hand will always require some configuration to work for anything but the most basic case.
Static asset management
Webpack with require overloads will let you require CSS files that can be injected in the browser at runtime. Node.js can’t exactly require CSS files though. But with Webpack, you have to configure it the way you like.
Similarly for images and other static assets where all you want is the URL to a file and nothing else, browserify has a tool called urify-emitter. It’s currently in an experimental stage, but it brings Webpack like static asset management in a way that is completely compatible with Node. Instead of overloading the require function, it introduces a package, that you can 'require’ static assets with. The required files, just return a simple string which is the path to that static asset. With some configuration, you can make it automatically copy your assets to a particular folder with unique hashed names. When ready, I believe this would be an improvement over asset management in JS that webpack make popular.
A lot has been said about Webpack’s built-in bundle splitting. However, with Factor-Bundle and Partition-Bundle, Browserify has the same capabilities.
Webpack’s fix for Node.js
If you do go down the Webpack route, it provides two way to make your code work in Node.js
- You can export your code with Node.js as the target and it will export code that can run in Node.js
- The Enhanced-Require module, overloads the require function in Node.js to make webpack code work within it.
I haven’t tried either of these two systems and I’m not sure about their various limitations.
Making a decision
Making a decision between Webpack and Browserify is more nuanced than most people think. In a feature war, Webpack does have a few features that Browserify doesn’t have. So, if you make your decisions only based on checklists of features, or if one of the features that are unique to Webpack are extremely important to you, like Hot-Loading, then Webpack is right choice for you.
If however, you’re predominantly dependent on the NPM ecosystem and you want a tool with a small and very well designed API and takes minimal configuration, you should go for Browserify. It doesn’t have all the features of Webpack, but it does have most, and it’s very easy to get started with. As an additional pro or con, depending on your philosophy, Browserify will try to push you in a certain direction regarding the modularity of your codebase. It will also make it easier to build isomorphic npm modules. With the
browser field in the package.json, you can easily have modules with the same API but different implementations for Node and browser.
My own opinion
With the advent of ES6, the tools of the trade are evolving. The new kid on the block is System.js (along with it’s pacakge manager jspm). System.js has a completely different approach to the problem where it’s philosophy leans mostly to ES6 compatibility, and providing a path to getting rid of bundling all together (as with HTTP 2.0/SPDY, it’s just as fast to load many smaller files as it is to load one large one). I have yet to learn much about it for now though. I’ll save it for a future blog post.