My RequireJS Itches and How I Scratched them using Browserify
Update: This seems to have goten way more attention that expected, so I owe to correct a thing or to here. See updates and please drop me message if this can be refined further.
After a few months of hard work I am about to release NOTA for public Beta (really exited!). My main goal for this first release is to have an agile MVP that will sustain rapid iterations.
As far as the backend is concern no problem there Laravel’s got my back.
Not only L4 (Laravel version 4) makes it drop-dead easy to write decoupled and testable code but it also comes packed with a bunch of convenient tools like the remote component (automation of SSH based tasks), the .env file ( for easy environment variables), artisan tinker and loads of other great stuff.
So all good there.
Unfortunately on the other end of the wire — it’s a whole different story.. Backbone views, models, collections, templates, libraries and other various plugins are kept from collapsing together into a huge spaghetti mess by the dependency management sytstem.
For the past few years I have entrusted RequireJS with that vital task and it’s fair to say that it did a pretty great job a it, but yet still left me with quite a few itches that needed to be scratched.
1) R.JS Tedious Building process
Not only does RequireJS have a somewhat bloated configuration file, but if you need to use R.js to bundle you will also have a build specific configuration file and if you are testing, you will need yet another configuration file for your tests.
So needless to say that maintaining all those configuration files in sync is quite an agility bottleneck .
2) R.js Big Fat Bundle
They say: "Premature optimization is the root of all evil", well I believe assumptions are, and RequireJS & R.js are making a big one: “You will want to build your whole app into one big fat bundle”
A few things bug me there:
I'd like to break my build in several files for multiple page project or to leverage the browser’s built-in paralleled resource loading for big build files.
I don’t want to bundle global dependencies (Backbone, jquery & friends) with the core of my app, cause—well that’s silly not to leverage CDN for that and also I find that it semantically doesn’t make sense. I personally like to have one separate script tag for jQuery, one for the other vendors (all minified and compressed), and finally one for the application code. Unfortunaly R.js doesn't help with those type of scenarios.
Update: Thanks to @GregFranko for pointing errors here. You can externalize module just as easly with r.js.
3) A Requiered Overhead
I dont't use the aync part of requireJS so the fact that my build files still need requireJS (or some other AMD implemetation) just seems like an unnecessary overhead. It means that the browser will first have to consume requireJS before any of my application’s actual code hits the wire.
There are a ways to include a lighter more barebone AMD implementation for production see Almond but even so that adds up toward slower iterations (2 different version of the AMD for production and development) and it doesn't feel right to have one the key component of my app differe from development to production.
4) Miscellaneous Itches
Too much boiler plate: A little bit of boilerplate here, a little bit of boilerplate there, and one more developers goes crazy. In the end what we all want is to code well and code happily. Boilerplate code doesn’t help.
Syntax: As JS developers we are getting (rightfully) brainwashed about how evil callbacks are, and writing all my modules inside one kinda sucks.
AMD: I don’t need async module loading. The idea is nice on paper; in practice I have never used it so why bother.
Now why browserify
Fast, flexible and easy to automate build process with almost 0 configuration needed
Always work from the bundle which makes you feel way more secure when publishing code
Very little overhead in the build file, just a few bytes.
Great syntax with literally no boilerplate.
CommonJS style has the advantage of being used on the server as well as in the browser
You can easily utilize globals and inject them into modules (need the shim plug in for that). That is to say you externalize Jquery, backbone and such and still be able to require them.Update: while this is still true for browserify it's just as easy with R.js
Allows breaking the build into many files, which can be very handy on multi page projects, but also can enable lazy loading of bigger apps as well as leveraging browser paralleled resources loading
Very active development. @substack browserify creator and maintainer is an amazingly productive developer.
Note: ComponentJS is probably worth evaluating. I personally dismissed it because I am already familiar with CommonJS and the NPM eco system, so it made more sense to me to not learn anything new (..ish, ComponentJS is pretty straight forward). But for some it might be a great choice.
Cheers to Curtis Matthiesen-Dillon for helping with the grammar review.