We can also think of these as module specifications. The question here is, what are the systems that Javascript uses to import and export code from various files and packages, and how are they different?

Reading

Navigating the module maze: history of JavaScript module systems

  • Mentions ESM and CJS
  • Asks “what is a module?”
  • Talks about Revealing Module Pattern (which I had never heard of) Revealing Module Pattern

CommonJS

var someModule = require('someModule')
 
exports = {}

AMD

RequireJS

  • Probably most popular implementation of AMD
  • Implements the AMD API (but wants to keep the spirit of CommonJS)
  • Async
  • Offers CommonJS wrappers so that CommonJS modules can be directly imported for use with RequireJS

Browserify

Allows you to ‘require’ modules in the browser by bundling up all of your dependencies.

  • Open source
  • Javascript bundler
  • Allows devs to write Node.js-style modular code and use it in the browser
  • Kind of old…? Is it still relevant?
  • Supports “transforms” which are kinda cool
  • Webpack and Rollup competed with it back in the day

Native ES Modules (EMS)

  • Standardized into ECMAScript in 2015
  • import and export
  • Browser support
  • Also support in Node.js
  • Future proof (part of JS standard)
  • Is synchronous but has an optional import asynchronous option!

Revealing Module Pattern

They use IIFEs (immediately invoked function expressions):

(function(){})()

Note to me: if that’s hard to remember, just note that it’s a normal function wrapped wrapped in an invoked closure: ()(). There are at least two anatomical mnemonics that may help encode the immediacy part.

So his creates a local scope for all variables and methods. Only public methods will have access to the code inside an IIFE.

These are so cool. Here’s an example @Rahulx1 on medium.) gives:

var namesCollection = (function() {
    // private members
    var objects = [];
    
    // Public Method
    function addObject(object) {
        objects.push(object);
        printMessage(object);
    }
  
    // Private Method
    function printMessage(object) {
        console.log("Object successfully added:", object);
    }
    // public members, exposed with return statement
    return {
        addObject: addObject,
    };
})();

Only the methods we want are returned! Wild! By the way, it’s okay to put the return statement at the top of the file. This…made no sense to me, so I investigated.

I actually tried this, and it didn’t work. But it did work if I put the return statement below this line:

var objects = []

This seems to be due to something called function hoisting, in which the interpreter function declarations to the top of their scope before code execution. This means that you can call a function before it is declared in your code without encountering an error!

Okay definitely learning some new things here. Check this out Function Declarations vs. Function Expressions & Hoisting

Validity Qualification!

This article was written a while ago and a few of the examples here don’t actually work quite as expected, but this is probably because they are using intentionally weird syntax that probably shouldn’t work, and his been weeded out.

This actually taught me something much more important, which is the different between function declarations and function expressions

Function declaration:

function foo(){}

Function expression:

const bar = function(){}
// or
const bar = () => {}

This gives an error:

console.log(hoist())
const hoist = () => "moose"

Cannot access ‘hoist’ before initialization. I tested this in ts and js just to be sure.

This does not:

console.log(hoist())
function hoist(){
  return "hoist"
}

I was getting some mixed messages about which is called an expression and which is called a declaration so I called up my old friend MDN and she confirmed.

What I finally understand now is that arrow functions are a (relatively) more modern version of traditional function expressions. They’re nice because now function declarations and expressions look super different.

It turns out, declarations are loaded when the code is compiled, not when it’s executed, whereas expressions seem to be loaded and executed in the same step.