# JavaScript Modules Learn about JavaScript module systems and ECMAScript modules. This material is part of [web development courses](https://github.com/MediaComem/comem-webdev) for [Media Engineering](https://heig-vd.ch/formations/bachelor/filieres/ingenierie-des-medias). **You will need** * [Google Chrome][chrome] (recommended, any browser with developer tools will do) **Recommended reading** * [JavaScript][subject-js] --- ## Why are modules needed? .breadcrumbs[
JavaScript Modules
] The purpose of module systems is to solve these 2 concerns: .grid-50[ **Dependency** Pieces of software need to be able to depend upon other pieces of software written by other developers.
] .grid-50[ **Encapsulation** Conflicts between different pieces of software must be avoided (e.g. prevent variable/function name collision, prevent access to private members).
] --- ### Traditional client-side JavaScript dependencies .breadcrumbs[
JavaScript Modules
>
Why are modules needed?
] Dependencies are **implicit** in a traditional client-side JavaScript browser page. It's the **developer's job** to **manually** ensure all dependencies are satisfied **in the correct order**: ```html
Backbone.js Todos
* * * * * * </body> ``` --- ### Traditional client-side JavaScript encapsulation .breadcrumbs[
JavaScript Modules
>
Why are modules needed?
]
In a web page, encapsulation has been traditionally achieved by taking advantage of the JavaScript function scope. Patterns like the [revealing module pattern][revealing-module-pattern] can be used to isolate private members within an [Immediately-Invoked Function Expression (IIFE)][iife]: ```js var myRevealingModule = (function () { // IIFE var privateName = 'John Doe'; // Declare private members inside the IIFE. function publicSetName(name) { privateName = name; } function publicGetName() { return privateName; } return { // Reveal a public interface. setName: publicSetName, getName: publicGetName }; })(); myRevealingModule.setName('John Smith'); console.log(myRevealingModule.getName()); // "John Smith" console.log(privateName); // ReferenceError: privateName is not defined ``` --- ### Problems of traditional dependency & encapsulation .breadcrumbs[
JavaScript Modules
>
Why are modules needed?
] * **Dependency management** gets cumbersome as JavaScript development complexifies: where should newer dependencies be put to maintain proper order of the load chain? * The risk of **naming collisions** increases with the number of dependencies, since all public functions and variables are in the **global scope**. * There is no way to programmatically **import modules** (e.g. revealing modules): dependencies must be handled **manually**. * **Asynchronous loading** of modules is not possible. * Revealing modules are **hard to analyze** for static code analyzers. --- ## Modern JavaScript module systems .breadcrumbs[
JavaScript Modules
] Various module systems were created over the years to solve these issues: * [AMD][amd] - Asynchronous Module Definition with `define()`: ```js define([ 'jquery' ] , function ($) { return function myExample() {}; }); ``` * [CommonJS][commonjs] - Synchronous imports with `require()` (used in Node.js): ```js const jquery = require('jquery'); exports.myExample = function() {}; ``` With ECMAScript 2015 (ES6), a new standard has emerged—[ECMAScript Modules][esm] ([import][esm-import]/[export][esm-export]): ```js import jquery from 'jquery'; import { Component } from 'react'; export function myExample() {} ``` --- ### JavaScript module systems compabitility .breadcrumbs[
JavaScript Modules
>
Modern JavaScript module systems
] Those systems are **not natively supported by browsers** (although ECMAScript modules are almost there), meaning that you cannot use AMD's `define()` or CommonJS's `require()` in the browser without including a module loader like RequireJS or System.js; and support for ECMAScript's `import/export` is not yet complete (and might never be on old browsers like Internet Explorer). Various tools can be used to work with JavaScript modules today: * [Babel][babel] - Transform "new" JavaScript (ES6+, AMD, CommonJS) into "old" JavaScript (ES5). * [System.js][systemjs] - Load any kind of JavaScript module (AMD, CommonJS, ECMAScript). * [TypeScript][ts] - A typed superset of JavaScript that compiles to plain JavaScript. * [Webpack][webpack] - Bundle all your assets (including modern JavaScript) into a minified production bundle. --- ## ECMAScript modules .breadcrumbs[
JavaScript Modules
] ECMAScript modules have been defined by [ECMA TC39, the ECMAScript International, Technical Committee 39][tc39]. Full support has not yet been achieved but it will eventually become compatible with all modern browsers [and with Node.js][node-esm]. It's *the way of the future*: ```js import jquery from 'jquery'; import * as React from 'react'; import { map, reduce } from 'lodash'; const privateFactor = 3; export const foo = [ 1, 2, 3 ]; export function hello(name) { console.log(\`Hello ${name}!`); } export default function doAllTheThings() { hello('World'); return reduce(map(foo, n => n * privateFactor), (memo, n) => memo + n); } ``` --- ### What's in a module? .breadcrumbs[
JavaScript Modules
>
ECMAScript modules
] A module is simply a JavaScript file. It has its own **isolated scope**, meaning that any variables declared within it are **scoped to that module**, i.e. they are not visible to other modules. This is unlike traditional JavaScript environments with `