All notes
Commonjs

Intro

CommonJS, RequireJS, AMD

SO: relation between commonjs and requirejs.

CommonJS is a project to define a common API and ecosystem for JavaScript. One part of CommonJS is the Module specification. Node.js and RingoJS are server-side JavaScript runtimes, and yes, both of them implement modules based on the CommonJS Module spec.

AMD (Asynchronous Module Definition) is another specification for modules. RequireJS is probably the most popular implementation of AMD. One major difference from CommonJS is that AMD specifies that modules are loaded asynchronously - that means modules are loaded in parallel, as opposed to blocking the execution by waiting for a load to finish.

AMD is generally more used in client-side (in-browser) JavaScript development due to this, and CommonJS Modules are generally used server-side. However, you can use either module spec in either environment - for example, RequireJS offers directions for running in Node.js and browserify is a CommonJS Module implementation that can run in the browser.

CommonJS

CommonJS makes use of an "exports" object, and a require() function to fetch it:



// someModule.js
exports.doSomething = function() { return "foo"; };

//otherModule.js
var someModule = require('someModule');
exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };

AMD

AMD started as a spinoff of the CommonJS Transport format and evolved into its own module definition API. The new feature in AMD is the define() function that allows the module to declare its dependencies before being loaded.



// package/lib is a dependency we require
define(["package/lib"], function (lib) {
    // behavior for our module
    function foo() {
        lib.log( "hello world!" );
    }

    // export (expose) foo to other modules as foobar
    return {
        foobar: foo
    }
});

// Somewhere else the module can be used with:
require(["package/myModule"], function(myModule) {
    myModule.foobar();
});

Disconfusion

module.exports, exports in CommonJS

The keyword require returns an object, which references the value of module.exports for a given file. sitepoint.com.

exports is a plain JavaScript variable that happens to be set to module.exports. At the end of your file, node.js will basically 'return' module.exports to the require function. A simplified way to view a JS file in Node could be this:



var module = { exports: {} };
var exports = module.exports; // This line makes them two equivalent.

// your code

return module.exports;

module.exports is the real exported obj



//////////// greetings.js

// var exports = module.exports = {};

exports.sayHelloInEnglish = function() {
  return "HELLO";
};

exports.sayHelloInSpanish = function() {
  return "Hola";
};

/* this line of code re-assigns module.exports */
module.exports = "Bonjour";

//////////// main.js

var greetings = require("./greetings.js");

/* TypeError: object Bonjour has no method 'sayHelloInEnglish' */
greetings.sayHelloInEnglish();
        
/* TypeError: object Bonjour has no method 'sayHelloInSpanish' */
greetings.sayHelloInSpanish();

// "Bonjour"
console.log(greetings);

import, export in ES6

mozilla.org: export.

It's ES6 syntax. It is not implemented in any browsers natively. Only implemented in many transpilers such as Babel.

wcfNote: it is not "exports", which is used in node.js. See "module.exports vs exports" in the previous section.

Three types: named, default, all


////////// Three different types of export

// https://stackoverflow.com/questions/42478661/difference-between-export-and-export-default-in-javascript

// Three different export styles
export foo; // Named.
export default foo; // Default.
export = foo; // All.

// Roughly compiles to:
exports.foo = foo;
exports['default'] = foo;
module.exports = foo;

// The three matching import styles
import {foo} from 'blah';
import foo from 'blah';
import * as foo from 'blah';

// Compiles to:
var foo = require('blah').foo;
var foo = require('blah')['default'];
var foo = require('blah');

////////// Syntax

export { name1, name2, …, nameN };
export { variable1 as name1, variable2 as name2, …, nameN };
export let name1, name2, …, nameN; // also var
export let name1 = …, name2 = …, …, nameN; // also var, const

export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };

export * from …;
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;


////////// Named exports

// module "my-module.js"
function cube(x) {
  return x * x * x;
}
const foo = Math.PI + Math.SQRT2;
export { cube, foo };

// In another script (cf. import)
import { cube, foo } from 'my-module';
console.log(cube(3)); // 27
console.log(foo);    // 4.555806215962888

////////// Default export

// https://stackoverflow.com/questions/21117160/what-is-export-default-in-javascript
// If a module defines a default export (without a name):
export default function() { console.log("hello!") } // In foo.js

// then you can import that default export by omitting the curly braces:
import anyName from "./foo"; // Relative import.
anyName(); // hello!

Transpiled in Babel

SO: module.exports vs export default.



////////// input
export const foo = 42;
export default 21;

////////// output by Babel
"use strict";

// Here it is transpiled to node.js's "exports". Note the extra trailing 's'.
Object.defineProperty(exports, "__esModule", {
  value: true
});
var foo = exports.foo = 42;
exports.default = 21;