DEV Community

loading...
Cover image for JavaScript Modules: A walkthrough.

JavaScript Modules: A walkthrough.

Debojyoti Chatterjee
・4 min read

In JavaScript, modules are pieces of encapsulated code that can reused in different parts of your application or program whenever you need it.

Basically you can write your JavaScript code without modules but breaking down your code into multiple reusable modules helps you to keep your code clean, readable, reusable and mode manageable when you have dependencies.

The syntax for modules was officially introduced in ES6. Let's have a look at the various ways we can achieve this:

1. Asynchronous Module Definition (AMD):

This method is used for the browser environments. Large web applications require many external modules. Now, the traditional way of loading them is using the <script> element. When using <script> the browser loads them in a synchronous(sequential) fashion. Now it would be much better if we can load those external modules in parallel provided that there are no dependencies among each other.
So, lets have a look at the Asynchronous Module Definition(AMD) syntax:

define('yourModuleName',
    ['foo', 'bar'], /* dependencies(optional) */
    // module definition function
    // dependencies (foo and bar) are mapped to function parameters
    function (foo, bar) {
        // return a value that defines the module export
        // (i.e the functionality we want to expose for consumption)

        // create your module here
        var yourModuleName = {
            someAction: function () {
                console.log('This is a log statement!');
            }
        }

        return yourModuleName;
    });
Enter fullscreen mode Exit fullscreen mode

2. CommonJS Format:

This format is used in NodeJS. It uses module.export and require keywords to define and consume the modules.
Let's have a look at the syntax:

/* file: yourModule.js */
exports.findLength = str => str.length;

/* otherFile.js */
const stringFunc = require("yourModule.js");
const val = stringFunc.findLength("I love pancakes!");
console.log(val) // 16
Enter fullscreen mode Exit fullscreen mode

You can export more than one function or value and require them using destructuring.

/* file: yourModule.js */
exports.findLength = str => str.length;
exports.changeToCaps = str => str.toUpperCase();
exports.changeToLowCaps = str => str.toLowerCase();

/* otherFile.js */
const {findLength, changeToCaps, changeToLowCaps} = require("yourModule.js");
const val = findLength("I love pancakes!");
const upper = changeToCaps("I love burgers!");
const lower = changeToLowCaps("Stop talking about food!")
Enter fullscreen mode Exit fullscreen mode

3. Universal Module Definition (UMD):

Well, this pattern for JavaScript modules are efficient to work everywhere, be it a client on server or elsewhere. The main attempt of this format is compatibility.
The pattern is a bit verbose, but is both AMD and CommonJS compatible, as well as supporting the “global” variable definition style.

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        /* AMD. 
        Register as an anonymous module. */
        define(['b'], factory);
    } else if (typeof module === 'object' && module.exports) {
        /* Node. 
        Does not work with strict CommonJS, but
        only CommonJS-like environments that support module.exports,
        like Node. */
        module.exports = factory(require('b'));
    } else {
        // Browser globals (root is window)
        root.returnExports = factory(root.b);
    }
}(this, function (b) {
    const findLength = str => str.length;
    const changeToCaps = str => str.toUpperCase();
    const changeToLowCaps = str => str.toLowerCase();

    return ({
        findLength,
        changeToCaps,
        changeToLowCaps
    });
}));
Enter fullscreen mode Exit fullscreen mode

4. System.register:

System.register can be considered as a new module format designed to support the exact semantics of ES6 modules within ES5.
Let's take an example here, the following module is defined in ES6 syntax:

import dependencyModule1 from "./dependencyModule1.js";
dependencyModule1.api1();

// Named export:
export const findLength = function (str) { return str.length };
export const changeToCaps = function (str) { return str.toUpperCase() };
export const changeToLowCaps = function (str) { return str.toLowerCase() };

// Or default export:
export default {
    findLength,
    changeToCaps,
    changeToLowCaps
}
Enter fullscreen mode Exit fullscreen mode

The above in System.register format:

System.register(["./dependencyModule1.js"], function (_export, _context) {
    "use strict";
    var dependencyModule1, findLength, changeToCaps, changeToLowCaps;
    var __moduleName = _context && _context.id;
    return {
        setters: [
            function (dependencyModule1) {
                dependencyModule1 = dependencyModule1;
            }
        ],
        execute: function () {
            dependencyModule1.default.api1();
            // Named export:
            _export("findLength", findLength = function (str) { return str.length };
            _export("changeToCaps", changeToCaps = function (str) {
                return str.toUpperCase();
            };);
_export("changeToLowCaps", changeToLowCaps = function (str) {
    return str.toLowerCase();
};);
// Or default export:
_export("default", {
    findLength,
    changeToCaps,
    changeToLowCaps
});
        }
    };
});
Enter fullscreen mode Exit fullscreen mode

5. ES6 module:

The goal for ES6 modules was to create a format that both users of CommonJS and of AMD are content. The basic syntax is import and export keyword.
You can use the export keyword for exporting the public API of a module.

export const findLength = function (str) { return str.length };
export const changeToCaps = function (str) { return str.toUpperCase() };
export const changeToLowCaps = function (str) { return str.toLowerCase() };
export default theDefaultFunc = function () {console.log("This is a default export!!")}
Enter fullscreen mode Exit fullscreen mode

And use the import keyword for importing it for use.

// So, this is how you make default import and named imports
import theDefaultFunc, {findLength, changeToCaps, changeToLowCaps} from "./yourModuleFile.js"

//  You can use alias while importing
import theDefaultFunc as defFunc from "./yourModuleFile.js"

// You can also import a complete module like below
import * from "./someModule.js"
Enter fullscreen mode Exit fullscreen mode

For browser, <script>’s nomodule attribute can be used as a fallback option.

<script nomodule>
    alert("Module not supported.");
</script>
Enter fullscreen mode Exit fullscreen mode

JavaScript has standard built-in language features for modules. This is supported in NodeJS but not by all the browser versions yet. But, we can already use the ES6 module format. We need a transpiler like Babel, Webpack etc. to transpile our code to an ES5 module format such as AMD or CommonJS before we can actually run our code in the browser.

Discussion (0)