Tag Archives: RequireJS

Adding require.js to HTML5 boilerplate build

HTML5 boilerplate has a really nice build script. It get’s your website in tip top and minified shape in no time. However what happens when you want to use require.js on a big project and don’t need the scripts.js file that is provided? In a few steps we can get your website in tip top shape with require.js as well!

Getting started

For the sake of simplicity we will assume you already have h5bp in your project. Now that is settled we can get started.

First off we are going to need a way to differentiate our require.js stuff from the rest of our site. H5bp already has a good mechanism for doing this with external libraries via the libs & mylibs folders. From what I can gather libs & mylibs are where you stick generic libraries that the project may need. (jQuery, Backbone, etc)

For our require.js code we are going to create a separate folder called “app”. This way we can isolate those files from the h5bp build script. By default h5bp will copy & minify everything from the js folder when executed. This not what we want since we need to trace the require.js files for dependancies first. Your default js folder structure should be like below.

Cleaning up after scripts.js

Since we are no longer using the default scripts.js file we will need to modify the build script accordingly. Again, by default h5bp will try to run the -js.scripts.concat target when building. This will fail the checksum since we don’t have a scripts.js file. To remedy this problem remove any references to the ‘-js.scripts.concat’ target in the build targets. Doesn’t make sense? See below.

And… So close. One last modification is needed. When building, the ‘-usemin’ target is ran before any other minification/concat targets. Currently, it has a dependency on the ‘-js.scripts.contact’ target. We will need to get rid of this. However, this would be a good spot to trace our require module dependancies since it will run before any copying, minifying, etc. Go ahead and change the depends attribute to “-r.js,-css”. In the next section we will create the -r.js target.

Creating the -r.js target

<!-- Require.js target, run separately -->
<target name="-r.js" description="Concatenates JS files using require.js dependencies">
    <java classname="org.mozilla.javascript.tools.shell.Main">
        <classpath>
            <pathelement location="./${dir.build.tools}/${tool.rhino}" />
        </classpath>
        <arg value="tools/${tool.require}" />
        <arg value="-o" />
        <arg value="${require.build}" />
    </java>
    <echo message="optimized ${require.build}">
</target>
view raw r.js.xml This Gist is brought to you using Simple Gist Embed.

Let’s break this down a bit. First, it invokes Java. Next, it adds rhino to the java classpath. Finally, it sets three arguments.

If you notice there are three variables within the target. tool.rhino, tool.require, and require.build. The convention when defining variables within h5bp is to define them in the project.properties file. These variables override the default.properties file with your project specific variables. This is a good thing since if you update html5 boilerplate it won’t break your already defined variables with a later build. But what are these variables? The are simply string variables defined in our project.properties file.

${tool.rhino}

tool.rhino is defined in many places within the h5bp build.xml file. It is the string variable representing the rhino jar file.

${tool.require}

tool.require is a custom variable which represents the path to the r.js file that comes with the require.js optimizer. r.js will trace your javascript files written in require.js AMD format for dependencies, then concatenate them together and finally minify them with uglify. You will need to download this file and drop it in the tools directory within the build folder.

${require.build}

require.build is another custom variable that links to our require.js build file. As described above r.js will preform a build on your javascript files. However, it needs to know how and where to build from. This is where a custom build file comes in. Require.js can build your site based on this custom build file which is represented in json format. In the example below we have set the require.build variable to point to a file name app.build.js. This file contains the instructions on how to build our require.js modules.

app.build.js

To get the full rundown of what can be done in a require build file visit http://requirejs.org/docs/optimization.html

A simple example of a build file is below. In this example we define our base url in the app folder, then we define the name of our module we want to traverse and finally, the location where we want to publish out the generated file(s).

Note: we are publishing out to the intermediate folder created by the h5bp build script.

Putting it all together

Now that we have defined the variables above the -r.js target should make a bit more sense. Again, all it is doing is reading our require build file and tracing the module dependancies. It does this using the rhino shell to execute the r.js optimizer script that comes with require.js.

${dir.js.app}

Almost done. I promise! We will need to exclude our app folder from any processes that might get run by h5bp internally. We can do this in three steps.

  • Create a custom variable to our app path in project.properties.
  • Add ${dir.js.app} to the list of files/folders to ignore in project.properties.
  • Add an exclude statement to the -js.all.minify target. This will prevent h5bp from minifiying and copying the app folder. See below.

Conclusion

Ok, maybe that was more complicated that I thought! Anywhooo, if you had trouble following along I have attached the modified build folder below. Hopefully this helps development teams that are looking to incorporate require.js into their current build processes. Please feel free to post suggestions or enhancements.

build.zip

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!