JavaScript Modules

JavaScript modules allow you to break up your code into separate files. Each module has its own scope and can export values that other modules can import. Modules help organize code, prevent naming conflicts, and promote reusability.

What Are Modules?

A module is simply a JavaScript file that can export and import functionality. Before modules, all JavaScript files shared the global scope, leading to naming conflicts and hard-to-maintain code.

Module Concept
// Before modules: everything is global
// file1.js: var name = 'Alice';
// file2.js: var name = 'Bob'; // Overwrites!

// With modules: each file has its own scope
// math.js: export function add(a, b) { return a + b; }
// app.js: import { add } from './math.js';

// Simulating module behavior
const mathModule = (function() {
  function add(a, b) { return a + b; }
  function multiply(a, b) { return a * b; }
  return { add, multiply };
})();

console.log(mathModule.add(2, 3));
console.log(mathModule.multiply(4, 5));

Script type="module"

To use modules in the browser, you must add type="module" to the script tag. This tells the browser to treat the file as a module with its own scope.

Using type="module" in HTML
// In HTML:
// <script type="module" src="app.js"></script>

// Key differences from regular scripts:
// 1. Module scope (not global)
// 2. Strict mode by default
// 3. Deferred by default
// 4. Executed only once (even if imported multiple times)

console.log('Module scripts are deferred by default');
console.log('They run after the HTML is parsed');
console.log('Like adding the defer attribute');

Module Scope

Variables and functions declared in a module are scoped to that module by default. They are not added to the global scope. Only explicitly exported items are accessible to other modules.

Module Scope vs Global Scope
// Simulating module scope
const moduleA = (function() {
  const secret = 'hidden';
  const publicValue = 'visible';

  return { publicValue };
})();

console.log(moduleA.publicValue);
// moduleA.secret would be undefined
console.log('secret' in moduleA);

// In real modules:
// const secret = 'hidden';        // NOT accessible outside
// export const visible = 'public'; // Accessible via import

Strict Mode by Default

Modules automatically run in strict mode. This means you cannot use undeclared variables, duplicate parameter names, or other sloppy mode features.

Strict Mode in Modules
// In modules, strict mode is automatic
// No need for 'use strict';

// These would cause errors in a module:
// x = 10;  // ReferenceError: x is not defined
// delete Object.prototype;  // TypeError

// Strict mode benefits
const strictExample = (function() {
  'use strict';
  let x = 10;
  console.log('Strict mode prevents silent errors');
  console.log('Variables must be declared: x = ' + x);
  return x;
})();

console.log('Result: ' + strictExample);

Module Benefits and Browser Support

Modules provide many benefits for code organization and are supported in all modern browsers. Bundlers like Webpack and Vite can also handle modules for older browser support.

BenefitDescription
EncapsulationEach module has its own scope
ReusabilityImport functionality across files
Dependency managementClear dependency chain via imports
MaintainabilitySmaller, focused files
No naming conflictsModule-scoped variables
Strict modeAutomatic strict mode prevents bugs
Deferred loadingModules are deferred by default
📝 Note: Modules are loaded using CORS (Cross-Origin Resource Sharing), so they don't work with the file:// protocol. You need a local server to test modules during development. Tools like live-server, Vite, or Webpack dev server handle this automatically.
Exercise:
What attribute must be added to a script tag to use ES modules?
Try it YourselfCtrl+Enter to run
Click Run to see the output here.