Modular Javascript Using Require.Js

Resource

Download demo project : RequireJsDemos.zip

Introduction

I don’t know how many of you use lots of JavaScript libraries, but we found ourselves using quite a lot within certain projects. One of the strange issues that came about from linking JavaScript files was that we occasionally ran into dependency issues, where by a particular JavaScript source file would have a dependency on another JavaScript source file that was not loaded (and therefore not available) yet.

As luck would have it there is an excellent library for dealing with interlinked JavaScript dependencies and module loading which is called : RequireJs

The Problem

You may be asking what problem RequireJs is attempting to solve. Well lets consider a most common example, which is that of a custom jQuery plugin, where jQuery MUST be loaded before the plugin will work. If we stuck to using standard script tags something like this

We instantly have a problem, our custom jQuery plugins will not work, as jQuery itself has not be loaded yet. Sure we could move the jQuery script tag to be before the  custom jQuery plugins, which would indeed fix the problem this once. This is however a very isolated small use case, which is not really the norm on large scale applications, where we may have many many related files which all have dependencies. This is where RequireJs can help. Want to know more, read on.

A Possible Solution

So now that you know the problem what is a possible solution? Well as I have already stated this article will use RequireJs a one viable solution to the problem just described. RequireJs does a bit more than just solve dependencies, it also provides asynchronous module and file loaded. In my mind the fact that RequireJs uses modules is a very good thing, as it gives a guiding push to the developer, which should nudge them into creating a module which has a single responsibility which is never a bad thing. Using RequireJs we are able to specify things like:

  • Define a module
  • Require a module 
  • The modules dependencies (via a RequireJs config called  shim)
  • The module paths 

The Demos

This section will outline several different RequireJs examples, starting with a typical simple use case, and then building on to slightly more complex examples.

Simple Demo

This is the simple basic 101 sample, and it illustrates the very basics of using RequireJs. This will be expanded upon later, but it does illustrate a few key points that we will come across in later examples.

Here is what the structure of this project looks like in Visual Studio:

Bootstrapping an app to use Require.js

One of the things you must do with RequireJs is to tell it which file will be used for the overall configuration. Here is a simple example

You can see that the data-main attribute points to a main file which is what sets up the RequireJs configuration. Lets see a simple example of this shall we:

What we can see there is the use of the require() function, which is what RequireJs gives us. The 1st parameter (which may be an array as shown) specifies the dependencies that this function has. Lets now focus our attention on one of those modules that we have a dependency on.

This following snippet is the logger module, and note above how we state that we require() the logger module, which RequireJs gives us, and then are free to use the modules code. Which again can be seen above where we use the logger modules logThePair( ) function

In this example we define a module using define() and we also take in RequireJs which gets special treatment, where RequireJs knows what to do with it. We are now able to use this defined module using another require() call somewhere else, which we saw above when we wrote out

One thing of note there is the path is also included “helper/logger” so require will look for a file that matches that path and use that. We can also specify paths like this

We will see more on path configuration later

Using require () vs. define()

We can use both require() and define() to load module dependencies. The require() function is used to run immediately, where as define() is used to define modules which may be used from multiple locations.

Using With jQuery

So now that we have seen a trivial example of using RequireJs lets continue our journey. Lets see what it takes to create an example where we have actually library depenencies, such as a jQuery plugin that needs jQuery in order for function.

Here is what the structure of this project looks like in Visual Studio:

As before we start (as we always will) by telling RequireJs the main javascript code file to boostrap the app

Where the scripts/app javascript file looks like this

This time we can see something new. We can see that we are actually configuring RequireJs
for certain things, such as:

  1. BaseUrl : Specifies the base path for all the scripts, you can still use RequireJs with relative paths, but this is its base path
  2. Paths : Is a map of named paths where we specify a well known name and a path
  3. Shim : Is a map of files, and their dependecies. What this does is that is gives a hint to RequireJs about the required module dependencies such that RequireJs will then know to load them in the correct order. Remember that RequireJs uses a technique which means modules are loaded asychronously. It can be seen from the example above that “jquery.appender” and “jquery.textReplacer”are dependent on jQuery. As such RequireJs will load that first.It may seem that we are just swapping the evils of having the correct javascript imports in the html in the correct order for this, but what we do get from RequireJs is that modules are loaded asychronously

The last point is that we then kick of the whole app by telling RequireJs wihch is the initial app file that should be run. This is done using the line

So lets examine that file for a minute

It can be seen that is uses jQuery and the 2 custom jQuery plugins, that have by magic had their dependency on jQuery satisfied by RequireJs, so we can now safely use them within the javascript that asked for them as requirements.

Just for completeness here is one of the custom jQuery plugins that the code above makes use of

RequireJs magically makes sure that this is not loaded until jQUery itself is loaded, at which poit it will be provided to these plugins

Leave a Reply

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

CAPTCHA