Skip to content

Latest commit

 

History

History
302 lines (248 loc) · 9.03 KB

README.md

File metadata and controls

302 lines (248 loc) · 9.03 KB

Anatomy of ES Modules

An overview of modules in javascript.

Contents

Pre-transpilers/tooling era

Post-transpilers/tooling era

  • import/export
  • import()
  • System.import()

ES Modules native

  • import support in the browser [1]
// counter.js
const counterModule = (() => {
    let counter = 0;
    const increaseCounter = () => counter++;
    const decreaseCounter = () => counter--;
    const resetCounter = () => counter = 0;

    return {
        increaseCounter,
        decreaseCounter,
        resetCounter,
        get counter() {
            return counter;
        }
    };
})();
// index.js
counterModule.increaseCounter();
counterModule.decreaseCounter();

console.log(counterModule.counter); // 0

Implementations:

  • nodejs
  • browserify (for browser usage)
  • webpack

Syntax

  • require() function
  • the module object

Main characteristics:

Modules are executed once

  • once a module is required, it is parsed and kept in memory

Required data is passed by value/reference

  • variables are passed by value
// module.js
const a = 2;

module.exports = { a };
// index.js
const a = require('./module').a;

Synchronous parsing

  • all required dependencies are loaded synchronous
  • async implementations for better browser support:

Dynamic module structure

  • all dependencies injected using require() are handled at runtime.
//module.js
console.log('module1 required');
//module2.js
console.log('module2 required');
//module3.js
console.log('module3 required');
//index.js
setTimeout(() => require('./module2'), 3000);

if (false) {
    require('./module3');
}

require('./module');

Cyclic dependencies support

Example from Nodejs docs[7]

Counter example

// counter.js
let counter = 0;
const increaseCounter = () => counter++;
const decreaseCounter = () => counter--;
const resetCounter = () => counter = 0;

module.exports = {
    increaseCounter,
    decreaseCounter,
    resetCounter,
    get counter() {
        return counter;
    }
};
// index.js
const counter = require('./counter');

function main() {
    counterModule.increaseCounter();
    counterModule.decreaseCounter();
}

module.exports = main;

ES Modules

Implementations

  • webpack + babel
  • rollup

Syntax

import[5]

import defaultMember from "module-name";
import * as name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import defaultMember, { member [ , [...] ] } from "module-name";
import defaultMember, * as name from "module-name"
import "module-name";

export[6]

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,  };

// Stage 1 proposal - Lee Byron
export * from ;
export { name1, name2, , nameN } from ;
export { import1 as name1, import2 as name2, , nameN } from ;
export default from ...;
export { default } from ...;

Main characteristics:

Modules are executed once

  • once a module is required, it is parsed and kept in memory

Static module structure[3]

  • all import's and export's must be declared top level
  • import's are hoisted
  • all import's are read only views on exports [13]
// module.js
export default 1+1;
export const a = { b: 2 };
//index.js
import * as module from './module';

module.a.b = 3; //SyntaxError: Cannot assign to read-only object

or

import { a } from './module';

a = 2 //SyntaxError
  • benefits:
    • dead code elimination
    • preparation for HTTP2
    • variable checking (linting, etc.)
    • faster property lookups [16]
var lib = require('lib');
lib.someFunc();
import * as lib from 'lib';
lib.someFunc();

Exporting live bindings

Unlike commonjs, ES modules imports are live bindings to the original primitives. (Objects are passed by references so they will be mutated anyways).

//counter.js
let counter = 0;
const incrementCounter = () => counter++;

export { counter, incrementCounter };
//index.js
import { counter, incrementCounter };

console.log(counter); // 0
incrementCounter();
console.log(counter); //1

Unit testing modules

There are multiple strategies of testing modules. We can split the module types into three categories:

  1. simple/independent modules (no dependencies)
  2. modules which have local dependencies
  3. modules which have 3rd party dependencies

ES modules native

Syntax

import as a keyword for static module parsing

  • browser support: <script type="module"></script>
    • are parsed under use strict mode
    • scoped environment
  • module script tags are differed
  • only paths like '/' or './' are supported
  • each import does a new fetch for the file
<script type="module">
    import { counter, incrementCounter } from './counter.js';
        
        document.body.append(`${counter}\n`);
        incrementCounter();
        document.body.append(`${counter}\n`);
</script>

import() as a function for dynamic module loading

  • stage 3 proposal[8]
import('./counter.js').then(counterModule => {
    console.log(counterModule.counter); // 0
    counterModule.incrementCounter();
    console.log(counterModule.counter); // 1
});

References

  1. ECMAScript modules in browsers - Jake Archibald
  2. ES6 Modules in Depth - Nicolás Bevacqua
  3. Exploring ES6 - Chapter 16 "Modules" - Dr. Axel Rauschmayer
  4. ES6 In Depth: Modules - Jason Orendorff
  5. import - MDN docs
  6. export - MDN docs
  7. Cyclic deps - Nodejs docs
  8. ES Proposals: import() - Domenic Denicola
  9. ES Proposals: export ns from - Lee Byron
  10. ES Proposals: export * as ns from - Lee Byron
  11. The Revealing Module - Addy Osmani
  12. Writing Modular JavaScript With AMD, CommonJS & ES Harmony - Addy Osmani
  13. Exploring ES6 - 16.3.5 Imports are read-only views on exports - Dr. Axel Rauschmayer
  14. ES Modules and NodeJS: Hard Choices - Rod Vagg
  15. ES6 Modules in Chrome Canary M60
  16. PICing on Javascript for fun and profit - CHRIS LEARY
  17. Optimizing Dynamically-Typed Object-Oriented Languages With Polymorphic Inline Caches Paper
  18. EcmaScript Specifications 7th Edition June 2016 - Modules section
  19. WHATWG Integration with the ES Spec
  20. ES Modules interview with Bradley Farias