Browserify: My New Choice For Modules In A Browser / Backbone App

For the many things that I think I got right in MarionetteJS, there are a number of #facepalm things and “WHAT THE?!?!?” things… the most notable being the module system. Let’s face it, this is probably the clunkiest module system ever written – and all because I hate AMD (Asynchronous Module Definition) and RequireJS. It seems no matter how many times I try to use RequireJS, it just gets in my way and makes my life painful. I don’t know what it is… I’ve tried. and tried. and cried and tried and cried. I just don’t like AMD. So I wrote something worse and called it good enough. 

To everyone that has ever used Marionette’s modules: I’m sorry. I should have known better (and probably did, but didn’t listen to myself or anyone else). I hope the rest of Marionette makes up for that horrible mess I made.

But I’m officially over Marionette’s modules, now. I’ve found something better. Something I actually enjoy working with. Something that fits the way I think a module system should work, without any of the stupid hacks and work arounds that I’ve become used to. 

NewImage

What I Love About Browserify

There’s one thing that sold me on browserify: the ability to use what look like NodeJS / CommonJS modules in my browser. I’ve been working in NodeJS for the last few years now, and I’ve really come to appreciate the simplicity of the NodeJS module system… the ability to require any file in to my current file, or a module in to my current file; the ability to module.exports any object or data or function that I want, out of a file – these are all things that I like. And I almost immediately fell in love with browseify when I realized I could write code that looks like NodeJS modules, but have it run in my browser!

You can run these two files in both NodeJS and in a browser. The difference is that you have to run the browserify command to bundle the files together before running it in a browser.

Browserify does it’s magic through the “require” keyword, and builds a final output file that contains everything the browser needs. Epic win!

“But that’s not so different than AMD / RequireJS!”

I know it’s not that much different, but it is different enough. The way AMD and RequireJS typically work adds a lot of extra cruft around each of the individual files, though… boilerplate that you, the developer, have to put in to each file. Browserify ends up with a similar module pattern wrapper around each file, but it does it for you. It’s transparent to the developer, so you never have to worry about it. I like that. It makes me happy to get rid of that boilerplate. 

I also get to avoid all of the add-ons and plugins and crazy configuration shims that RequireJS tends to … require (see what I did there?). And avoiding crazy configuration makes me happy, too. I’ve spent days on end trying to configure RequireJS properly, with the right plugins and shims, slamming my face in to my keyboard in frustration. Sure, I eventually got it to work, but not before Jim Cowart had to write a 10 page article on how to properly shim things that I was using at the time. 

My experience with RequireJS and AMD has never been pleasant. Maybe yours has. Good for you. I don’t like it. I like browserify. 

How I’m Using It With Backbone

Ok, so browserify isn’t absolutely perfect. I don’t claim it is. I only claim it’s better than AMD. But there are still a few tricks to it, unfortunately – loading libraries like Backbone, as a prime example. In my (somewhat limited) experience, there are 3 ways to load Backbone (and underscore, and jquery, and marionettejs) in to my browserified app.

  1. just let Backbone be a global var, like always
  2. use the NPM backbone package
  3. magic hacks with browserify externals (i think)

I’m tending to go with option #1 these days, cause it suits my way of thinking and my style of development at the moment. I end up with at least 2 <script> tags because of this, but I’m ok with 2 for the apps i’m building right now. They tend to look like this:

where the “infrastructure.js” is a concat & minified file containing underscore, jquery, backbone, marionettejs and any other “infrastructure” libraries that don’t change very often. The “app.js” file is the browserified bundle. It’s where my actual app code lives, after running the browserify command line tool to build the bundle. 

Option #2 is probably a “better” idea in that everything will get bundled in to the one app.js file. I haven’t bothered to set this up in my apps, but it seems simple enough. You can google for “browserify backbone.js” and find a few hundred articles on how to set this up using the NPM packages for Backbone and jQuery. 

Option #3 is something I’m trying to figure out in my spare time (which I have none of right now). I think there should be a way to use one of browserify’s options to load external libraries in to the bundle without having to use the NPM package. The reason you would need to do this, is that Backbone detects the presence of a “require” function, and when it sees that it puts itself in to module-mode. This means it tries to “require” it’s dependencies (underscore) instead of looking for a global. This causes browserify to have problems loading backbone if you’re not using the backbone NPM package. I think there’s a way around this, but I haven’t figured it out yet (other than option #1 or #2). 

How I’m Using It With MarionetteJS

In addition to Backbone, I’m using MarionetteJS with browserify in my app. Once again, Marionette ends up inside of the infrastructure.js file, referenced above. The difference between what I’m doing now and what I used to do, then, is in the module system. 

