From IIFEs to ES6 Modules

JavaScript Modules

  • Isolates code / not in the global scope
  • Automatically runs in strict mode
  • Don't have to worry about ordering of script tags 
  • Can be imported at runtime
  • Classic <script> tags block HTML parsing - modules can be downloaded parallel to the HTML parsing
  • Supported by all modern browsers
  • Can use tree shaking when bundling

Dynamic Imports

  • When there is a low likelihood that you will need the code you are importing, or you will not need it until a later time.
  • When the import specifier string needs to be constructed dynamically. (Static import only supports static specifiers.)

 Load a module conditionally or on demand

Future Proofing

"A lot of the most exciting new browser features are built on top of modules, not classic scripts. That means if you want to use any of these features, your code needs to be deployed as real modules, not transpiled to ES5 and loaded via classic script tags..." - Philip Walton, Google Engineer

  • Built-in modules
  • HTML Modules
  • CSS Modules
  • JSON Modules
  • Import Maps
  • Sharing modules between workers, service workers, and the window

Browser Support

Import an entire module's contents  

// This inserts myModule into the current scope, containing all 
// the exports from the module in the file located in /modules/my-module.js. 

import * as myModule from '/modules/my-module.js';




// Accessing the exports means using the module name ("myModule" 
// in this case) as a namespace.

myModule.doAllTheAmazingThings();

Import a Single Export from a Module 

// This inserts myExport into the current scope

import { myExport } from '/modules/my-module.js';




// Can be called as a function

myExport();

Import Multiple Exports from a Module 

// This inserts myExport into the current scope

import { foo, bar } from '/modules/my-module.js';




// Can be called as functions

foo();
bar();

Import with a More Convenient Alias

// This inserts shortName into the current scope

import {reallyReallyLongModuleExportName as shortName}
	from '/modules/my-module.js';




// Can be called as a function

shortName();

Import a Module for It's Side Effects Only

// This runs the module's global code, 
// but doesn't actually import any values

import '/modules/my-module.js';


// This works with dynamic imports too

(async () => {
  if (somethingIsTrue) {
    // import module for side effects
    await import('/modules/my-module.js');
  }
})();

Concerns

  • module cache busting
  • more requests but smaller file sizes
  • how to bundle (rollup?) - more tools!!

Demo in Omni

Importing Defaults

// The simplest version directly imports the default:

import myDefault from '/modules/my-module.js';


// It is also possible to use the default syntax with the ones 
// seen above (namespace imports or named imports). In 
// such cases, the default import will have to be declared 
// first. For instance:

import myDefault, * as myModule from '/modules/my-module.js';
import myDefault, {foo, bar} from '/modules/my-module.js';


// Works with dynamic imports. You need to destructure and 
// rename the "default" key from the returned object.
 
(async () => {
  if (somethingIsTrue) {
    const { default: myDefault, foo, bar } = await import('/modules/my-module.js');
  }
})();

From IIFEs to ES6 Modules

By Eric Danowski

From IIFEs to ES6 Modules

  • 142