Loading JavaScript with RequireJS

RequireJS according to it’s website is…

…a JavaScript file and module loader. It is optimized for in-browser use, but it can be used in other JavaScript environments, like Rhino and Node. Using a modular script loader like RequireJS will improve the speed and quality of your code.

In this section we will walk through some basics on how and when you can use RequireJS and discuss some of the benefits you may get from doing so. Personally, I’ve always thought that RequireJS can be a somewhat confusing concept to wrap one’s head around at first. I think this may have mainly been because a lot of times RequireJS is demonstrated in the context of a big web application project and it can sometimes be difficult to follow what its responsibilities are in the midst of numerous files doing all sorts of different things. So we are going to start off very very slowly (we’re just going to use it to load a couple JavaScript files) and we will look at doing more in depth things later on.

You can grab the demo files below from this tutorial if you want to follow along…

Demo Files

Why Use RequireJS?

Why would you want to use RequireJS? Well there can be a number of reasons but at the bottom of it all the main purposes are to keep your JavaScript nice and organized, fast-loading, and easily extendable. If you are just doing a little bit of jQuery for a bit of enhancement on the front end of a website, then maybe RequireJS is a bit overkill for your purposes. However, the real value of RequireJS comes in when you start to develop larger client-side web applications that have numerous JavaScript files, with different dependencies, all interacting with one another..

Often times, if you look in an HTML document of you’ll see something like the following…

<!DOCTYPE html>
<html>
<head>
<title>Loading Scripts</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
<script src="js/underscore.js" type="text/javascript"></script> 
<script src="js/plugins.js" type="text/javascript"></script>  
<script src="js/scripts.js" type="text/javascript"></script>  
</head>
<body>

<h1>JavaScript Loading...</h1>
<div id="output"></div>

</body>
</html>

As we can see here, we’re loading jQuery, we loading some other libraries, we’re loading some jQuery plugins and we’re loading other scripts from other places. There might even be some more scripts that we’d load before the closing </body> tag. Just lots and lots and lots of script tags in the document. What RequireJS can do for us is take that out of the DOM and use JavaScript to load other JavaScript. Take a look at the HTML document below..

<!DOCTYPE html>
<html>
<head>
<title>Require JS</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script data-main="app/main" src="require.js"></script> 
</head>
<body>

<h1>RequireJS Loading...</h1>
<div id="output"></div>

</body>
</html>

You can see we have just the one tag there. That is what loads and RequireJS and that’s really all we’re going to need as far as script definitions in the DOM go (looks nice and clean, eh?). RequireJS is going to handle the loading of all the other JavaScript files and dependencies we may have (e.g. jQuery, Underscore, etc). We’re going to define how these files get loaded, where they get loaded from, and what happens after they are loaded and we don’t have to go mucking up to the DOM with massive numbers of script tags. That’s a big benefit of RequireJS. Also, in the case above where we’re loading multiple JavaScript tags in the DOM, we’re doing so sequentially so that the browser has to wait for each script and load and before it will continue loading the rest of them. This can cause things to slow down quite a bit. But with RequireJS scripts are loaded asynchronously, so that scripts are loaded in parallel and things are not slowed down by say a much larger script on a much slower connection loading faster than a smaller script on a quicker connection. What’s even more beneficial, is that we can still tell RequireJS not to run code until the required dependency is loaded. So. for example, we can make sure that wouldn’t attempt to run any jQuery before jQuery is loaded. RequireJS will handle that for us.

So to review the benefits…

1. Single point of entry, no mucking up the DOM with numerous script tags.
2. Asynchronous loading of scripts allows for faster load times where we can still tell require not to run code before the dependency is loaded.

Using RequireJS

Now let’s talk about the RequireJS script definition…

<script data-main="app/main" src="require.js"></script> 

