Understanding RequireJS for Effective JavaScript Module Loading

Share this article

Modular programming is used to break large applications into smaller blocks of manageable code. Module based coding eases the effort for maintenance and increases reusability. However, managing dependencies between modules is a major concern developers face throughout the application development process. RequireJS is one of the most popular frameworks around for managing dependencies between modules. This tutorial examines the need for modularized code, and shows how RequireJS can help.

Key Takeaways

  • RequireJS is a popular framework used for managing dependencies between modules in JavaScript, which improves the speed and quality of code, particularly in large projects.
  • RequireJS uses Asynchronous Module Loading (AMD) for loading files, which allows scripts to load modules and their dependencies in a non-blocking manner.
  • In RequireJS, all code is wrapped in require() or define() functions. The require() function is used for immediate functionalities, while define() is used for defining modules for use in multiple locations.
  • RequireJS improves code quality by promoting modularity and separation of concerns, reducing the risk of naming collisions by keeping the global scope clean, and providing a robust error handling mechanism.

Loading JavaScript Files

Large applications often require a number of JavaScript files. Generally, they are loaded one by one using <script> tags. Additionally, each file can potentially be dependent on other files. The most common example would be jQuery plugins, which are all dependent upon the core jQuery library. Therefore, jQuery must be loaded before any of its plugins. Let’s look at a simple example of JavaScript file loading in real applications. Assume we have the following three JavaScript files. purchase.js
function purchaseProduct(){
console.log("Function : purchaseProduct");

var credits = getCredits();
if(credits > 0){
reserveProduct();
return true;
}
return false;
}
products.js
function reserveProduct(){
console.log("Function : reserveProduct");

return true;
}
credits.js
function getCredits(){
console.log("Function : getCredits");

var credits = "100";
return credits;
}
In this example, we are trying to purchase a product. First, it checks whether enough credits are available to purchase the product. Then, upon credit validation, it reserves the product. Another script, main.js, initializes the code by calling purchaseProduct(), as shown below.
var result = purchaseProduct();

What Can Go Wrong?

In this example, purchase.js depends upon both credits.js and products.js. Therefore, those files need to be loaded before calling purchaseProduct(). So, what would happen if we included our JavaScript files in the following order?
<script src="products.js"></script>
<script src="purchase.js"></script>
<script src="main.js"></script>
<script src="credits.js"></script>
Here, initialization is done before credits.js is loaded. This will result in the error shown below. And this example only requires three JavaScript files. In a much larger project, things can easily get out of control. That’s where RequireJS comes into the picture. Plain JavaScript Example

Introduction to RequireJS

RequireJS is a well known JavaScript module and file loader which is supported in the latest versions of popular browsers. In RequireJS we separate code into modules which each handle a single responsibility. Additionally, dependencies need to be configured when loading files. Let’s get started by downloading RequireJS. Once downloaded, copy the file to your project folder. Let’s assume our project’s directory structure now resembles the following image. Folder Structure All the JavaScript files, including the RequireJS file, are located inside the scripts folder. The file main.js is used for initialization, and the other files contain application logic. Let’s see how the scripts are included inside the HTML file.
<script data-main="scripts/main" src="scripts/require.js"></script>
This is the only code required to include files using RequireJS. You might be wondering what happened to the other files and how they are included. The data-main attribute defines the initialization point of the application. In this case, it is main.js. RequireJS uses main.js to look for other scripts and dependencies. In this scenario all the files are located in same folder. Using logic, you can move the files to any folder you prefer. Now, let’s take a look at main.js
.
require(["purchase"],function(purchase){
purchase.purchaseProduct();
});
In RequireJS, all code is wrapped in require() or define() functions. The first parameter of these functions specifies dependencies. In the previous example, initialization is dependent on purchase.js, since it defines purchaseProduct(). Note that the file extension has been omitted. This is because RequireJS only considers .js files. The second parameter to require() is an anonymous function which takes an object that is used to call the functions inside the dependent file. In this scenario, we have just one dependency. Multiple dependencies can be loaded using the following syntax.
require(["a","b","c"],function(a,b,c){
});

Creating Applications with RequireJS

In this section we are going to convert the plain JavaScript example discussed in the previous section into RequireJS. We already covered main.js, so let’s move on to the other files. purchase.js
define(["credits","products"], function(credits,products) {

console.log("Function : purchaseProduct");

return {
purchaseProduct: function() {

var credit = credits.getCredits();
if(credit > 0){
products.reserveProduct();
return true;
}
return false;
}
}
});
First, we declare that purchase functionality depends on credits and products. Inside the return statement, we can define the functions of each module. Here, we have called the getCredits() and reserveProduct() functions on the objects passed. product.js and credits.js are similar, and are shown below. products.js
define(function(products) {
return {
reserveProduct: function() {
console.log("Function : reserveProduct");

return true;
}
}
});
credits.js
define(function() {
console.log("Function : getCredits");

return {
getCredits: function() {
var credits = "100";
return credits;
}
}
});
Both of these files are configured as independent modules – meaning they are not dependent on anything. The important thing to notice is the use of define() instead of require(). Choosing between require() or define() depends on the structure of your code, and will be discussed in the following section.

Using require() vs. define()

