class: center, middle # JavaScript Modules --- ## Summary .breadcrumbs[
JavaScript Modules
] Learn about JavaScript module systems and ECMAScript modules. This material is part of the [mobile development course](https://github.com/MediaComem/comem-devmobil) 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; } // Reveal a public interface. return { 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 () {}; ``` --- ### JavaScript module systems compabitility .breadcrumbs[
JavaScript Modules
>
Modern JavaScript module systems
] Those systems are **not natively supported by browsers** 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. 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. With ECMAScript 2015 (ES6), a new standard has emerged—[ECMAScript Modules][esm] ([import][esm-import]/[export][esm-export]), which is now widely supported by the major browsers. --- ## 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 is compatible with most modern browsers, [and with Node.js][node-esm]. ```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 `