Object JavaScript – Getting Started with Modules Using RequireJS

imageRequireJS 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 NodeJS. Using a modular script loader like RequireJS will improve the speed and quality of your code.

When a project reaches a certain size, managing the script modules for a project starts to get tricky. You need to be sure to sequence the scripts in the right order, and you need to start seriously thinking about combining scripts together into a bundle for deployment, so that only one or a very small number of requests are made to load the scripts.

You may also want to load code on the fly, after page load.

RequireJS can help you manage the script modules, load them in the right order, and make it easy to combine the scripts later via the RequireJS optimizer without needing to change your markup. It also gives you an easy way to load scripts after the page has loaded, allowing you to spread out the download size over time.

RequireJS has a module system that lets you define well-scoped modules, but you do not have to follow that system to get the benefits of dependency management and build-time optimizations. Over time, if you start to create more modular code that needs to be reused in a few places, the module format for RequireJS makes it easy to write encapsulated code that can be loaded on the fly. It can grow with you, particularly if you want to incorporate internationalization (i18n) string bundles, to localize your project for different languages, or load some HTML strings and make sure those strings are available before executing code, or even use JSONP services as dependencies.

From the RequireJS documentation:

A module is different from a traditional script file in that it defines a well-scoped object that avoids polluting the global namespace. It can explicitly list its dependencies and get a handle on those dependencies without needing to refer to global objects, but instead receive the dependencies as arguments to the function that defines the module. Modules in RequireJS are an extension of the Module Pattern, with the benefit of not needing globals to refer to other modules.

Compatibility

RequireJS is compatible with IE 6 and greater, Firefox 2 and greater, Safari 3.2 and greater, Chrome 3 and greater, and Opera 10 and greater.

How to Get Require.js

All you need to start using require.js is the browser. Then you add the RequireJS library in your Scripts of src folder.

  • If you are running on Node.js, and want to use npm to install this file via npm, see the Use with Node page for more information.
  • For information on its use, as well as how to get the JAR files to run it under Rhino, see the r.js README.
  • You can get it from  from requirejs.org.
  • Available in NuGet for your Visual Studio projects.

image

Using Require.JS

To begin, you can think of RequireJS as having two parts. Let’s say you want to create your own code that has certain requirements. You do this by:

  • Defining a module. In this step, you’ll write the code that you want to execute and describe its dependencies.
  • Requiring a module. Once you define your module, you can use it in your main code.
  • Starting up your module. In this step, you’ll see how to load RequireJS, your code, and the code that is required.
  • Incorporating libraries, such as jQuery, which does not provide support for RequireJS out of the box. In this step, you’ll see how you can use libraries as modules.

Quick Note About Namespaces in  JavaScript Modules

We did a lot of discussion about namespace and their goodness in Scope, Namespaces, “use strict”. With modules, you already have a naming convention that you use when you define the module.

No more namespacing — AMDs obviate the need for namespacing such as foo.bar.myModule, via a global variable and nested objects. The namespacing is in the path to the file, a local variable is short and convenient handle.

Define a Module

You can define a module in three steps:

  1. Give your module a ModuleID.
  2. Define dependencies. Dependencies are defined as an array. If there are no dependencies, then it is an empty array. Otherwise, you can have a list in an array.
  3. Define the module factory. This is the code that you want to execute in your module.

Here’s where the files in this post.

image

In step 1, you define your module with a module ID.

Next you can define the dependencies. Use RequireJS’s define method to define your module. You pass in the name of the module as the first parameter, then an array of dependencies, followed by the thing you want to do.


// in Scripts/discount.js
define(
// Module ID
'discount',
// no dependencies here, but RequireJS is smart enough to figure that out
// but if you had some, they would go here
// the thing you want to do
function () {
// properties
var pct = 0,
// methods
calculateDiscount = function (level) {
switch (level) {
case 'partner':
pct = 10;
break;
case 'employee':
pct = 27;
break;
default:
pct = 0;
}
return pct;
}
return {
calculateDiscount: calculateDiscount
};
});

Now the moduleID is optional, as are the list of dependencies.

IMPORTANT: Only one module should be defined per JavaScript file, given the nature of the module name-to-file-path lookup algorithm.

The ModuleID

The ModuleID is actually optional, and is often not needed. The default moduleID is its filename (but without the .js extension). When you want to require a module as a dependency, you can do so by passing the path to that file. You will see that in the next section.

The dependencies

The dependencies are names of modules.  And these dependencies are passed to your module in the same order they were in the dependency array.

The module’s factory function

The module’s factory function uses the revealing module pattern.  The function will be called to define the module once all dependencies have loaded. The function should return an object that defines the module. The dependencies will be passed to the definition function as function arguments, listed in the same order as the order in the dependency array.

Sample of a module with a dependency

In the following example, the product module needs access to the discount module to perform some action. In this case the product module uses the discount module to calculate a price after a discount is applied.


// in project.js
define(
// an optional module ID
'product',
// this module needs the discount.js as a dependency
['discount'],
// the requireJS loader provides discount as a parameter.
// if you have more than one in the array above, then you get
// them in the same order for your function.
function (discount) {
// properties
var productName = '';
var price = 1;
var discountedPrice = function (level) {
return price (price * discount.calculatDiscount(level));
};
return {
productName: productName,
price: price,
discountedPrice: discountedPrice
};
});

Require a Module

Now that you have your module, you will want to require it before you perform some function. For example, you might want to use

For example, a function can require jQuery and some code you have written in a module called discount and alterter from above. Your function can then safely use dataservice and alerter, knowing that it has been loaded before this function is called.


// on product.html
// load the discount.js and use that module to calculate employee discount
require(
// name of module that is required, ie the depenency
['discount'],
// the function that uses the discount object
function (discount) {
var d = discount.calculateDiscount('employee');
document.write('employee discount is ' + d + '%');
});

Shim Config to Help the Loader

Ideally the scripts you load will be modules that are defined by calling define(). However, you may need to use some traditional/legacy “browser globals” scripts that do not express their dependencies via define(). For those, you can use the shim config. To properly express their dependencies.


requirejs.config({
//By default load any module IDs from js/lib
baseUrl: 'Scripts',
//except, if the module ID starts with "app",
//load it from the Scripts/app directory. paths
//config is relative to the baseUrl, and
//never includes a ".js" extension since
//the paths config could be for a directory.
paths: {
app: '../app'
}
});

Starting RequireJS

You tell your Web page where to find require.js:

<script  src="scripts/require.js"></script>

Then you can run your config and find and run code that has dependencies. 

The entire page would look like this:


//product.html
<!DOCTYPE html>
<html>
<head>
<title>Simple RequireJS Sample</title>
<script src="scripts/require.js"></script>
<script>
requirejs.config({
//By default load any module IDs from Scripts folder
baseUrl: 'Scripts'
});
// load the discount.js and use that module to calculate employee discount
require(['discount'],
function (discount) {
var d = discount.calculateDiscount('employee');
document.write('employee discount is ' + d + '%');
});
</script>
</head>
<body>
</body>
</html>

Loader Plugins

You can extend the functionality of RequireJS through plugins. I’ve found them to be quite useful. These are useful loader plugins:

  • text. Load text files and treat them as dependencies. Great for loading templates. The text strings can be inlined in an optimized build when the optimizer is used.
  • dom-ready. Wait for the DOM is ready. Useful for pausing execution of top level application logic until the DOM is ready for querying/modification.
  • cs (CoffeeScript). Load files written in CoffeeScript.
  • i18n. Load string bundles used in internationalization (i18n) that are made up of separate country/language/locale-specific bundles.

Sample Code

Resources