LLB Web App Series Part 2: Require.js

This is part 2 of the series. This is a series dedicated to explaining a bunch of helpful web development tools in the simplest language possible. For a full recap, or if you start feeling confused, check out part 1. Note that the term ‘app’ I use in this series could easily be changed to ‘website’. These days, most complex websites are web apps.

requre.js



Require.js – Why should you care?

Because it makes your app: faster (hence giving a better user experience), better organized(making it easier to improve your code) more scaleable (fewer updates, more paydays) and because boffins use it – so you should try and understand how it works so you can learn from others.

OK. We’re going to continue working on the simple web app we were looking at in part 1. Here’s the new source code.

We’ve decided that we want to be able to load all our javascript separately from the rest of our app files by using Require.js – the fancy term for this is Asynchronous Module Definition. For example, if you have an app with a landing page and a payments page, and which uses jquery, you wouldn’t want to load the javascript file dealing with payments when a user navigated to the landing page. This would be a waste of resources. Furthermore, you would want to make sure that jQuery was loaded before your other javascript files (otherwise they would break). Require.js helps you with all this.

Before we look at Require.js, let’s assume we’ve decided to implement a few coding best practices, which we didn’t bother with in part 1 for simplicity. First of all, we’re going to put our Javascript in separate files (in this case, one file to begin with), and we’re going to use jQuery (which we downloaded with Bower in part 1) because jQuery makes using Javascript way easier. We’ll call the first javascript file main.js and before we do any require.js stuff it will look like this:

Note that all text after “//” is comments to help you understand the code:

<br></br>
$(document).on('ready', function() { //uses the jQuery 'ready'<br></br>
//function to only execute the page once everything is loaded```
  
`  $('#buttonTest').on('click', hideStuff);`  
`  function hideStuff() {`  
`    // Line below hides the text `  
`    $('#myText').css('display', 'none');`  
`  }`  
`});`

So that’s the main.js without require.js.

Now we need to download require.js – let’s use Bower to do this. Open the bower.json file, and add require.js to the list of dependencies like so:

[![bower.json](http://thelifelifebalance.com/wp-content/uploads/2014/02/requirejsbower.jpg)](http://thelifelifebalance.com/wp-content/uploads/2014/02/requirejsbower.jpg)

Now open a command prompt and navigate to the folder where the bower.json file is, and run “bower install”. You’ll see that require.js is downloaded into your bower_components folder.

Now we add a reference to the require.js file in a script tag in our index.html file. Crucially, we also add a ‘data-main’ attribute to the script tag, and specify the name of our ‘root’ javascript file (the first file we want to start using). If you’ve never seen the ‘data’ attribute before, it’s one of the newer HTML5 attributes, and allows you to store extra info. In our case, ‘main.js’ is the root javascript file, so we put the directory of this file (note that in the data attribute you do not have to specify a file extension. So this looks like:

[![Data Attribute](http://thelifelifebalance.com/wp-content/uploads/2014/02/dataAttributeTag-300x24.jpg)](http://thelifelifebalance.com/wp-content/uploads/2014/02/dataAttributeTag.jpg)





This is where require.js kicks in – now we need to configure the ‘main.js’ file to make use of require.js (recall how the file looked before – see code above). First, we configure require.js:

`requirejs.config({ //this initiates the configuration `  
`  paths: {`  
`    jquery: '../bower_components/jquery/jquery'`  
`  }`  
`});`

OK – so far we’re just telling require.js where to find different resources, in this case jquery. Now we can just refer to ‘jquery’ throughout the file.

What now?

Well basically there are two key things to understand about require.js: ‘define’ and ‘require’. In the demo source code main.js file, we can see that underneath the requirejs.config, we have the following:

`require(["app"],function(app){`  
`app.hideStuff();`  
`});`

The require function can take a bunch of arguments. Above, the stuff in the array (i.e. the square brackets) is listing the dependencies of the function being called. So in this case, ['app'] is a dependency of the function. You can infer from this that I have sneakily created a second javascript file: app.js. This is where the hideStuff() function now lives. Then, the actual ‘meat’ of what is being required comes: the function. A hard thing to understand here is why we are repeating ‘app’ as the function argument. This is because you have to pass into your function all dependencies <strong>as arguments</strong> This certainly took me a while to figure out.

So to recap, I’m going to `require` the app file (marked with the square brackets), then use a function from app.js here in main.js. Now I can call the method ‘hidestuff’ on the line below. Since ‘hidestuff’ is in the app.js file, I have to prefeace it with its ‘parent’ file: <code>app.hideStuff()</code>(remember to add the open and close parenthesis in order to actually run the function).

However, this is a two step process. Our app.js file is being accessed because it is a module. Modules are good because they allow us to break our code up into different files which do different things, so that if something breaks, we know where to look. Programmers call this ‘separation of concerns’. They also call it, ‘avoiding spaghetti code’. In order to make app.js a module, we have to `define` it as an accessible module.

This might not yet make sense, so let’s jump to app.js and look at the code:

`define(["jquery"], function(jquery) {` //Notice the function takes the //jquery dependency as its argument.

`return {` //The return statement indicates everything from this module you //want to be able to use in other files  
`hideStuff: function() {`  
`  $('#buttonTest').on('click', function(){`  
`  $('#myText').css('display', 'none');`  
`});`  
`console.log('LLB App working with Require.js');`  
`}`  
`}`  
`});`

Before you start feeling confused – look at what is familiar here – the jquery ‘hideStuff’ function (which was in main.js before we implemented require.js). This hides the text when the button is clicked – should be familiar to anyone who has used jquery. Notice also that <code>define</code also has an array as an argument, which has the same meaning as in <code>require</code>, i.e. listing any dependencies. Because we have defined the ‘app’ module, we can access everything we return from the app module in other files. If our file looked like this:

`define(["jquery"], function(jquery) {` //Notice the file begins with ‘define’.

`  hideStuff: function() {`  
`    $('#buttonTest').on('click', function(){`  
`    $('#myText').css('display', 'none');`  
`  });`  
`  console.log('LLB App working with Require.js');`  
`  }`  
`}`  
`});`

`return;`

Then we would not be able to access the ‘hideStuff’ function in other files.

So this is basically how you use require.js – you whack it into your html, you define a bunch of modules, then you require those modules whenever you need to use something from them. As with the previous example, no one in their right mind would use require.js on a simple app like the one we have in our example. But when you have a complex application, with 20+ javascript files (very easy when you’re using a framework like Backbone), then imagine trying load all those files using multiple HTML script tags **in the correct load order**? Exactly, a nightmare.

A much better coder than me has written a great article explaining the module pattern which require.js is built upon [here.](http://netmvc.blogspot.be/2012/11/javascript-modularity-with-requirejs.html)

So hopefully my rambling made some sense. Check back for part 3.

SOURCE CODE [HERE](https://github.com/ChristopherGS/llbRequireTest)