Imediava's Blog

Just another WordPress.com site

Tag Archives: requirejs

Introduction to Require.js

In a programming language like Java you normally don’t need to pay attention to how dependencies are loaded. All you need to do is define your dependencies with a fully qualified name (e.g. import java.utils.Collection) and the loading is done transparently by the JVM.

However when you move to JavaScript the landscape changes and you realize that loading dependencies is not a simple process. JavaScript doesn’t initially define a smart module system, what means that the programmer needs to take care of it by himself, making modularisation difficult.

Let’s have a look at an example of a project and the dependencies that are defined within its modules. The dependencies are represented as arrows from the client module on the left to the required module on the right:

module1 → module 2 → module3, module4

With this system in JavaScript, every time you need to use the module1, all the other modules need to be imported in the right order in the following manner:

<script type="text/javascript" src="module4”></script
<script type="text/javascript" src="module3”></script>
<script type="text/javascript" src="module2"></script>
<script type="text/javascript" src="module1"></script>

Whereas in Java a similar system could be defined like this:

//Module 1
import module2; 

class Module1 { .. }

//Module 2
import module3;
import module4;

class Module2 { .. }

// And a client module would only need to import module1
import module1;

class Client { .. }

Disadvantages of Javascript

We can see that JavaScript’s approach is less adequate:

  • It means that every time we want to use module1 we have to first have a look at which are its dependencies recursively.
  • What makes it even worst those dependencies need to be defined every time the module is used.
  • If the dependencies change, they need to be redefined in every module that imports module1. If someone is using module1 and forgets or is not informed of the changes, its code would stop working without any previous notice regardless of if there have been any changes in module1′s public API.

CommonJS and Require.js

The good news are that there are ways on JavaScript of defining hierarchies of dependencies in a way pretty similar to that of languages like Java.

In platforms like Node and Rhino, you can use the “require” function that allows to load dependencies of modules that have been defined using the CommonJS specification. However this loading mechanism is not specially suited for JavaScript on the browser where loading synchronously is not the more appropriate mechanism. Luckily Require.js exists, a library that allows defining dependencies between modules in a way that is appropriate for the browser.

Applying Require.js to our initial example

To allow a module to be imported with requirejs you need to wrap your javascript in a module format defined by the library. Fortunately the format is really simple. Let’s start applying it to the leafs of our hierarchy, the modules 3 and 4.

define(function(){

     // Code defining the module (private code)
     ....

     // It returns the properties that form the module's public API
     return {
         myMethod1: function(){ .. } 
         myProp1: value
     };
});

All we need to do is wrap our code in a call to define and pass it a callback function. The callback function must return the methods and properties of the module that you want to make available to its clients , it’s public API . This is done in a way that follows the Module Pattern a pattern that has as purpose to preserve the encapsulation of modules. Despite of wether or not you’re interested in using requirejs you should definitely use the Module Pattern when programming in Javascript to protect the clients of your module and to avoid polluting the namespace.

When you’re defining modules that have dependencies on other modules like module1 and module2, the definition doesn’t change that much. The only modification requires to provide as the first argument to the define function an array with the dependencies of the modules (the imports) and as many parameters as imported modules to the callback function. Taking as an example module2 the definition would be the following.

define([“module3”, “module4”], function(module3, module4){

   // Any code 
   ...

   // Accessing the methods of the imported modules is done
   // through the parameters of the callback function

   module3.myMethod1();
});

Loading any module would follow the same pattern keeping the benefit of only having to define direct dependencies.

Finally defining the starting point

Any Javascript application that uses requirejs needs to have a starting point. It is something similar to how an application in Java has to have a class with a main method. This starting point uses the require function to define its dependencies. This function works just like define by passing an array of dependencies and a callback function with the code that will run when the dependencies are loaded.

require([“module1”], function(module1){
   // Code to run as a main method
   ....
});
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: