82

I would like to use requireJS and I am using jQuery. I don't want to use the combined version of requireJS and jQuery since I am not using the latest jQuery version. What is the best way for me to work with requireJS?

5
  • 2
    What's preventing you from using the latest jQuery?
    – Incognito
    Commented Dec 27, 2010 at 0:36
  • I am using jQuery 1.3.8. This version works a bit different then 1.4.X. I order to use the newest jQuery I have to update some code and right now I don't have time for that. Moreover, I don't think that combining packages is a right thing.
    – Naor
    Commented Dec 29, 2010 at 12:12
  • The answer below is good...why haven't you marked it as correct? Commented May 16, 2011 at 12:04
  • @Prisoner ZERO: Honestly, I haven't manage to test it. ecentually I used the ajax script loader of microsoft. Thanks for remind me to mark this answer. If you said it is great - I believe you.
    – Naor
    Commented May 16, 2011 at 16:20
  • I also found requirejs hard to use with other libraries and vice-versa. That is why I created a library which is much easier to use and is tested with angular. There is a demo application at the bottom: gngeorgiev.github.io/Modulerr.js You can also combine all scripts into one without the dependency to Modulerr.js
    – Georgi-it
    Commented Aug 10, 2014 at 21:29

5 Answers 5

133

That is my exact question too! I also must use an older jQuery, but also more "traditional" javascript libraries. What is the best technique to do that? (I may edit your question to make it more broad if you don't mind.) Here is what I learned.

RequireJS author, James Burke, explained the advantages of the combined RequireJS + jQuery file. You get two things.

  1. A module, jquery, is available, and it's the jQuery object. This is safe:

    // My module depends on jQuery but what if $ was overwritten?
    define(["jquery"], function($) {
      // $ is guaranteed to be jQuery now */
    })
    
  2. jQuery is already loaded before any require() or define() stuff. All modules are guaranteed that jQuery is ready. You don't even need the require/order.js plugin since jQuery was basically hard-coded to load first.

To me, #2 isn't very helpful. Most real applications have many .js files that must load in the right order—sad but true. As soon as you need Sammy or Underscore.js, the combined RequireJS+jQuery file doesn't help.

My solution is to write simple RequireJS wrappers that load my traditional scripts using the "order" plugin.

Example

Suppose my app has these components (by dependency).

  • My app, greatapp
    • greatapp depends on a custom jquery (old version I must use)
    • greatapp depends on my_sammy (SammyJS plus all its plugins I must use). These must be in order
      1. my_sammy depends on jquery (SammyJS is a jQuery plugin)
      2. my_sammy depends on sammy.js
      3. my_sammy depends on sammy.json.js
      4. my_sammy depends on sammy.storage.js
      5. my_sammy depends on sammy.mustache.js

In my mind, everything above that ends with .js is a "traditional" script. Everything without .js is a RequireJS plugin. The key is: high-level stuff (greatapp, my_sammy) are modules, and at deeper levels, it falls back to traditional .js files.

Booting

It all starts with a booter telling RequireJS how to start.

<html>
  <head>
    <script data-main="js/boot.js" src="js/require.js"></script>
  </head>
</html>

In js/boot.js I put only the config and how to start the application.

require( // The "paths" maps module names to actual places to fetch the file.
         // I made modules with simple names (jquery, sammy) that will do the hard work.
         { paths: { jquery: "require_jquery"
                  , sammy : "require_sammy"
                  }
         }

         // Next is the root module to run, which depends on everything else.
       , [ "greatapp" ]

         // Finally, start my app in whatever way it uses.
       , function(greatapp) { greatapp.start(); }
       );

Main Application

In greatapp.js I have a normal looking module.

define(["jquery", "sammy"], function($, Sammy) {
  // At this point, jQuery and SammyJS are loaded successfully.
  // By depending on "jquery", the "require_jquery.js" file will run; same for sammy.
  // Those require_* files also pass jQuery and Sammy to here, so no more globals!

  var start = function() {
    $(document).ready(function() {
      $("body").html("Hello world!");
    })
  }

  return {"start":start};
}

RequireJS module wrappers around traditional files

require_jquery.js:

define(["/custom/path/to/my/jquery.js?1.4.2"], function() {
  // Raw jQuery does not return anything, so return it explicitly here.
  return jQuery;
})

require_sammy.js:

// These must be in order, so use the "order!" plugin.
define([ "order!jquery"
       , "order!/path/to/custom/sammy/sammy-0.6.2-min.js"
       , "order!/path/to/custom/sammy/plugins/sammy.json-0.6.2-min.js"
       , "order!/path/to/custom/sammy/plugins/sammy.storage-0.6.2-min.js"
       , "order!/path/to/custom/sammy/plugins/sammy.mustache-0.6.2-min.js"
       ]

       , function($) {
           // Raw sammy does not return anything, so return it explicitly here.
           return $.sammy;
         }
      );
8
  • 5
    Good work on this answer...hopefully the questioner will mark this! Commented May 16, 2011 at 12:09
  • you create a require_jquery module depending on the actual jquery file, but doesn't jquery stay global? the actual jquery file 1.4.2 that you load from the custom path, is not a require.js module ? or did you wrap require around that file too?
    – Sander
    Commented Sep 8, 2011 at 23:44
  • 3
    I would like to note that with the most recent version of jQuery (1.7) it already supports modules and so all you need to do is require it as per normal and it will work.
    – MikeMurko
    Commented Dec 17, 2011 at 23:18
  • 1
    can someone update this answer to reflect how to do requireJS 2 (w/ shim) + jQuery 1.7+ that supports AMD?
    – Henry
    Commented Jun 7, 2012 at 1:01
  • 1
    I'd just like to point out that the best way to achieve dependency support with non-AMD javascript files is now the shim config found in RequireJS 2.0+ If you're still using Require 1.x you can use the precursor to the shim, wrapjs
    – Johann
    Commented Jul 2, 2012 at 23:01
33

This question is at least two years old now, but I noticed this is a problem still with RequireJS 2.0 (require-jquery.js uses jQuery 1.8.0, but the latest version is 1.8.2).

If you happen to see this question, note that require-jquery.js is now just require.js and jquery.js, mashed together. You can just edit require-jquery.js and replace the the jQuery parts with a newer version.

Update (May 30, 2013): Now that RequireJS has paths and shim, there is a new way to import jQuery and jQuery plugins, and the old method is no longer necessary nor recommended. Here is an abridged version of the current method:

requirejs.config({
    "paths": {
      "jquery": "//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min"
    }
});

define(["jquery"], function($) {
    $(function() {
    });
});

See http://requirejs.org/docs/jquery.html for more info.

7
  • Thanks, this is still relevant :)
    – Naor
    Commented Sep 27, 2012 at 7:13
  • Are you still using jQuery 1.3.8? :)
    – Chris
    Commented Sep 27, 2012 at 22:45
  • Thank you for pointing this out. I read that an older version of 1.8 had problems that were solved in the latest. Commented Sep 28, 2012 at 17:16
  • Indeed. They weren't jQueryUI problems with curCSS, were they?
    – Chris
    Commented Sep 28, 2012 at 20:44
  • 1
    @AHMED: They both work. The difference is that define explicitly specifies a module. I tend to prefer using define almost exclusively because it's more explicit about paths: stackoverflow.com/questions/16087635/…
    – Chris
    Commented Jun 14, 2013 at 15:15
9

I've found the best approach is to keep jQuery outside of my RequireJS build.

Just include jquery.min.js in your HTML. Then, make a jquery.js file with something like this...

define([], function() {
    return window.$;
});
1
  • This is a good workaround, as I have some JS files which must be loaded traditionally using script tags, and they depend on jQuery.
    – jingtao
    Commented Nov 19, 2014 at 4:11
3

Found JasonSmith's anwer tremendously helpful, probably more so than the RequireJS's documentation.

However, there is way to optimize on it to avoid having separate AJAX requests for (tiny) define-declaring modules ("require_jquery" "require_sammy"). I would suspect r.js would do it at optimization stage, but you can do that ahead of time in order not to fight with Path, BaseURI system.

index.html:

<html>
  <head>
    <script data-main="js/loader.js" src="js/require.js"></script>
  </head>
</html>

loader.js:

// We are going to define( dependencies by hand, inline.
// There is one problem with that through (inferred from testing):
// Dependencies are starting to load (and execute) at the point of declaring the inline
// define, not at the point of require(
// So you may want to nest the inline-defines inside require( 
// this is, in a way, short replacement for Order plug in, but allows you to use
// hand-rolled defines, which the Order plug in, apparently does not allow.

var jQueryAndShims = ['jquery']

if(window.JSON == null){
    jQueryAndShims.push('json2')
    define(
        'json2'
        , ['js/libs/json2.min.js']
        , function() {
            return window.JSON
        }
    )
}
// will start loading the second we define it.
define(
    'jquery'
    , ['js/libs/jquery_custom.min.js']
    , function() {
        // we just pick up global jQuery here. 
        // If you want more than one version of jQuery in dom, read a more complicated solution discussed in
        // "Registering jQuery As An Async-compatible Module" chapter of
        // http://addyosmani.com/writing-modular-js/
        return window.jQuery 
    }
)

// all inline defines for resources that don't rely on other resources can go here.

