Skip to content
Retr0 Academy
Advanced JavaScript

Advanced JavaScript · 2 min read

ES Modules

import and export, named vs default exports, live bindings, dynamic import() for code splitting, and module scope.

A module is a file with its own scope. Nothing leaks to the global scope unless you export it, and nothing comes in unless you import it. Every modern dApp front end, including this one, is built from modules.

Named and default exports

js

// near.js
export const NETWORK = "testnet";
export function explorerUrl(account) {
  return "https://testnet.nearblocks.io/address/" + account;
}
export default function formatNear(yocto) { /* ... */ }
 
// app.js
import formatNear, { NETWORK, explorerUrl as link } from "./near.js";
import * as near from "./near.js"; // namespace object: near.NETWORK

Prefer named exports: they are easier to search for, rename consistently, and tree-shake.

Modules behave differently from scripts

Classic <script><script type="module">
ScopeGlobalModule scope
Strict modeOpt-inAlways on
LoadingBlocks parsing unless deferDeferred by default
Top-level awaitNoYes
RunsEvery time includedOnce per URL, then cached

Live bindings

Imports are live views of the exporter's variables, not copies:

js

// counter.js
export let count = 0;
export function inc() { count++; }
 
// main.js
import { count, inc } from "./counter.js";
inc();
console.log(count); // 1, the binding updated
count = 5;          // TypeError: imports are read-only

Dynamic import()

import() returns a promise and loads code on demand. That is how this site loads the wallet selector only when you need it:

js

button.addEventListener("click", async () => {
  const { setupWalletSelector } = await import("@near-wallet-selector/core");
  // ...the wallet code is downloaded only now
});

Try it: modules in the browser

Inline module scripts can import from URLs. Here, a module is created from a string with a Blob URL so the example is self-contained.

Import a module, use its exports, load one dynamically
<pre id="out"></pre>

Edit this example in the Playground.

Open in Playground

Summary

Modules give every file private scope, explicit dependencies and strict mode. Use named exports, remember imports are live and read-only, and reach for import() to split heavy code like wallet SDKs out of your first load.