tl;dr: The problems inherent in jQuery dependency should not be resolved by not depending on jQuery or some other $
-providing library. Rather, library authors should write library code that expects a $
will be injected that meets the library's needs.
In the front-end JS world, there is a movement to be dependency-free, and specifically to be jQuery dependency free. This problem seems to be the result of a pre-package management mindset. But those days are long gone, or, they should be.
The result of this mindset, however, tends to not be pretty: library authors write their own, often minimally tested, DOM manipulation and utility belt routines. If you come to depend on multiple or many such libraries, your code, via their code, then comes to contain dozens of diverse implementations of similarly or identically-purposed functions.
- Sortable.js. A wonderful library that's very easily integrated with DOM elements managed by Backbone Views (aka, does not manipulate the DOM itself very much). Code that would be unneccesary if a
$
was injected:
https://github.com/RubaXa/Sortable/blob/master/Sortable.js#L465-L506
This library could probably be 30-40% shorter if it depended on some $
, and although it is already quite simple and easy to follow, would be that much better with such a dependency.
- Medium.js. A cool library, though not very useful in terms of Backbone integration. Made less cool by stretches of code like this:
https://github.com/jakiestfu/Medium.js/blob/master/medium.js#L138-L184 (and the code around it too).
This library would be much improved by depending on some $
and some utility belt. Depending on this library means you inherit all those totally unnecessary event binding routes, and all the other similar, supporting code in this library.
- List.js. Also an interesting library, made not useful by 2 factors:
(1) It attempts to solve the above-state problem by using Component:
https://github.com/javve/list.js/blob/master/index.js#L9-L11
This attempt fails, however, because it's mostly incomplete. The library still has tons of hand-crafted, untested DOM manipulation, utility-belt- type code.
(2) Component is a total drag to use with NPM/Browserify, thus making this library pretty much worthless for anyone using NPM/Browserify.
Library code should specify the $
and _
it expects, and a matching $
and _
should be injected into the library.
Thus, instead of writing libraries like:
var $ = require('$')
var isArray = require('lodash.isarray);
// library code
Or, not depending on a $
at all (which is even worse), instead write library code like:
// someLibrary.js
module.exports = function(_, $) {
return factory(_, $);
};
function factory(_, $) {
var someLibrary = {
somethingCool: function() {
$('.lame').removeClass('lame').addClass('awesome');
},
alsoCool: function(something) {
return _.isArray(something) ? 'is array' : 'not an array';
}
};
return someLibrary;
}
Application programmers can then craft a $
and _
for their application:
// myApplication$.js
var $ = require('domToolbelt.$');
$.fn.removeClass = require('domToolbelt.removeClass')
$.fn.addClass = require('domToolbelt.addClass');
module.exports = $;
// myApplication_.js
var _ = {};
_.isArray = require('lodash.isarray');
module.exports = _;
And then inject those into the libraries they use:
// application.js
var $ = require('./myApplication$');
var _ = require('./myApplication_');
var someLibrary = require('someLibrary')(_, $);
Notice that library code should not require()
its own $
or _
, because the application author should be able to inject their desired implementation into the library. Although using require()
for $
or _
in library code makes sense superficially, it prevents applications from being built in truly modular ways, without the use of repetitive implementations in your final bundle. The application author should decide which browser edge cases they want their application to support, and provide the relevant $
and _
.
interesting idea, but seems to make a lot of assumptions about the capabilities of those injected
_
and$
no? Those will vary depending on each library. So it pushes the dependency resolution problem up a layer.