TypeScript → Lesson 5: Modules & organization

Lesson 5: Modules & organization

How to organize JavaScript code into reusable modules for better readability and maintainability.

Learning goals

  • Understand why organizing code into modules helps readability and reuse.
  • Learn what ES modules are and how to use <script type="module">.
  • Create and import small helper modules: `shared/dom.js` and `shared/storage.js`.
  • Practice moving functions into modules and importing them.

Why organize code?

Good organization makes code easier to read, test, reuse and change. Splitting code into small modules:

  • Reduces file size and cognitive load.
  • Lets you reuse helpers across pages.
  • Makes responsibilities explicit (one module = one concern).

What is a module?

A module is a JavaScript file that exports values (functions, constants, objects) and other files import them. In modern browsers you can use ES modules natively.

How to use ES modules in the browser

  1. Use <script type="module"> in your HTML.
  2. Export what you need from a file with export or export default.
  3. Import using a relative path: import { fn } from '../shared/dom.js'.

Important

  • Module imports are resolved relative to the importing HTML or JS file.
  • When opening files with file:// some browsers block module imports due to CORS; run a local server instead (example below).
<!-- example in your page -->
<script type="module" src="../lessons/javascript-lesson-05.js"></script>
<!-- or inline -->
<script type="module">
  import { qs } from '../shared/dom.js';
  console.log(qs('h1').textContent);
</script>
      

Example helpers (practical)

Create a shared folder at the site root and add two files: shared/dom.js and shared/storage.js. Below are minimal, practical implementations.

shared/dom.js

// exports: qs, qsa, on, createEl
export function qs(selector, root = document) {
  return root.querySelector(selector);
}
export function qsa(selector, root = document) {
  return Array.from((root || document).querySelectorAll(selector));
}
export function on(target, event, handler, options) {
  const el = (typeof target === 'string') ? qs(target) : target;
  if (!el) return () => {};
  el.addEventListener(event, handler, options);
  return () => el.removeEventListener(event, handler, options);
}
export function createEl(tag, attrs = {}, children = []) {
  const el = document.createElement(tag);
  Object.keys(attrs).forEach(k => {
    if (k === 'text') el.textContent = attrs[k];
    else el.setAttribute(k, attrs[k]);
  });
  if (typeof children === 'string') el.innerHTML = children;
  else children.forEach(c => el.appendChild(typeof c === 'string' ? document.createTextNode(c) : c));
  return el;
}
      

shared/storage.js

// exports: loadJSON, saveJSON
export function loadJSON(key, fallback = null) {
  try {
    const raw = localStorage.getItem(key);
    return raw ? JSON.parse(raw) : fallback;
  } catch (e) {
    return fallback;
  }
}
export function saveJSON(key, value) {
  try {
    localStorage.setItem(key, JSON.stringify(value));
  } catch (e) {
    // could be quota error
  }
}
      

Importing the helpers

From this lesson file (in lessons/) import with a path that reaches the root shared/ folder:

<script type="module">
import { qs, on } from '../shared/dom.js';
import { loadJSON, saveJSON } from '../shared/storage.js';

const prefs = loadJSON('prefs', { theme: 'light' });
console.log('prefs', prefs);

on('button#save', 'click', () => {
  saveJSON('prefs', { updated: Date.now() });
});
</script>
      

Keep functions small

Each exported function should do one thing (single responsibility). Small functions are easier to test and reuse.

Common mistakes

  • Wrong import path: remember imports are relative to the importing file. From lessons/ to shared/ use ../shared/....
  • Forgetting type="module" on the <script> tag; without it imports won't work.
  • Opening via file:// may block module imports — run a local server (example below).

Run a quick local server (recommended)

# Python 3
        python -m http.server 8000

        # Then open http://localhost:8000/lessons/javascript-lesson-05.html
          

Practice tasks

  1. Move a UI helper (for example a function that toggles a class on an element) from this page into shared/dom.js, export it, and import it back.
  2. Create a small module shared/math.js that exports a clamp function and import it where needed.
  3. Refactor a long function into two small functions and export the smaller pieces.

Done — modules make your site easier to maintain. Try the practice tasks now.