Better JavaScript organisation with RequireJS - Specialmoves

Better JavaScript
organisation with
Require JS

 Specialmoves Labs

When you've got lots of JavaScript files in a site you can run into problems. Each file you specify is another http request, every third-party plug-in can come with several dependencies that have to be included, and remembering what order things need to be executed in might not be obvious at first.

Require JS solves those problems and in this article, I'll let you know how this lightweight library can help you organise your JavaScript into well structured modules.

How Require works

First, download the Require JS library from http://requirejs.org and include it in your project; it should look something like this:

<script data-main="javascript/main" src="javascript/require-jquery.js"></script>

The data-main attribute specifies where all of your JavaScript it located. Require now knows the base URL for all your code so you don’t have to specify full paths to your files.

Require JS has 2 basic functions: define() and require(). define() is used to encapsulate your module and prepare it in a format the library can understand. require() is used to being them all together. Let’s take a look at the define part first and how we create our modules, before looking at how we would use them on a page.

A define module is typically written in the same style as the module pattern :

define(function() {	
	var obj = {
		multiply: function(a, b) {
			Return a * b;
		}
	};	
	return obj;
});

This example is nicely self-contained and returns an object with properties and methods. This is the most basic use of the define() function. If your modules had other dependencies (like jQuery or another library) you can specify it like this:

define(["some/plugin"], function(thePlugin) {
	var foo = thePlugin();
		
	return {
		color: "blue",
		bigNumber: function(arg){
			return arg * thePlugin()
		}
	}
});

The first argument is an array of file paths, relative to this module. Require loads this module and passes it to function call back in the second argument. This call back is only executed when the module has finished loading so we can be sure it is ready for use.

So now that we’ve got all our modules organised into nice little files we need a way to use them on our page and load them all in. This is where we use the require() function to bring all of this together. Let’s assume we have two modules, and the paths are: “modules/first-module.js” and “modules/second-module.js”, our code would look like this:

require( ["modules/first-module", "modules/second-module"], function(someModule, anotherModule) {
	var firstNumber = 20;
	var secondNumber = 10;
	var myVariable = someModule.method(firstNumber, secondNumber);
	var myProperty = anotherModule.bigNumber(firstNumber);
    }
  );

This code now pulls in our two modules dynamically. We access the methods and properties of these modules using the argument names passed to our callback. The benefit of this is that we have 2 perfectly namespaced modules. I can reference properties and methods on these objects with no chance of naming clashes. Already, RequireJS is helping us organise our code better. I don’t need to know the name of returned object in the 2 modules – I just need to know what can be done with them.

The second module required the use of a 3rd party plug in. You’ll notice that the code above doesn’t make any reference to it at all. The define() call in that module took care of that for us, so we don’t have to worry about it anymore. As long as modules look after themselves we can use them and not have to worry about dependencies. On a large project this dependency management can save you a lot of headaches.

The code is only executed once all of the modules have finished loading, meaning you don’t have to worry about the order of script execution.

Conclusion

Require JS is a great way to organise your code into smaller more manageable modules. Modules can be written without needing to know their intended implementation making them easier to reuse. They can manage their own dependencies and load resources as required instead of upfront, saving valuable loading times.

Next steps

There are lots of resources available on using Require JS and lots of ways you can include them in your projects. Our next step is to make Require modules more independent and implement mediators to control communication between modules. In the examples above we’ve relied on the module pattern to create a single instance of a module, but you might also want to use Require to help you create classes and create multiple instances of those classes.

---

Gary Stevens is a developer at specialmoves where he likes to make things modular, even his sandwiches. @garystevens

Follow us on Twitter @specialmoves