The src attribute should be pretty familiar if you’ve ever loaded JavaScript before. We’re basically just specifying the path to the require.js file (which is in the root directory in this case). What about that data-main=”app/main”? Well, RequireJS loads file paths in pretty much the same way as normal only it drops the “.js” What this data/main attribute is saying is “Hey RequireJS, load the file main.js found in the “app” directory and use that as the starting point for loading and running all the rest of our JavaScript.” The important thing is notice how the .js is dropped off of main.js in the path and remember that this is how RequireJS specifies paths to JavaScript files. We’ll create the main.js file and write the code for it next.

Now let’s create a file called main.js and put it in a directory called ‘app’ RequireJS is in the root of the project (where the HTML file is).

require.config({
  paths: {
    jquery: 'libs/jquery/jquery',
    underscore: 'libs/underscore/underscore',
  }

});

What this is doing is defining the paths to our JavaScript files from where this main.js file is located. And like with the data-main attribute above, the convention is to drop the “.js” from the end of each file. So the full path to each of these files from the root of our application so far would be app/libs/jquery/jquery.js and app/libs/underscore/underscore.js respectively.

What’s nice about having these other files defined is that we can easily set paths over HTTP if we wanted to as well. So if we wanted to we could change the code above to…

require.config({
  paths: {
    jquery: 'https://code.jquery.com/jquery-latest',
    underscore: 'libs/underscore/underscore',
  }

});