Earlier I mentioned that we can use both require() and define() to load dependencies. Understanding the difference between those two functions is essential to managing dependencies. The require() function is used to run immediate functionalities, while define()
is used to define modules for use in multiple locations. In our example we need to run the purchaseProduct() function immediately. So, require() was used inside main.js. However, the other files are reusable modules and therefore use define().

Why RequireJS is Important

In the plain JavaScript example, an error was generated due to the incorrect order of file loading. Now, delete the credits.js file in the RequireJS example and see how it works. The following image shows the output of the browser inspection tool. RequireJS Example The difference here is that no code has been executed in the RequireJS example. We can confirm it since nothing is printed on the console. In the plain JavaScript example we had some output printed on the console before generating the error. RequireJS waits until all the dependent modules are loaded before executing the functionality. If any modules are missing, it doesn’t execute any code. This helps us maintain the consistency of our data.

Managing the Order of Dependent Files

RequireJS uses Asynchronous Module Loading (AMD) for loading files. Each dependent module will start loading through asynchronous requests in the given order. Even though the file order is considered, we cannot guarantee that the first file is loaded before the second file due to the asynchronous nature. So, RequireJS allows us to use the shim config to define the sequence of files which need to be loaded in correct order. Let’s see how we can create configuration options in RequireJS.
requirejs.config({
shim: {
'source1': ['dependency1','dependency2'],
'source2': ['source1']
}
});
RequireJS allows us to provide configuration options using the config() function. It accepts a parameter called shim which we can use to define the mandatory sequences of dependencies. You can find the complete configuration guide in the RequireJS API documentation.
define(["dependency1","dependency2","source1","source2"], function() {

);
Under normal circumstances these four files will start loading in the given order. Here, source2 depends on source1. So, once source1 has finished loading, source2 will think that all the dependencies are loaded. However, dependency1 and dependency2 may still be loading. Using the shim config, it is mandatory to load the dependencies before source1. Hence, errors will not be generated.

Conclusion

I hope this tutorial helps you get started with RequireJS. Although it seems simple, it is really powerful in managing dependencies in large scale JavaScript applications. This tutorial alone is not enough to cover all the aspects of RequireJs, so I hope you learn all the advanced configurations and techniques using the official website. And if you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, like Simply JavaScript. Comments on this article are closed. Have a question about JavaScript? Why not ask it on our forums?

Frequently Asked Questions (FAQs) about JavaScript Module Loading with RequireJS

What is the main purpose of using RequireJS in JavaScript?

RequireJS is a JavaScript file and module loader. It is optimized for in-browser use but can be used in other JavaScript environments as well. The main purpose of using RequireJS is to improve the speed and quality of your code. It helps you manage dependencies between your code modules and load scripts in an efficient manner. This is particularly useful in large projects where managing individual scripts can become complex. RequireJS also helps to keep the global scope clean by reducing the use of global variables.

How does RequireJS handle dependencies?

RequireJS handles dependencies through a mechanism known as Asynchronous Module Definition (AMD). This allows the script to load modules and their dependencies in a non-blocking manner. When you define a module, you specify its dependencies, and RequireJS ensures that these dependencies are loaded before the module itself. This way, you can be sure that all the necessary code is available when your module is executed.

Can RequireJS be used with Node.js?

Yes, RequireJS can be used with Node.js, although it’s more commonly used in the browser. When used with Node.js, RequireJS allows you to organize your server-side JavaScript code into modules, just like in the browser. However, Node.js has its own module system (CommonJS), so using RequireJS is not as common.

How does RequireJS improve code quality?

RequireJS improves code quality by promoting modularity and separation of concerns. By organizing your code into modules, each with its own specific functionality, you can write more maintainable and testable code. It also reduces the risk of naming collisions by keeping the global scope clean.

What is the difference between RequireJS and CommonJS?

Both RequireJS and CommonJS are module systems for JavaScript, but they have some key differences. RequireJS uses the Asynchronous Module Definition (AMD) format, which is designed to load modules and their dependencies asynchronously in the browser. On the other hand, CommonJS, which is used by Node.js, loads modules synchronously, which is more suitable for server-side environments.

How do I define a module in RequireJS?

In RequireJS, you define a module using the define function. This function takes two arguments: an array of dependencies and a factory function. The factory function is called once all the dependencies are loaded and should return the module’s value.

How do I load a module in RequireJS?

To load a module in RequireJS, you use the require function. This function takes two arguments: an array of dependencies and a callback function. The callback function is called once all the dependencies are loaded.

Can I use RequireJS with other JavaScript libraries?

Yes, RequireJS can be used with other JavaScript libraries like jQuery, Backbone, and Angular. It can load these libraries as modules and manage their dependencies.

How does RequireJS handle errors?

RequireJS has a robust error handling mechanism. If a script fails to load, RequireJS will trigger an error event. You can listen for this event and handle the error appropriately in your code.

Can I use RequireJS in a production environment?

Yes, RequireJS is suitable for both development and production environments. For production, RequireJS provides an optimization tool that combines and minifies your JavaScript files to improve load time.

Rakhitha NimeshRakhitha Nimesh
View Author

Rakhitha Nimesh is a software engineer and writer from Sri Lanka. He likes to develop applications and write on latest technologies. He is available for freelance writing and WordPress development. You can read his latest book on Building Impressive Presentations with Impress.js. He is a regular contributor to 1stWebDesigner, Tuts+ network and SitePoint network. Make sure to follow him on Google+.

Intermediate
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week