Single Page App – Using RequireJS Asynchronous Module Definition (AMD) Modules with jQuery, LoDash

image6[1]In the previous post, you learned how you can use RequireJS in projects to define your own loading order, and how to build your own modules.

This tutorial go into depth on how to use RequireJS for AMD (Asynchronous Module Definition) modules. You will write we can write our own modules and load them with RequireJS.

In this tutorial you will build a small app that uses LoDash and jQuery. If you want to use Underscore, just substitute Underscore for the LoDash references.

Although you can use a bunch of <script> tags to load the libraries, your page is blocked during the load. And you could minify them and maintain the order in your own code. But with RequireJS, you include the RequireJS source and let it load the files.

Prerequisites

This post relies on what you have learned in:

Other helpful posts include:

The Combined Project

Let’s start with your project. This project combines LoDash, RequireJS, and HTML Templates

image

I’ve used NuGet to load my libraries and left them in the Scripts folder so that I can use NuGet to maintain the version dependencies for me. I’ve added an Scripts/app folder that contains my app.js file. And a Scripts/modules folder that will contain all my self-written modules – in this case, a template.js file – that I can reuse across apps.

My 0-RequireJSExample.html  file is my single page application (SPA).

If you put files in other directories, which you certainly can do, you will need to adjust the paths. As you will learn in the next section, the paths are all based on the relative location from your app.js file.

Loading Require.JS and Our App

Lets begin by adding a line in to load both RequireJS and to automatically load app.js.

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

Note that you include the path to app.js, but you leave off the .js part of the filename. This also sets the base path for loading in files. Whenever we load in a file with RequireJS, it will treat the folder app.js is in as the base path and load all files relative to that.

Require Modules/Dependencies

Often in your own app code, you will use modules that have been written by others. And you want to be sure those libraries are loaded in the right way. So your module will have some dependencies. As a generic example, you might have want to require a module named myFile that you would want loaded before your module uses a myFile method.

Your module would look like this:

require(['myfile'], function(myFile) {
  myFile.init();
});

This code would look fir myfile.js in the same directory as your main JS file, in our case the Scripts/app folder. And you can then use whatever is in myfile.js.

Define Your Modules

Use the define function RequireJS to define your modules. When you module has dependencies, the first argument should be an array of dependency names, and the second argument should be a definition function.

For example (from the RequireJS documentation) that is a file app/shirt.js:

//my/shirt.js now has some dependencies, a cart and inventory
//module in the same directory as shirt.js
define(["./cart", "./inventory"], function(cart, inventory) {
  //return an object to define the "my/shirt" module.
  return {
    color: "blue",
    size: "large",
    addToCart: function() {
      inventory.decrement(this);
      cart.add(this);
    }
  }
});

The order of the function arguments should match the order of the dependencies.

Modules that define globals are explicitly discouraged.

There should only be one module definition per file on disk.

Usually when defining your own modules you do not explicitly name it, because the name is automatically generated by the file name. You reference yoru module based on that file name and the directory structure.

jQuery Already Defines Itself

As of jQuery 1.7, it comes with support for AMD as it implements the AMD spec. At the bottom of the jQuery file, you will find this line of code.

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

What that means is that whenever you need jQuery, you can require it:

require(['jquery'], function() {
  //some code
});

But that assumes that jQuery is in the same folder as app.js.

LoDash Defines Itself as Underscore

Because of the close affinity between LoDash and Underscore, LoDash defines with the Underscore module name. On lines 5534 in the not-mimified version you will find:

// define as an anonymous module so, through path mapping, it can be
// referenced as the "underscore" module
define(function() {
  return _;
});

And that means I can require LoDash using the following code:

require(['_'], function() {
  //some code
});

Using require.config

Because the paths to your files may not be the same as the folder that holds app.js, use require.config to define the paths to those modules. For example, using my directory structure:

require.config({
  paths: {
    // "jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min",
    "jquery": "../../Scripts/jquery-2.0.3",
    "_": "../../Scripts/lodash",
  }
});

You can also use config to use your favorite CDN by naming it.

IMPORTANT: Be sure to leave the “.js” off of your path name.

Put the require.config method into the app.js file.

Our Template Module

This will provide a method that will compile a basic Underscore/LoDash template and display it on the page. Write your module in Scripts/modules/template.js

Define a simple template function that requires LoDash and jQuery. You create a (private) function named showName that takes takes a variable n. Next you create a simple LoDash template and compile it into the variable temp. Then apply the compiled template to the name n that you passed in. Finally, return the showName method so you can access it outside your module.

define(['_', 'jquery'], function() {
  var showName = function(n) {
    var temp = _.template("Hello <%= name %>");
    $("body").html(temp({name: n}));
  };
  return {
    showName: showName
  };
});

The define will use the path that you declared in your require.config method to find the right libraries.

Applying the Template

In order to call the template, you require the template module, then call showName() from Scripts/app/app.js.

require(['../modules/template'], function(template) {
  template.showName("Jack");
});

Example Code

Here is the finished example. It is only about a dozen lines of code.

0-RequireJSExample.html

Scripts/app/app.js

Scripts/modules/template.js

Sample Code

Sample code for this post has bee posted on GitHub: https://github.com/devdays/object-javascript/tree/master/RequireLoDashTemplates

References

This article is based on the excellent tutorial Introduction to RequireJS. But I use LoDash instead of Underscore and I use a different directory structure.

Require.JS

Advertisements

One comment

  1. Pingback: Single Page App – Loading, Caching LoDash or Underscore Templates Using RequireJS, AppCache | DevDays®