JavaScript Modules

Modules are highly self-contained and they are grouped with their specific functionality. It’s allowing them to be moved around and used by other places and even to be removed without disrupting the system as a whole.

you can think about modules as it was a toolbo of functions to use like service to my data base calls or service for HTTP calls.

The big advantage with modules is that we can write organized code with functions that can share data without polluting the global scope, with no variables names collisions and this is important since today our JavaScript apps are huge.

Module Pattern

In an ideal world, we should have a module scope up above the function scope. a scope that we can combine multiple functions together and which won’t pollute the global namespace. this module scope can be used to share the variables between the functions without going to the global scope. it means that with this module scope, we can be explicit about which of the variables or functions in the module should be available,

with the module pattern, we can create such a thing. it is a combination of closure and encapsulation. Let’s see an example:


var messageModule = (function() {
  var helloGretting = 'hello';  // private variable  (no access)
  var helpMessage = 'SOS';  // private variable  (no access)
  
  function sendGreet(name) {
    console.log(`${helloGretting } ${name}`);
  }

  function sendHelp() {
    console.log(`${helpMessage } ${helpMessage } ${helpMessage }`);
  }

  return {
    greet: sendGreet,
    help: sendHelp,
  }
})()

messageModule.greet('Dan);  // Hello Dan.
messageModule.help();  // SOS SOS SOS.

when the compiler sees the IIFE it will immediately invoke the function and an object will be created. the variable are private and only the function inside the IIFE have access to them. finally we add the functions that we want to expose on the object that we return.

Side note: we could import data from the global scope by passing it to the IIFE.

Side note: The big difference between module and constructor is that when you using a module pattern you will get only one from object.

The pros:

  • Decoupling
  • maintainability
  • Reusability

The cons:

  • Polutting the global namespace with one variable
  • no way to know the dependencies ( we need to make sure that the order of the script tags is correct)

CommonJS and AMD

CommonJS and AMD solved the problem of designing a module in a way that we won’t interfere with the global scope.

let’s see an example of CommonJS


  var module1 = require('module1');
  var module1 = require('module2');

  function doSomething() {}

  module.exports = {
    doSomething: doSomething
  }

Side note: CommoJS was created mainly for the server and Node.js still using it and this is probably the reason why Node.js became so popular.

With CommonJS, modules are meant to be loaded synchronously but it’s not ideal for browsers, synchronously in the browser will slow down the app. so browserify came out, browserify bundle all the scripts in the project to one file (webpack can also do this).

AMD is designed specifically for the browsers, which means it loads scripts or modules asynchronously, let’s see an example:


define(['module1', 'module2'],
  function (module1Import, module2Import) {
    var module1 = module1Import
    var module2 = module2Import

    function dosomething() {

    }

    return {
      do: dosomething,
    }
  });

ES6 Modules

JavaScript needed a way to support modules, when ES6 came out we introduced the native modules.

Now we can use the keywords “import” to import JavaScript files and “export” to export anything we want. Let’s see an eample:


// JavaScript File: message.js
const helloGretting = 'hello';
const helpMessage = 'SOS';

export function sendGreet(name) {
  console.log(`${helloGretting } ${name}`);
}

export function sendHelp() {
  console.log(`${helpMessage } ${helpMessage } ${helpMessage }`);
}


// In another file we will use the module.


With WS6 modules we ar not poluting the global namespace.