Intro to modular JavaScript development

When developing any kind of project, wether it is an application, or just simply brochureware, you are going to have a good bit of code to maintain. As the size of your project grows so will the amount of code that it contains. This creates its' own issues: How do we organize this code? How do we promote highly cohesive yet loosely coupled code?

Cohesion: The degree of focus that your code has on the task it is to perform. It should be highly specific to the task at hand. This is called highly cohesive.

The answer to these questions is this: Simplify your code into small chunks that have a clear purpose. These chunks of code are called modules. Modules go by other names, in PHP and other classical languages one may refer to them as a service, a class, a helper, or they can even be traits. All of these are just different names for chunks of re-useable code.

In the following we are going to discuss how to program your JavaScript using a modular fashion. What are best practices, how to organize things, ect.

Coupling: How strongly the different parts of your program depend on each other. The less the dependency the better. Minimal dependence is called loose coupling while the inverse is called tight coupling.

Enough theory though, let's look at what problems modules solve.

Why do we need modules?

We already have a way to load JavaScript right? We just load them in a bunch of script tags and we can control the order of things, we can put it wherever we want it. Boom done. Yeah we can do that, but it's not really scaleable. The thing is, today's projects are expected to behave more and more like desktop applications. They are expected to do more and more. With the need for more ajax, more scripts comes the need for greater flexibility in organization and delivery.

Script tags block page load

With all of these scripts in your page the load time is going to start to slow to a crawl. Sure you can put as much as possible in the footer before the body tag close, but some things have to come at the top of the page. Some things have dependencies that rely on other JavaScript. That jQuery plugin that needs jQuery. That gallery you wrote that needs fancybox.

As your page loads the HTML, when it hits a script tag, it stops rendering the page until it has finished loading the script tag. This isn't a big deal for a few small JS files but when you get into a data-centric app that has tons of JS files then you start to have issues. Even smaller projects that start to make use of several libraries can benefit from a little JS organization.

Dependency Ordering

When you load a few custom scripts, then you throw in four or five libraries ( which have their own dependencies ) things can get out of hand. Few cool projects just have one or two script files btw, even if there is concatenation. The cool thing about node modules, is each module is like a world unto itself. It has it's own dependency tree and it's own project layout. This takes the majority of the work out of doing it yourself.

What types of modules are there?

So there are two main types of modules: AMD and CommonJS modules.
Modules by definition are very similar but there are some differences.

Some of the main differences are:
1. How they are constructed.
2. How they are loaded.
3. How they define their dependencies.

ES6, the next version of JavaScript has built in support for modules but at the time of this writing it is not released and implemented by the major browsers yet. I have used both module systems but these days i'm using CommonJS modules. The reason for this is it is the style that node uses and as such, we can leverage the vast multitude of node modules that are already written. This is one of the major reasons why I like CommonJS style.

How do we use these in our web projects?

So you know now what a module is, the main types. How do you use them though? The most obvious way to include any kind of JavaScript is like this:

<script type="text/javascript" src="js/myScript.js"></script>  

As we explained above though, this presents problems when your project starts to grow. So, to use modules what we usually do is have a main file that declares our initial dependencies. It will hold all of our modules, or just the main module we use. However it you decide to structure it. You can think of it as the file that bootstraps your application.

So without further ado, let's take a quick look at AMD modules and then we'll dive into the CommonJS style.

AMD: Define this please

AMD, aka Asynchronous Module Definition, is a method of loading modules asynchronously. It allow's you to define your dependencies so if you need script A to load before script B then you're set.

AMD is all about using the define method. Define's signature looks like this:

define(<moduleId>, deps, definitionFunction);  

The above format is the same one used by requirejs. Additionally, the definitionFunction is also called a factory function by most people as it is supposed to build and return your module. Furthermore, most people don't use the module ID param at all.

When you load deps, the factory function recieves them as params in the order in which they are declared in the dependency array. If you just want to load the resource but not reference it you do not need to pass it to the factory function.

Using modular JS, each module has a list of dependencies it depends on. It pulls in its' own dependencies. It basically acts as a self contained unit. These modules are referenced by one main module which acts as a main method of a C program. It starts the whole application.
Often this file is called main.js / app.js or something similar.

Using Plugins with AMD

In addition, AMD allows you to use plugins to pull in additonal resources. Here is a list of examples resources you can load via AMD plugins:

  • HTML templates
  • CSS
  • Images
  • coffee script
  • and more..

CommonJS Modules

CommonJS modules aka Node modules, make use of some of the same keywords that AMD uses but they work a bit differently and have some different results. These keywords are available for us in the global namespace. The most common CJSM keywords are:

  • require
  • module
  • exports

Going back to our previous discussion, our main bootstrap file will be called App.js. Let's take a look at how to lay that out with CommonJS syntax.

Let's pretend we are making a Zoo application. This is how our App.js might look:

#js/App.js
var zoo     = require('modules/zoo');  
var lion    = require('modules/lion');  
var tiger   = require('modules/tiger');  
var bear    = require('modules/bear');

var animals = [lion, tiger, bear];  
zoo.init(animals);  

Notice the difference here. In CJS there is no return for the module that is being created. Instead, you attach things to the global exports method and it then sends back your desired stuff to the parent module. Another thing to note is the CJS's version of require is synchronous.

So now that you've seen the main file, let's take a look at what one of those animal modules might look like:

var lion   = {};  
lion.speak = function(){  
   console.log('roaaarrr');
};

module.exports = lion;  

That's pretty much it. When you use module.exports you just want to return an object. You can work with and attach stuff to that object just like your normally would before you export it.

So, now we have a main file with all our modules in it. To use it we just include it in the browser right? WRONG!!! To use it, we have to run it through a tool so that the browser can understand the imports. Bascially, what happens it, the imports all get bundled into what we call a build file. This is a concatenated and often minified version of the the result of including all of your modules and scripts. Then we just include that one file in our html page. So let me show you that as a final step.

If you build it, they will come: Broswerify

I use gulp and a browserify setup to automate my build process. It runs my sass, any JS checking I want to do, any tests if I want to do that, and it browserify's my app.js file. This is an intro article though so maybe we'll go over my gulp setup in a new post. For now, ill show you how to use the manual browserify for this step of your build process.

1. Install the tools
npm install browserify --save-dev  
2. Run browserify
//Format: browserify <main_file.js> -o <destination_file.js>
browserify app.js -o ./dist/app.js  

The format of the browserify command is just specify your entry / main file, use the -o flag to signify the output, and then specify where you want to put the built bundle file. Now in your HTML you can include the buildfile:

<script type="text/javascript" src="js/dist/app.js"></script>  

That's it. That's the main points of using modular JavaScript development.
Often you see some people use file prefixes to signify the build file. Those will look like app.dist.js or app.min.js but I prefer the directory way.

Pro Tip: You can also install watchify to automatically browserify for you whenever you save your js files. If you aren't using a build tool like Gulp or Grunt then this is a good thing to do.

Conclusion

So, I hope this has shown you how to code in a modular fashion with JavaScript. Coding in this fashion will help promote loosely coupled, more highly cohesive code and make it easier to DRY your code out. So as always, if you have any questions leave them in the comments and we'll chat.