Previously, I used Marionette’s module system to private encapsulation and modules, while also providing the ability to have “sub-applications” in my system. That is, smaller part of the over-all system that could be started and stopped when needed. Having moved to browserify, I’m no longer using Marionette’s modules. This means I no longer have access to the Application object from inside of my modules, and I no longer have the ability to start / stop sub-applications as needed (at least, not built-in). 

The one major problem I have with no access to the Application object, is getting to the root level regions. I solved this by adding a “getRegions()” function to my Application object, and use that to pass the list of regions down through my application hierarchy. It’s a bit ugly, but it works fine for now. I’m hoping to find a more elegant solution for this at some time, though.

The problem with no sub-applications to start / stop has not yet presented itself in my apps. I don’t need that right now. I know I will need it, though, and when I do run in to that requirement again, I’ll find another solution for it. There’s a good chance I’ll build an add-on for Marionette that specifically works with this new setup, in order to provide the functionality I want. There’s also work being done in Marionette’s future versions to allow multiple Application instances, which would help facilitate this. 

The Gory Details Of Using It With Marionette

Jason Krol posted a link to his epic blog post / article on using Browserify with Backbone, Marionette, MongoDB, and Nodejs. If you want to get the real-deal scoop on how to set up this epic stack (which is the same stack I’m using in my projects, these days), check out this post! It’s got all the goods that you need.

Not Just Backbone, Though

At this point, Browserify is my module system of choice for the browser. I’ve done more with Browserify than just Backbone / Marionette, too. It works well for most of the libraries and frameworks I’ve tried it with, so far. Note that I have not tried it with Ember or Angular, though. You’ll have to ask someone else about those. 

So, if you’re looking for a good module system for your browser, check out browserify. It’s been rocking my world for the last few weeks, and I’ve already got it in production in at least 3 pages on SignalLeaf. 

But, How Does This Compare To ES6 Modules?

I have no idea. I haven’t had a chance to look at ES6 modules, yet. I hope to do that some time soon, though. As soon as I can get some experience, there, I’ll blog the comparison / difference.

Get Your Magic On

Ok, get to it. Go install browserify and build awesome modules, instead of frustrating boilerplate with a thousand plugins and shims!


Get The Best JavaScript Secrets!