Where we are loading jQuery from the jQuery’s home site (just remember that the .js is dropped here as well so the full path to the file is actually https://code.jquery.com/jquery-latest.js).

Now below this let’s add some code below this config definition so that our file looks like the following…

require.config({
  paths: {
    jquery: 'libs/jquery/jquery',
    underscore: 'libs/underscore/underscore',
  }

});
require(['jquery'], function($){ 
    $('#output').html('We have now loaded jQuery...');
});

What are we doing here? Well here is where we are executing our jQuery after it has been loaded. Notice that jQuery uses the $ so what RequireJS is saying is load the first dependency in our config (jQuery) and pass in the $ as the marker that maps to jQuery. Remember in the HTML we had a <div> with the id of “output”. Here is a demonstration of how we can load jQuery through RequireJS and use it! We wouldn’t be able to use jQuery if we hadn’t loaded it successfully with RequireJS. Congratulations! You’ve just completed your first load.

What if we wanted to load something else? Let’s add UnderscoreJS to our list of items we are loading.

require.config({
  paths: {
    jquery: 'libs/jquery/jquery',
    underscore: 'libs/underscore/underscore',
  }

});
require(['jquery', 'underscore'], function($, _){ 
    $('#output').html('We have now loaded jQuery...');
    alert(window._.isEmpty({ name: 'Joe'}));
 
});

As you can see we have loaded Underscore.js and we get an alert of ‘false’ because the object we are passing in is not empty. This means that we know that we have loaded Underscore successfully because we would get an error otherwise.

So as we can see we are using JavaScript to load other JavaScript and really we could load as many libraries as we want! We just have to keep adding to our config paths and the array of properties that RequireJS takes in.

What About Loading Our Own JavaScript?

To load our own JavaScript files we do something similar. We can just include the path how we did it for the others. Let’s create an app.js file that is in the same directory as main.js. We can specify the path as being just the file name because it is in the same directory (or we wanted to we could even omit it and RequireJS will still look for it here). But in case you wanted to put it somewhere else for whatever reason, it’s good practice to have the path definned here.

require.config({
  paths: {
    jquery: 'libs/jquery/jquery',
    underscore: 'libs/underscore/underscore',
    app: 'app'
  }

});
require(['jquery', 'underscore', 'app'], function($, _, App){ 
    $('#output').html('We have now loaded jQuery...');
    alert(window._.isEmpty({ name: 'Joe'}));
    //do something with App here....
});

Now in App we can just start typing out any old JavaScript that we want but we’re most likely going to want to load the same dependencies such as jQuery and UnderscoreJS so that we can use them in our app.js file. So let’s use RequireJS to load them…

define(['jquery','underscore'], function($, _){

    console.log('Hello from App!');
	
    var initialize = function(){
       console.log('Initialize function has been called from main.js...')
    };

});

And if we can even have our app code return something so we can run it inside of main if we want.

define(['jquery','underscore'], function($, _){

    console.log('Hello from App!');
	
    var initialize = function(){
       console.log('Initialize function has been called from main.js...')
    };

    return { 
        init: initialize
    };
});

Now we can see that when we call App.init() in main.js, that function in app.js will run…

require.config({
  paths: {
    jquery: 'libs/jquery/jquery',
    underscore: 'libs/underscore/underscore',
    app: 'app'
  }

});
require(['jquery', 'underscore', 'app'], function($, _, App){ 
    $('#output').html('We have now loaded jQuery...');
    alert(window._.isEmpty({ name: 'Joe'}));
    App.init();
});

Shims

We should have a very brief discussion of shims and the use of the shim object in RequireJS. If you noticed up above when we used Underscore we had to say “window._” as opposed to just “_”. We could do this with jQuery using the ($) but we couldn’t with Underscore. Why is that? RequireJS implements the asynchronous module definition (AMD) pattern. Basically that just means that we load small little chunks of code where we can know what dependencies have already been loaded and run them, returning an object that other modules can use. It’s what we’ve been doing all along in using RequireJS. RequireJS website discusses the reasons for why AMD is important here

The AMD format comes from wanting a module format that was better than today’s write a bunch of script tags with implicit dependencies that you have to manually order and something that was easy to use directly in the browser. Something with good debugging characteristics that did not require server-specific tooling to get started.

Remember, as we discussed above, one of the main reasons we wanted to use RequireJS is that we wanted to get away from having a whole bunch of <script> tags in our DOM.

AMD is nice, but it’s important to keep in mind that not all JavaScript libraries support this pattern. Underscore.js, for example, is one of the libraries that does not return a global object that we can just use. In contrast, jQuery (version 1.7+) does support AMD by giving us the $ and even our own module “App” was returned. But with Underscore, we had to use it in the global window object.

To enable Underscore to be implemented into our RequireJS AMD pattern, we can specify this in the shim object. Edit the config function to become the following…

require.config({
    paths: {
        'jquery': 'https://code.jquery.com/jquery-latest',
        'underscore': 'libs/underscore/underscore',
        'app': 'app'
    },
    shim: {
        'underscore': {
             exports: '_'
        }
    }
});

Now we should be able to use the “_” character wherever we want.

require(['jquery', 'underscore', 'app'], function($, _, App){ 
    $('#output').html('We have now loaded jQuery...');
    console.log(_.isEmpty({ name: 'Joe'}));
    App.init();
});

The window object is no longer needed because we now have the “_” available globally. Backbone.js is another popular application library (written by the same developer who developed Underscore) that doesn’t support AMD. However, many developers like using RequireJS for their Backbone applications. As a result of this Backbone would also need to be defined in the shim if you wanted to use RequireJS….

    shim: {
        'underscore': {
             exports: '_'
        },
        'backbone': {
            exports: 'Backbone',
        }	
    }

So there you have it. That concludes our basic rundown of loading JavaScript files with RequireJS. Hopefully, it hasn’t been too painful an experience. Feel free to grab the demo files below from this tutorial below and experiment…

Demo Files
, , , , 9bit Studios E-Books

Like this post? How about a share?

Stay Updated with the 9bit Studios Newsletter

1 Response to Loading JavaScript with RequireJS

  1. Vivek C says:

    Thanks for this great article, Ian! Surprised to see someone respond 6 years after you wrote this? 🙂 Well, the documentation on requirejs.org is confusing for a beginner even today, and your article here really helped to get started. Hope you still enjoy code, beer and coffee. Cheers!

Leave a Reply

Your email address will not be published. Required fields are marked *