Javascript – How to modularize and package a client-side Javascript library today

javascriptmodulespackages

I've been catching up with the modern client-side JS ecosystem and reading up on CommonJS and AMD (incl. associated tools – browserify, requirejs, onejs, jam, dozens of others). If I'm writing a Javascript library, how do I modularize/package it such that it can be most broadly accessible (ideally by users who swear by CommonJS, AMD, and especially neither)?

Popular libraries like jQuery seem to just use old-school file concatenation for building itself and dynamically detect whether it should write to an exports or the global context. I'm currently doing the same thing, but the main downside is that if I (unlike jQuery) depend on a few libraries, it's nice to not have to ask users to manually pre-include the transitive set. (Though I currently just have two dependencies.) And of course global namespace pollution.

Or perhaps it's cleanest to generate multiple versions of my library, for each context?

I'm also wondering about packaging and publishing. There are several systems, but I believe the major one is bower, which is easy to deal with since all it does is fetch. However, I'm wondering if I should also be targeting other package systems like component (which requires CommonJS).

Are there other relevant aspects I should be aware of? Are there any good example projects to follow for all of this?

Best Answer

I've always used to use build files but since I started my first nodejs project I started using browserify. With browerify and other similar libraries your code is your build file. I am taking advantage of a client and server library that can run on both but it can also work with purely client code. To sum it up browserify gives you all the benefits of writing code in node (no anon functions to avoid globals, npm, simple requires) and it allows you to package that code to run on the client with one command and only load one file.

With browserify you can do something like (named app.js):

var MyLib = require('../myLib');

if(typeof window !== 'undefined') {
    window.MyLib = MyLib;
    window._ = require('underscore');
    window.$ = require('$');
    window.MyLib.myCan = require('./3rdParty/can/can');
}

browserify app.js > client.js

Would produce something like:

[function(require,module,exports){
    window.MyLib = //MyLib code
},
function(require,module,exports){
     window._ = //_ code
},
function(require,module,exports){
    window.$ = //$ code
},
function(require,module,exports){
    window.MyLib.myCan = //can code
}

The file that you would define could have all your 3rd party libs included and not clash with any of your developers that use it.

--Edit in respond to the comment (and a complete miss on the question)

I guess that would depend on your dependencies and how much time you want to spend making sure they work across all versions and libs. If your dependencies are common and follow the same api from version to version you could go the Backbone route and just require the user to have $ and _. I would suggest putting the more obscure libs as part of the bundled file. The options don't have to be cut and dry either. You could offer a pre-built or build your own package.