Get the best kept secrets of JavaScript, and the most important career advice you'll ever hear!
Don't miss out: join my list to get all the inside info!

  • Jmeas

    re: loading Backbone in a CommonJS environment.nnnI’ve never used Browserify, but when using Webpack you can specify it to load from your Bower manifest. It takes a bit of configuration (as all things do, it seems) but a friend of mine shared his configuration with me:nnhttps://gist.github.com/cletustboone/f237cf1fbd2f2dff282ennnnIn the past I just use the NPM modules for these things, but I’m thinking of trying out this bower-ified way in the future.nnnAnyway, I know this comment is mostly about Webpack but I thought I’d mention it as a possible 4th solution to loading the file from Bower.

    • http://mutedsolutions.com Derick Bailey

      that looks pretty slick, in spite of the configuration. at least in this case, the configuration happens once and you can then require everything / anything from bower… not a per-module shim like requirejs.nnnthanks, yo!

  • http://kroltech.com/ Jason K

    I hope you don’t mind my shameless plugging of my blog post, but I have a fairly thorough (long) post covering a full app built with Browserify, Backbone, marionette and node.js: http://kroltech.com/2013/12/boilerplate-web-app-using-backbone-js-expressjs-node-js-mongodb/nnnI've been working with Browserify for the past 7 months on a project at work and I too love it! Its made development so much fun and the modular nature of our project in particular has proven to be pretty great for the developers involved!

    • http://mutedsolutions.com Derick Bailey

      epic! added a link to this directly in the post :)

      • http://kroltech.com/ Jason K

        thanks!!! Much appreciated! Btw loving your screencasts and podcasts! Keep up the great work!

  • Roberto Guerra

    I got very frustrated with marionette modules early on. I’m currently maintaining my first marionette project where I went bananas with modules everywhere. Hopefully I’ll get a chance to refactor it. I never found a need to start/stop modules. I found it much cleaner to just tear down the dom and recreate everything. We keep the application state in an object literal for this purpose. After I started using requirejs, I found the need for marionette modules just disappear. For some time I felt like maybe I was doing it wrong. I mean, the books and the docs use modules, so there must have been something I was missing. I’m glad I wasn’t so wrong.nnMaybe our finest piece of engineering is a marionette login app for a centralised user database. We use requirejs to encapsulate the entire login module and serve it up different sites that our users access. We were able to isolate all the libraries so it wouldn’t clash with the libraries in these sites. For example, in one site they were using an old version of jquery, but we were able to isolate our version thanks to requirejs. Looking forward to dive into browserify again, I’ve always been deterred by the poor documentation.

    • http://mutedsolutions.com Derick Bailey

      sadly, the documentation is still terrible. a big part of why i haven’t figured out “externals” is because there is zero documentation / examples on it. i’ve looked many times, and there isn’t anything available. the majority of what i’ve been able to do with browserify comes from my experience with nodejs and making educated guesses as to how browserify would do it. this is definitely not the way it should be.

      • Brian Miller

        Rather than using the command line, I opted to write a script to do the bundling, and use the Browserify API. When you do this, you can call:nbrowserify.require(‘./path/to/script’, {expose: ‘myscript’});nnAfter that, you get that module anywhere you use require(‘myscript’) .nnSomething to keep in mind is that the object key that Browserify’s require uses to find the script once it’s bundled is the path that you gave it to resolve. So, if your CWD is at the top of your script at compile time when you require the extern, then the path from the root of your app is the key that you need to use in your require statements no matter where they are made in any file in your app, everywhere in the directory tree. This is why the “expose” option is helpful. You can rename it to whatever it ought to be universally, and then you’re back to not having to try to resolve any paths in your head when you’re actually writing your app.

  • http://oct8cat.redroach.es Tako Neko

    Uhm, personally I love the way “old” Marionette module system can be combined with Require.js, especially with the ability to split a module definition apart, so I can break my app to modules, then break each module to views/controllers/etc and let the module to manage it’s components thru Require.js dependencies. It really shines when using naming/directory structure conventions (I’m a big fan of conventions, huehuehue). Still a matter of taste, I mean.nnBut a module’s abilty to be started/stopped seems quite useful for some daemons-like application parts (background uploaders, REST-adapters, hurr-durr). My cat will be in trouble without it :(

  • http://monokromatic.blogspot.com monokrome
  • indigon

    Hey Derick, if you remember over an year ago I sent you a variation of Marionette’s modules we brewed up and used (you can see it here: https://gist.github.com/ShayDavidson/4578770). nnnLooking back at that time and that proposition, it reminded me how complex modules were and why we had to add our own layer in order for things to be simpler (or not? :)).

    • http://mutedsolutions.com Derick Bailey

      i do remember that – such a great article! so much good stuff in there. :)

  • Tony Stuck

    Ironically, we’ve found a way to use both at CloudFlare, but maybe using Marionette’s modules for a slightly different reason than they were originally intended. We’ve been rebuilding our entire web application using Backbone + Marionette + Browserify + a private NPM sever for a little while now (will be in beta soon), and use Browserify to build/package the entire app info different components (e.g., different pages).nnWhere Marionette’s modules come into play for us is essentially a way to package those different components (i.e., pages) in a simple way. Each Marionette module is super simpleu2014they typically just get a controller and a router. We then package each module (with Browserify) into individual files so we can load them on the fly when a user navigates to a new page (load the JS file, require the package, and call start() on it (i.e, the module)). And since each module registers itself with the main application object, it makes it easier for the application to manage its state (i.e., knowing when a module is already loaded on the page vs when it needs to fetch it).

    • http://mutedsolutions.com Derick Bailey

      that was one of the original use cases i had for marionette’s modules. i just think it can (and should) be done in a better way than is currently done. not sure what that “better way” is yet… but i’ll get there eventually :D

  • http://cwebbdesign.tumblr.com/ Chris

    @derickbailey:disqus FYI substack recently released a more in-depth ‘Browserify Handbook’ https://github.com/substack/browserify-handbook and this article helped me with understanding externals better: http://aeflash.com/2014-05/grunt-browserify-2-x-update.html

  • http://twitter.com/juandopazo Juan Dopazo

    You should consider authoring your modules using a subset of the ES6 module syntax. You can then compile them to CommonJS and bundle them up with Browserify, but you still leave the door open for other people to compile to AMD or whatever they want. You also get future compatibility with the language as a bonus.

    • http://mutedsolutions.com Derick Bailey

      i like the sound of that. i saw a blog post on this earlier today, and will be looking in to it (hopefully soon)

    • Michael

      Any recommended reading about this technique? Sounds pretty ideal for covering all bases.

  • Dan Sargeant

    It would be nice to be able to get a build of Marionettejs without the built in modules.

  • Brian Miller

    In package.json:n/* The actual version numbers are unimportant, feel free to keep them updated to the current version. */n “dependencies”: {n “backbone”: “^1.1.2″,n “browserify”: “latest”,n “jquery”: “^1.11″,n “underscore”: “^1.6.0″n }nnIn your app file:nwindow.jQuery = window.$ = require(‘jquery’);nwindow._ = require(‘underscore’);nwindow.Backbone = require(‘backbone’);nBackbone.$ = window.jQuery;nnDone.

  • http://www.surfulater.com/ nevf

    I share your frustration with Require.js however one aspect of it and AMD I find incredibly useful is that you have all of your JS files specified in the require.config which makes it super easy to swap files, as you just need a single change. nnnFor example I can switch between a minified and non-minified version, or bring in a mock or test version of the code. In other words yet have dependency injection. nnnMaybe I’m missing something but how do you accomplish this with Common JS style require(file)?

    • http://mutedsolutions.com Derick Bailey

      the require.config file is one of the things i don’t like about require.js :Pnnni’m not sure about the testing story in browserify at this point. it’s going to be a bit different than what i normally do w/ nodejs testing for commonjs modules. i have to dig in to this more, to have a good answer here. :)

      • http://www.surfulater.com/ nevf

        @derickbailey:disqus I’ll be interested to hear about your experience. I’d really miss the dependency injection that you get with AMD. I’ve developed a reasonably complex app Clibu http://www.clibu.com and a Browser Extension for it and both use AMD heavilly.

    • http://keripix.pethak.com/ keripix

      I agree with @nevf:disqus here. This is actually a very useful feature.

  • johanalkstal

    So using CommonJS modules, does that mean RequestResponse with Marionette goes out the door too?

    • http://mutedsolutions.com Derick Bailey

      no – Request/Response is an architectural pattern for communication between independent pieces of an application. modules are more of a file / code organization mechanism.

      • johanalkstal

        Sure. I was just thinking that if you’re not using Marionette modules, then the Marionette Request/Response system wouldn’t work?nI’m a Marionette noob so forgive me If I’m way off. =)nnAlso, not using the Marionette modules, is there still a way to split your routes into different CommonJS modules?

        • http://mutedsolutions.com Derick Bailey

          Ah – I see now. You won’t have access to the App.request / App.response methods, but you can create your own Marionette.RequestResponse object, which is where these methods are found. nnnRegarding routes: it works the same, no matter how you organize your code. You can put 100 routers in one file, or across 50 files or across 100 files. It doesn’t really matter from a file organization perspective. If you need to instantiate that router from another file, you would require that file in to the place that needs to create it.

  • pixelBender67

    Excellent article, I’ve been using require until I found out about browserify. It’s so much more intuitive and dev friendly.

  • http://wilmoore.com/ Wil Moore III

    You’ve pretty much summed up my experience and pain working with AMD for the last 1.5 years. Every time I have to touch that part of the codebase, I die a little inside.

  • http://keripix.pethak.com/ keripix

    How about the testing? What testing tools do you use?nnThe last time I tried to use marionettejs and browserify, I was facing a hard time testing it. I believe mw configuration was wrong, but I didn’t had the time to check it. I used requirejs since then.nnDo you mind sharing your testing configuration please?

  • drwxrxrx

    re loading option #3: have you looked at browserify-shim’s way of marking things global? https://github.com/thlorenz/browserify-shim#3-provide-browserify-shim-config

  • Agathiyar

    Derick, may be just me!!! but i have this feeling that you are not planning anything in advance and designing application(s). I see lot of statement in this article like “I may need it but not currently now. if i need it i will figure out later”. This sounds like on they fly plug and go ideas, it may appear to do the deal but i am afraid some point in time you may hit roadblock and it may be costlier to backtrack what we did at that time. I am sure for some of the “do it later stuff” you will come up with definite solution or ideas atleast.if not for you atleast for others who take your footpath seriously :)

    • http://mutedsolutions.com Derick Bailey

      this is always a concern and a risk, yes. i have a tendency to take risks in technology and code. but in the however many years i’ve been doing this, most of my best ideas and code have come from putting it off until i need it.

      i don’t know, yet. maybe it will work out, maybe it won’t. right now, i’m still loving browserify. it is making my life so much easier.

      • Agathiyar

        Thanks Derick. Yes Browserify rocks and its really a great feel using it. Coming from spring background, am I getting carried away with Wire.js. That also seems to be a great framework. Do you see any advantage of integrating wire.js with Marionette? or its simply over kill.

  • davidbiehl

    I’ve been struggling with Marionette’s module system for several weeks, and have never really felt comfortable with them. Now I don’t feel so bad! I do enjoy working with RequireJS and AMD, but don’t like the verbosity. I’ll give Browserify a shot, thanks for the tip.