// First level require(
// regardless of depends nesting in 'myapp' they will all start downloading 
// at the point of define( and exec whenever they want, 
// async in many browsers. Actually requiring it before the nested require makes
// sure jquery had *executed and added jQuery to window object* before
// all resolved depends (jquery plugins) start firing.
require(jQueryAndShims, function($) {

    // will start loading the second we define it.        
    define(
        'sammy_and_friends'
        , ['jquery','js/libs/jquery_pluginone.min.js','js/libs/jquery_plugintwo.min.js','js/libs/sammy.min.js']
        , function($) {
            // note, all plugins are unaltered, as they are shipped by developers.
            // in other words, they don't have define(.. inside.
            // since they augment global $ (window.jQuery) anyway, and 'jquery' define above picks it up
            // , we just keep on returning it.
            // Sammy is attached to $ as $.sammy, so returning just Sammy makes little sense
            return $
        }
    )

    // second level require - insures that Sammy (and other jQuery plugins) - 'sammy_and_friends' - is
    // loaded before we load Sammy plugins. I normally i would inline all sammy plugins i need 
    // (none, since i use none of them preferring jQuery's direct templating API
    // and no other Sammy plug in is really of value. )  right into sammy.js file. 
    // But if you want to keep them separate:
    require(['sammy_and_friends'], function() {

        // will start loading the second we define it.
        define(
            'sammy_extended'
            , ['sammy_and_friends','js/libs/sammy_pluginone.min.js','js/libs/sammy_plugintwo.min.js']
            , function($) {
                // as defined above, 'sammy_and_friends' actually returns (globall) jQuery obj to which
                // Sammy is attached.  So we continue to return $
                return $
            }
        )
        // will start loading the second we define it.
        define(
            'myapp'
            , ['sammy_extended', 'js/myapplication_v20111231.js'] 
            , function($, myapp_instantiator) {
                // note, myapplication may, but does not have to contain RequireJS-compatible define
                // that returns something. However, if it contains something like 
                // "$(document).ready(function() { ... " already it MAY fire before 
                // it's depends - 'sammy_extended' is fully loaded.
                // Insdead i recommend that myapplication.js returns a generator 
                // (app-object-generating function pointer)
                // that takes jQuery (with all loaded , applied plugins) 
                // The expectation is that before the below return is executed, 
                // all depends are loaded (in order of depends tree)
                // You would init your app here like so:
                return myapp_instantiator($)
                // then "Run" the instance in require( as shown below
            }
        )

        // Third level require - the one that actually starts our application and relies on
        // dependency pyramid stat starts with jQuery + Shims, followed by jQuery plugins, Sammy, 
        // followed by Sammy's plugins all coming in under 'sammy_extended'
        require(['jquery', 'myapp'], function($, myappinstance) {
            $(document).ready(function() {myappinstance.Run()})
        })
    }) // end of Second-level require
}) // end of First-level require

finally, myapplication.js:

// this define is a double-wrap.
// it returns application object instantiator that takes in jQuery (when it's available) and , then, that
// instance can be "ran" by pulling .Run() method on it.
define(function() {
    // this function does only two things:
    // 1. defines our application class 
    // 2. inits the class and returns it.
    return function($) {
        // 1. defining the class
        var MyAppClass = function($) {
            var me = this
            this._sammy_application = $.sammy(function() {
                this.raise_errors = true
                this.debug = true
                this.run_interval_every = 300
                this.template_engine = null
                this.element_selector = 'body'
                // ..
            })
            this._sammy_application.route(...) // define your routes ets...
            this.MyAppMethodA = function(blah){log(blah)}  // extend your app with methods if you want
            // ...
             // this one is the one we will .Run from require( in loader.js
            this.Run = function() {
                me._sammy_application.run('#/')
            }
        }
        // 2. returning class's instance
        return new MyAppClass($) // notice that this is INITED app, but not started (by .Run) 
        // .Run will be pulled by calling code when appropriate
    }
})

This structure (loosely replaces (duplicates?) RequireJS's Order plugin, but) allows you to prune the number of files you need to AJAX, adding more control to definition of depends and depend tree.

There is also a large bonus to loading jQuery separately (which usually comes at 100k) - you can control caching at server, or cache jQuery into browser's localStorage. Take a look at AMD-Cache project here https://github.com/jensarps/AMD-cache then change the define( statements to include "cache!": and it will be (forever :) ) stuck in user's browser.

define(
    'jquery'
    , ['cache!js/libs/jquery_old.min.js']
    , function() {
        // we just pick up global jQuery here. 
        // If you want more than one version of jQuery in dom, read a more complicated solution discussed in
        // "Registering jQuery As An Async-compatible Module" chapter of
        // http://addyosmani.com/writing-modular-js/
        return window.jQuery 
    }
)

Note about jQuery 1.7.x+ It no longer attaches itself to window object, so the above will NOT work with unmodified jQuery 1.7.x+ file. There you must customize your jquery**.js to include this before the closing "})( window );":

;window.jQuery=window.$=jQuery

If you have "jQuery undefined" errors in console, it's a sign jQuery version you are using is not attaching itself to window.

Code license: Public domain.

Disclosures: JavaScript above smells of "pseudo-code" as it is a paraphrasing (hand-pruning) of much more detailed production code. Code as presented above is not guaranteed to work and was NOT tested to work as presented. Audit, test it. Semicolons omitted on purpose, as they are not required per JS spec and code looks better without them.

1
  • After fighting with RequireJS (things loading out of order, not respecting define, require nesting. other magic misbehaviors) switched to Curl.JS and started to sleep well at night. It's not as hyped, but, damn, it is stable and easy to work with!
    – ddotsenko
    Commented Feb 4, 2012 at 20:42
1

In addition to jhs's answer, see the more recent instructions on the require-jquery github page from the README.md file. It covers both the simplest approach of using a combined jquery/require.js file and also how to use a separate jquery.js.

Not the answer you're looking for? Browse other questions tagged or ask your own question.