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.
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.
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.
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:
- Give your module a ModuleID.
- 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.
- Define the module factory. This is the code that you want to execute in your module.
Here’s where the files in this post.
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.
Now the moduleID is optional, as are the list of dependencies.
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 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.
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.
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.
You tell your Web page where to find require.js:
Then you can run your config and find and run code that has dependencies.
The entire page would look like this:
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.
- John Papa’s demo at https://github.com/johnpapa/kis-requirejs-demo
- Asynchronous Module Definition (AMD) API
- Why AMD?
- Getting started with HTML mobile application development using jQuery Mobile, RequireJS and BackboneJS
- James Burke’s blog