Skip to content

Instantly share code, notes, and snippets.

@tbranyen
Forked from davearel/jquery_amd.js
Last active August 29, 2015 13:56
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tbranyen/9255362 to your computer and use it in GitHub Desktop.
Save tbranyen/9255362 to your computer and use it in GitHub Desktop.
// Use an AMD package here to gain access to nested internal modules.
require.config({
packages: [{
name: "jquery",
location: "vendor/jquery/src",
main: "index.js"
}]
});
// If we are using AMD, we don't care about core.
define(function(require, exports, module) {
"use strict"
var ajax = require("jquery/ajax");
var data = require("jquery/data");
var req = ajax.get("/modular");
req.then(function() {
// Modules, sucka.
});
exports.ajax = ajax;
exports.data = data;
});
// jquery/html would return a module representing the function.
require(["jquery/html"], function(html) {
html.call(elems, "value");
});
// Want chaining instead, hold onto your seats!!!!
require(["jquery/core", "jquery/html"], function($, html) {
// Attach to core.
$.fn.html = html;
// Now that's what I'm talking about.
$(".some-elems").html("value");
});
@davearel
Copy link

@timmywil I can get behind this. It's a paradigm shift, but its a very decoupled architecture; which I like.

Though I'm not sure why we can't have the same level of granularity in each module, while still allowing a way to extend several modules into one chainable namespace. Only within the module that is requiring it.

Per my original gist:

var $ = jq.require(find, addClass);

@tbranyen
Copy link
Author

@timmywil I still don't understand why we can't move slowly and keep the API intact as-is. All the chainable methods are attached to $.fn anyways so why not keep it that way?

An idea I was thinking is that if jquery/core is loaded, each method once required could test for, and then attach to, that module.

Concept:

define(["require"], function(require) {
  "use strict";

  function html(elems, value) {
    /*.. */
  }

  // If the module is defined, simply attach it.
  if (require.defined("jquery/core")) {
    require("jquery/core").fn.html = html;
  }

  return html;
});

The entire internal API could be designed this way and that's also how it could be trivially assembled without having that massive $.fn.extend call.

@davearel
Copy link

@tbranyen the problem with that is you are extending the core object for all future modules.

What happens when you extend the prototype for html in two of your app modules, but forget to require it in one? If you remove the dependency from that original module, it will be removed from production code, but your code is still trying to access it.

My example creates a clone for use within that one module only. That way, it is truly decoupled among your modules.

@xMartin
Copy link

xMartin commented Mar 2, 2014

What you want is what for example the Dojo Toolkit is doing since years and it's great. The complete code base is structured in tiny AMD modules with explicit dependency management and scoping of these. This approach is amazingly powerful. The toolkit also covers all features and jQuery and way beyond - just require what you need.

jQuery has a completely different approach. Wrapping everything in jQuery objects makes a beautiful DSL for the DOM and is very valuable as such if that's all you need. But you cannot have both. The limitation of jQuery is not that it is not modular. It is that it is by design monolithic as in namespace and wrapping things.

If you need something that is more powerful (and thus less simple) move on. jQuery cannot be the answer to all needs.

@davearel
Copy link

davearel commented Mar 2, 2014

I disagree, only in that I think it's possible for jQuery to have both. However, As I stated before:

Maybe that paradigm doesn't belong in AMD

It may be a little too aggressive for jQuery to migrate away from the current syntax, and I'm not 100% sure if it's in its best interest; chaining is a valuable thing. Regardless, that doesn't mean we can't have chaining and AMD.

My original example was exactly that:

define([

  // jquery core is always required
  'jquery/core',

  // jquery utilities
  'jquery/ajax',
  'jquery/data'

], function(jq, ajax, data) {

  // Using the core module, create a jQuery instance
  // with the required extensions
  var $ = jq.require(ajax, data);

  // The local instance of $ contains the necessary jQuery
  // extensions, but once this module is done executing,
  // "$" no longer exists to other modules.

});

https://gist.github.com/davearel/9254418

Of course, that doesn't describe the actual implementation, but rather the outcome. The point is simply that we extend the core jQuery namespace, with the necessary dependencies, to a LOCAL variable. That way it is only accessible to that particular module.

The require method would return a new instance of jQuery that only contains the core methods and the dependency methods.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment