When we say an application is modular, we generally mean it's composed of a set of highly decoupled, distinct pieces of functionality stored in modules.
However, unlike other traditional programming languages, for a long time, JavaScript didn't provide developers with the means to import such modules of code in a clean, organized manner.
But, this didn't stop the community and they created impressive work-arounds. Following are the most used module loading patterns used by the developers:
Scripts
are code fragments that browsers run in global scope. They are precursors of modules.CommonJS
modules are a module format that is mainly used on servers (e.g., via Node.js).AMD
is a module format that is mainly used in browsers.ECMAScript modules
are JavaScript’s built-in module format. It supersedes all previous formats.
CommonJS modules
CommonJS is a project that aims to define a series of specifications to help in the development of server-side JavaScript applications. The CommonJS module proposal specifies a simple API for declaring modules server-side and unlike AMD attempts to cover a broader set of concerns such as IO, filesystem, promises and more.
There are essentially two elements to interact with the module system: require
and exports
require
is a function that can be used to import symbols from another module to the current scopeexports
is a special object: anything put in it will get exported
var lib = require('package/lib');
// some behaviour for our module
function foo(){
lib.log('hello world!');
}
// export (expose) foo to other modules
exports.foo = foo;
Implementations
Since it was made primarily for the server, it is well implemented in NodeJs (Node.js modules have a few features that go beyond CommonJS). For the client there are currently two popular options: webpack and browserify which help bundle these modules.
Asynchronous Module Definition (AMD)
AMD was born as CommonJS wasn’t suited for the browsers early on. The main difference between AMD and CommonJS lies in its support for asynchronous module loading.
//Calling define with a dependency array and a factory function
define(['dep1', 'dep2'], function (dep1, dep2) {
//Define the module value by returning a value.
return function () {};
});
// Or:
define(function (require) {
var dep1 = require('dep1'),
dep2 = require('dep2');
return function () {};
});
Implementations
Currently the most popular implementations of AMD are require.js and Dojo.
ECMAScript 6 modules
Fortunately, the ECMA team behind the standardization of JavaScript decided to standardize modules. We finally have a standard to define modules in Javascript which compatible with both synchronous and asynchronous modes of operation.
- On lines of
require
anddefine
, ES6 modules have animport
directive which can be used to bring in modules into namespace. export
helps to explicitly make elements public. A module can have 2 types of exportsnamed exports
which can be several per moduledefault export
primary export of module
Importing examples
// Default exports and named exports
import theDefault, { named1, named2 } from 'src/mylib';
import theDefault from 'src/mylib';
import { named1, named2 } from 'src/mylib';
// Renaming: import named1 as myNamed1
import { named1 as myNamed1, named2 } from 'src/mylib';
// Importing the module as an object
// (with one property per named export)
import * as mylib from 'src/mylib';
// Only load the module, don’t import anything
import 'src/mylib';
Exporting examples
// export inline
export var myVar1 = ...;
export let myVar2 = ...;
export const MY_CONST = ...;
export default 123;
// define everyting and export at the last
export { MY_CONST, myFunc };
// export things under different names:
export { MY_CONST as THE_CONST, myFunc as theFunc };
ReExporting examples Re-exporting means adding another module’s exports to those of the current module.
// add all of the other module’s exports:
export * from 'src/other_module';
// be more selective
export { foo, bar } from 'src/other_module';
// Export other_module’s foo as myFoo
export { foo as myFoo, bar } from 'src/other_module';
// Re-export other_module's default export
export { default } from 'src/other_module';
The above exampled are taken from the wonderful 2ality post
Module loading techniques summary
type | Runs on | Loaded | Filename ext. |
---|---|---|---|
Script | servers | async | .js |
CommonJS module | browsers | sync | .js .cjs |
AMD module | browsers | async | .js |
ECMAScript module | browsers and servers | async | .js .mjs |