Skip to content

andrei-cacio/es-modules

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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

Releases

No releases published

Packages

No packages published