Require JS – Requires an explanation…

After going to a jQuery conference out in Mountain View I was more determined than ever to understand how to use script loaders to abstract my JavaScript code into a more object oriented approach. I always loved the ability in AS3 to break code up using OOP principles. I found the process of concatenating scripts to be clumsy and cumbersome. That being said I had heard of requireJS while I was at the conference and decided to give it a go. The examples below are my attempts to just get things flowing with require. They are by no means perfect.

Step 1: Add base dependency app.js

In this first line we are requiring one file to be loaded. In this case it is in the scripts directory and is named app.js

Step 2: Adding dependencies to app.js

The code within app.js will load a dependency file based on the array parameter in the define function. app.menu.js. Pretty slick! Each file you want to make available just needs to be included in this array parameter at the top. As you can see we are leaving the extension .js off since require doesn’t want it. Since we have also included app.menu.js we can easily return Menu which is a function defined in app.menu.js. Making sense?

Step 3: Adding dependencies to dependencies – app.menu.js

In this file we are using a simple JavaScript inheritance technique that John Resig blogged about Good Read here. All that really needs to be understood here is that within app.menu.js we are loading another file called inherit.js which contains that inheritance code. So now we have a reusable menu that can be worked on within app.menu.js and it will automagically be loaded when app.js is loaded. Reusable components. Toats!

Step 4: Wait a sec…

At this point you are probably thinking ok great. I can separate my logic into multiple JavaScript files but man you are killing me with all these HTTP requests. Arn’t those supposed to be like the worst for JavaScript performance?? And the answer is yup. We are killing it. But relax… This is on a local environment. That’s ok. When we push to dev or test is when we need a method to “compile” our JS code. (For lack of a better term)

Enter ANT…

Lucky for us requireJS comes with a tool for this process. Since we namespaced using APP in beginning when defining our JS objects we should have less conflicts when using the concat and minify tools on our JS. Ok let’s get started… First, we need to setup a generic optimize target. We can then call this over and over for different require dependency traversals. We are going to be invoking the java based engine Rhino along with Uglify.js for the minification. Don’t worry the rhino.jar file comes with requireJS so you shouldn’t need to download anything else. Let’s take a look at this generic ANT target.

We first define requirejs.dir as the path to our requirejs folder. We then tell java where the rhino jar file is. Next we are invoking rhino and passing it a baseUrl argument. This will be specific to where your JavaScript code is located in your project. Ours is just in a scripts folder off the root. Next we are passing in a variable for the name of the JavaScript file to traverse called “build-in-file”. This would be our app.js from the examples above. We also have an argument for the out file “build-out-file”. The last argument “excludeShallow=jquery” is basically saying if we have a dependency that requires jquery ignore it. As you can see in app.menu.js we are saying that jquery is required as a dependency however in our strategy we are loading it from an external CDN and want the benefits of caching so we chose to leave it out.

Step 5: Minify and Concatenation

Ok at this point you are prolly saying wow this is alot of steps. Or you stopped reading. Either way here’s the big pay off.

Here is an antcall to the generic -optimize target. It is going to run requireJS on app.js, traverse through, grab namespaces.js, app.menu.js, inherit.js (nested from inside app.menu.js), exclude jquery and concatenate and minify all those files into one file called app-build.js in the scripts directory. Oh Snap! Think about that for a second. Now you have the same power you had with Flash and compiling to one swf file with one HTTP request. This can be taken one step further as well and be combined with a CI server to automate all of this so you could have one core JavaScript file that would be used on every page along with page specific scripts. Neato!

4 comments

  • I also come from an AS3 oop background. Would it be possible to get an example of working files from you. I’m having problems understanding how to initialize functions in my loaded modules. Also having problems referencing them from other modules. Not sure what you mean in your above tut what namespaces.js does. Also what is App referring to, is this a function in menu.js. Would love to se how you setup your methods and properties in each js file and how you might reference those from other modules.

    Thanks.

  • Oops put a wrong email address in my last post.

  • Cool. I’m interested to know your thinking behind using namespaces within a modular design (assuming that’s what namespaces.js is for).

    If I understand correctly the whole point of something like AMD is to help you code de-coupled, re-usable modules. If you’re defining your dependencies up-front in each module why even bother using namespaces?

    • @James indeed. Honestly, my thinking was that at the time I really didn’t know better. I was learning require and as you point out the whole point of using an AMD loader is to de-couple and write re-usable modules. Which require was already doing for me : ) I have updated this post to be less confusing. Thanks for the feedback!

Leave a Reply

Your email address will not be published. Required fields are marked *