In nutshell JavaScript modules are just a way of packaging related JavaScript code in its own scope which can be consumed by other JavaScript programs.
In this tutorial I will show the different ways to create JavaScript modules.
Immediately-Invoked Function Expression
IIFE is a anonymous function which invokes itself. Creating modules using IIFE is the oldest way of creating JavaScript modules. Here is example code on how to create modules using IIFE
You can place the below code in an separate file to make it an distributable module or place it directly in your main program for your own use.
(function(window){
var sum = function(x, y){
return x + y;
}
var sub = function(x, y){
return x - y;
}
var math = {
findSum: function(a, b){
return sum(a,b);
},
findSub: function(a, b){
return sub(a, b);
}
}
window.math = math;
})(window);
//Module Ends
console.log(math.findSum(1, 2)); //3
console.log(math.findSub(1, 2)); //-1
Here sum
and sub
function objects remain in memory but there is no way the program which uses the module can access them therefore we prevented any chances of overriding global variables. The only thing thats available global is math
object which exposes all the functionality of the module by hiding their implementation.
jQuery library is a IIFE module. The only object that it exposes is $
or jQuery
.
CommonJS
CommonJS is a non-browser JavaScript specification for creating modules. CommonJS is not available for browser JavaScript. Its mostly used in NodeJS.
Suppose we have two files “main.js” and “math.js”. Let me show you how to make “math.js” behave like an module and then use the module in “main.js” file.
Here is the code in “math.js” file
return x + y;
}
var sub = function(x, y){
return x - y;
}
var math = {
findSum: function(a, b){
return sum(a,b);
},
findSub: function(a, b){
return sub(a, b);
}
}
//All the variable we want to expose outside needs to be property of "exports" object.
exports.math = math;
Here is the code in “main.js” file
var math = require("./math").math;
console.log(math.findSum(1, 2)); //3
console.log(math.findSub(1, 2)); //-1
Here we successfully prevented any chances of overriding global variables and also hide the implementation.
There are some hacky implementations for making CommonJS specification work on browser but there are lots of performance issues with it. One such implementation is Browserify.
Asynchronous Module Definition
AMD is a JavaScript browser specification for creating modules. AMD is designed keeping browser limitations in mind. Browsers don’t natively support AMD so you need a AMD implementation library for creating and importing AMD modules. One such AMD library is RequireJS.
Let’s see example code on how to use RequireJS for creating and importing a module. Let’s take an scenario that we have an “index.js” file which has all of our website’s JS code and we want to create a module named “math” which will expose mathematical APIs. Here’s how to create “math” module and import it in “index.js” file
Here is code for “index.html” which is our webpage
<html>
<head></head>
<body>
<!-- Load RequireJS library and then provide relative path to our website's JS file. File extension not required. -->
<script type="text/javascript" src="http://requirejs.org/docs/release/2.1.16/minified/require.js" data-main="index"></script>
</body>
</html>
Provide relative url of the “index.js” file in the data-main
attribute.
Here is the code in “index.js” file
require(["math"], function(math){
//main program
console.log(math.findSum(1, 2)); //3
console.log(math.findSub(1, 2)); //-1
})
Here we are asking RequireJS to load math module before the main program.
Here is the code in “math.js” file
var sum = function(x, y){
return x + y;
}
var sub = function(x, y){
return x - y;
}
var math = {
findSum: function(a, b){
return sum(a,b);
},
findSub: function(a, b){
return sub(a, b);
}
}
return math;
});
This is how you need to create a module. Now any website using RequireJS can import “math.js” module file.
Here we successfully prevented any chances of overriding global variables in main program and also hidden the module functionality implementation.
Universal Module Definition
UMD is a set of techniques to create modules that can be imported using CommonJS, AMD or as IIFE.
UMD modules are called Universal Modules. There are many techniques under UMD. Its upto you to choose whichever you want to use for creating modules.
My favourite UMD technique is returnExports.
Here is example code on how to create math module using returnExport pattern. Place this code in “math.js” file
(function (root, factory) {
//Environment Detection
if (typeof define === 'function' && define.amd) {
//AMD
define([], factory);
} else if (typeof exports === 'object') {
//CommonJS
module.exports = factory();
} else {
// Script tag import i.e., IIFE
root.returnExports = factory();
}
}(this, function () {
//Module Defination
var sum = function(x, y){
return x + y;
}
var sub = function(x, y){
return x - y;
}
var math = {
findSum: function(a, b){
return sum(a,b);
},
findSub: function(a, b){
return sub(a, b);
}
}
return math;
}));
Import module “math.js” any way you wish to i.e., CommonJS, RequireJS or as IIFE and it will be successfully imported.
UMD doesn’t provide techniques for importing modules its just for creating modules.
ECMAScript 6 Modules
Due to the huge usage of JavaScript modules it was time for browsers and server side runtime engines to natively support some form of common module system. Therefore ES6 modules were introduced. ES6 modules are supported everywhere.
In ES6 every module is represented by a file. Here is how to make “math.js” file as a math module
constructor()
{
this.sum = function(x, y){
return x + y;
}
this.sub = function(x, y){
return x - y;
}
}
findSum(a, b)
{
return this.sum(a, b);
}
findSub(a, b)
{
return this.sub(a, b);
}
}
Here is how to import math module in our main program
var math = new Math();
console.log(math.findSum(1, 2)); //3
console.log(math.findSub(1, 2)); //-1
There are lots of more advanced functionality supported by ES6 modules.