Codementor Events

Comparing CommonJS and AMD/RequireJS

Published Feb 01, 2017
Comparing CommonJS and AMD/RequireJS

Introduction

Unlike web servers such as Apache and Microsoft IIS, both of which are pre-configured, node.js is quite different. With node.js, developers build web servers from scratch. A developer’s coding skills is expected to safeguard the web server. Thus, Node.js differs from Apache and the rest.

In this article, we will focus on two main system modules - AMD and Common.js - in node.js. Before we compare the two, we must discuss the differences between the two system modules. Two guiding questions that help us compare the two are: which one is faster when loading modules in or from the browser and how to convert one system module to inherit some features of other system module.

This article will not focus on the basics of node.js amd javascript. It will not cover topics such as "how to install node.js," "how to use npm or nave to install packages," or "different versions of node.js for different projects." Our purpose is to resolve the confusion between AMD and Common.js. Therefore, we will emphasize lightly on the core modules in node.js, a couple of functions and variables, and eventually direct our attention to AMD and Common.js and how we can convert one of the system modules to load modules faster in the browser.

Core, File and External Node Modules

In node.js, there are three main important modules; Core, file, and external node modules. Let's kick start it with the file module first because it is easier to grasp.

  • File Module:
    Unlike the other two models, the file model is a relative-path based model. Why? Let’s say you were to export a module via the following syntax:
 module.exports  =  foo  {  
           ‘something’ :  123 
   }  ;     
  var foo =  function  ()    { 

console.log('foo called');  

};
var b = function () {  

console.log('b called');  

};  

module.exports = { 

b : b 

};

module.exports.bar = function () {

console.log('bar called');

};   

module.exports.bas = function () {

console.log('bas called');

};

The way modules are loaded or imported into files is quite different from the core and external_node modules; which is why the other two are also known as non-relative based modules.

Note: there are diverse ways of exporting modules/files in node.js. Anonymous function is another of way exporting a module from a file.

  • Core Modules:
    The next modules that include the three main modules in node.js are the core modules. Core Modules are non-relative based modules. They are very different from file modules, especially when you are requiring (or importing) modules into files.

For instance, if we were to consume the path module in node.js, which fixes up slashes to be OS specific, takes care of . and .. in the path, and also removes duplicate slashes, we would not include the relative path:

var require  = require(‘path’)
      console.log (path.normalize (‘/foo/bar/......’));
  • external_node modules:
    These modules fall somewhere in between core and file-based modules. external_node modules are quite similar to file-based, especially when you are exporting a module.
module.exports = function () {
console.log('called node modules!');
} 

However, when you are loading modules, they become quite different.

var bar = require('bas');
bas(); // 

Additionally, node.js provide some important global with useful features, which we won’t discuss in details. timer,console, _filename and_dirname, and process are all examples of important globals in node.js. For instance, _filename and _dirname are available in every file and give access to the full path and directory for the current module.

Now that we have a brief understanding of modules in node.js, let’s move on to the main aspect, where we differentiate CommonJS and AMD modules. We will tackle the problems of "why Common.js is so slow in loading modules from the browser" and "how we can convert it via browserify to inherit certain features of AMD and Require.js." .

Introducing CommonJS and AMD

 CommonJS is a great module for the server side environment, especially when you have immediate access to the filesystem. However, using the same module system in the browser may be less reliable and extremely slow. 

For instance, let's consider how the two modules are loaded in the server side environment:

var foo = require('./foo');
var bar = require('./bar');
// more code here  

Looking at the example above, it is considered a good practice on the server side when one module is loaded while the other module waits for another module to be parsed.

In other words, when the foo module is being loaded, the bar will not be parsed or processed until the foo is loaded off completely. Even the server might not be aware of the bar module until it is done with the foo module.

Using the same module system in the browser is not considered a good idea because each module system would need to trigger an HTTP request to the server. This is a lot less efficient and less reliable in the server environment. It degrades user experience on the client side. This problem could be resolved via asynchronous loading of modules.

This is where AMD comes in. AMD, also known as async module definition, was introduced to support asynchronous loading of modules in the browser —
it eventually resolves slow rate of loading modules in the browser. In line with the meaning of "asynchronous," modules are triggered at different times.

In order to export something in a file in AMD, we simply need to include a callback function and return it from a define callback function. Here's an example:

 define([], function () {
   var foo = function () {
   console.log ('foo was called');
};
  return foo; // function foo is exported
});

Just like the export variable syntax in node.JS, the define function also takes a special argument called exports, which is quite similar to the one in node.JS.

define(['exports'], function (exports) {

var bas = exports.log = function () {

console.log ('bas.log was called'); 
};
});

In order to make it possible to load two modules in the browser, we need to download and install RequireJS. Keep in mind, this is just an option that prevents developers from using node.JS code in the browser.]

Why do we need RequireJS to able to load modules via the asynchronous module definition?
Here is the reason: because the Define function, which is part of the code below (showing us how we can load more than one module in the browser via the AMD), is not native to the browser. Therefore, the best option is to access it from a third-party library. RequireJS is simply a javascript file you include in your project.

define(['./bas', './bar'], function(foo, bar){ 

//more code here
// more code here 

});  

How to Convert node.js into Browser Code:

Now, let’s see how we can convert CommonJS to become compatible with AMD/RequireJS via browserify. Converting CommonJS via browserify allows node.js to load modules in the browser similar to AMD/RequireJS.

Let’s install browserify via the following code. Please make sure you are connected to the internet whilse installation. The hyphenated g simply means global.

npm install –g browserify

You can create modules, name it as clientJS or any name you prefer, and eventually convert it to AMD/RequireJS using browserify.

module.exports = function () {

console.log('bas was called');
}
exports.log = function () {

console.log('bar.log was called');
}

Now, to convert the above code to be AMD compatible, in other words, to load modules asynchronously, we need to do so via the following command line arguments:

browserify client.js -o amdmodule.js

You can assign any name you prefer to be the client. It should not always be client.js but client.js, too, is preferable. Remember, it is just a file. Moreover, you can check out more configuration about browserify at http://browserify.org/.

Wrapping up:

Finally, you should note that not all node.JS modules can be converted to work effectively in the browser. Those that depend on features that are available on the server-side won’t work at all in the browser.

I have just introduced AMD/RequireJS as a solution that allows asynchronous loading of modules in the browser, which is considered a good practice. Loading modules asynchronously is a lot faster and more reliable than using CommonJS in the browser.

Discover and read more posts from Michael Aboagye
get started