Dwarves
Memo
Type ESC to close search bar

JavaScript modules

Modules have always been a part of JavaScript development and providing mechanisms for splitting JavaScript programs up into separate modules that can be imported when needed was the absolutely necessity for JavaScript developers.

“Modules are like building blocks that we can create software by combining.”

So what is a module?

A module is just simply a file that exports its own code.

Why do we need it?

History of JavaScript’s modules

In order to understand about the development of JavaScipt’s modules, we need to walk through 4 stages: Vanilla, IIFEs, CommonJS and ESM.

Vanilla (1990s - early 2000s)

When JavaScript was first invented by Brendan Eich in 1995, it was known to have been created in 10 days and the creator himself doesn’t think that his programing language would be as popular as today.

“No one thought JavaScript would be used at the wide scale it is. Not just reaching lots of people on the Web, but large application like Gmail… To write large code, you don’t just want this little snippet language that I made for beginners…“ Bredan Eich (Creator of JavaScript)

So modules aren’t a thing back then, developers would mostly used inline-scripting and script-tags and no one would think of scalability, maintaining a large code base would be a nightmare because there is no structures and organizations.

YAHOO manifesto

Around 2006, a global manifesto was raised by a team of UI developers from YAHOO which was “Global Variable are dangerous”. The point they trying to make is that using global variable is a risky practice and all the people back then are engaging in. Global variables can spark conflict between naming if there are many people involving in developing the same program and since everyone can access it, it is not very secure.

YAHOO Solution?

Create a huge Global namespace object and parse all the variables in that object.

Example: YAHOO.value.getValue

IIFEs (early to late 2000s)

IFFEs or Immediately invoked function expression was used with closures to keep the private data hidden, basically the ideal is that you only need to care of what the function returns and not what happen inside it.

Example

var Dialogue = function () {
  //private variables
  var dialogue
  //exposed functions
  return {
    hello: function () {
      dialog = 'Hello Dwarves!'
      console.log(dialogue)
    },
    goodbye: function () {
      dialog = 'Goodbye Dwarves!'
      console.log(dialogue)
    },
  }
}

At this stage we have solve the Global namespace pollution problem but we haven’t got to the point that we can swapping modules with one another and copy/paste function happens all the time.

CommonJS (early to mid 2010)

Around 2009, people are hype about the potential of JavaScript, you can now run JavaScript on the server-side. And come with that a proposal was made for JavaScript to have a standard way to include other modules. Node created a module implementations name CommonJS.

Implementation of CommonJS:

This was design for server development.

Synchronus modules loading

Node module wrapper function

;(function (exports, require, module, __filename, __dirname) {
  // Module code actually lives in here
})

Example

//dialogue.js
var getDialog (function (){
    console.log("Hello Dwarves!");
})
module.exports = getDialogue;
//main.js
const sayHello = require('./dialogue.js')

At this time, CommonJs is a real noviation, organizing files and maintaining code has become much easier.

ESM (2010s - present)

ESM or ES modules was supported by all major browsers and was the first built-in module in JavaScript and introduce top-level await functionality for module imports.

Top-level await

A feature accessible within modules is top level await. This implies that the await keyword is functional. It enables modules to function as sizable asynchronous functions, allowing code to be assessed before usage in parent modules without preventing the loading of siblings.

ESM Asynchronus ?

The loading and parsing for ESM modules is indeed asynchronous, but the execution of the code in them is synchronous and serialized based on the order they are imported.

Implementation ESM:

Example

//Export syntax

//dialog.js
export default const dialog = "Hello Dwarves!";

//utils.js
export const getHours = () => //do something;
export const getMinutes = () => //do something;
//Import syntax

import dialog from './dialog.js'

import * as utility from './utils.js'
import { getHours, getMinutes } from './utils.js'

ESM in the browsers

ESM has a specfic module type in the browser which they are processed differently and create a fallback for older browsers using bundle.

<!-- Adding module script -->
<script type="module" src="main.js"></script>
<!-- Fallback for older browsers -->
<script nomodule src="bundle.js"></script>

CommonJS vs ESM

Conclusion

Although CommonJS can still be used for server development since synchronous wasn’t an issue and it was built by Node, using ESM is still the better way to keep the syntax consistent if you were to develop client-side and server-side with JavaScript.

Reference