Skip to content

Instantly share code, notes, and snippets.

@rauschma
Last active January 15, 2022 01:46
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save rauschma/6fc72435e8a159b58b752827608c4e9c to your computer and use it in GitHub Desktop.
Save rauschma/6fc72435e8a159b58b752827608c4e9c to your computer and use it in GitHub Desktop.

Cheat sheet: modules

Named exports, named imports, namespace imports

If we put export in front of a named entity inside a module, it becomes a named export of that module. All other entities are private to the module.

//===== lib1.mjs =====
// Named exports
export const one = 1, two = 2;
export function myFunc() {
  return 3;
}
//===== main1a.mjs =====
// Named imports
import {one, myFunc as f} from './lib1.mjs';
assert.equal(one, 1);
assert.equal(f(), 3);

// Namespace import
import * as lib1 from './lib1.mjs';
assert.equal(lib1.one, 1);
assert.equal(lib1.myFunc(), 3);

The string after from is called a module specifier. It identifies from which module we want to import.

Dynamic imports

So far, all imports we have seen were static, with the following constraints:

  • They have to appear at the top level of a module.
  • The module specifier is fixed.

Dynamic imports via import() [ES2020] don’t have those constraints:

//===== main1b.mjs =====
function importLibrary(moduleSpecifier) {
  import(moduleSpecifier)
  .then((lib1) => {
    assert.equal(lib1.one, 1);
    assert.equal(lib1.myFunc(), 3);
  });
}
importLibrary('./lib1.mjs');

Default exports and imports

A default export is mainly used when a module only contains a single entity (even though it can be combined with named exports).

//===== lib2a.mjs =====
export default function getHello() {
  return 'hello';
}

A default export is the exception to the rule that function declarations always have names. In the previous example, we can omit the name getHello.

//===== lib2b.mjs =====
export default 123; // (A) instead of `const`

There can be at most one default export. That’s why const or let can’t be default-exported (line A).

//===== main2.mjs =====
import lib2a from './lib2a.mjs';
assert.equal(lib2a(), 'hello');

import lib2b from './lib2b.mjs';
assert.equal(lib2b, 123);

Kinds of module specifiers

There are three kinds of module specifiers:

  • Absolute specifiers are full URLs – for example:

    'https://www.unpkg.com/browse/yargs@17.3.1/browser.mjs'
    'file:///opt/nodejs/config.mjs'
    

    Absolute specifiers are mostly used to access libraries that are directly hosted on the web.

  • Relative specifiers are relative URLs (starting with '/', './' or '../') – for example:

    ./sibling-module.js
    ../module-in-parent-dir.mjs
    ../../dir/other-module.js
    

    Relative specifiers are mostly used to access other modules within the same code base.

  • Bare specifiers are paths (without protocol and domain) that start with neither slashes nor dots – for example:

    'some-package'
    '@some-npm-scope/some-scoped-package'
    'some-package/with/sub-path'
    

    Bare specifiers are mostly used to refer to npm packages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment