ES6 - Modules
ES6 - Modules (import/export)
Section titled “ES6 - Modules (import/export)”ES6 introduced a standardized module system for JavaScript, allowing developers to organize code into reusable, self-contained units. Modules help in managing complexity, improving code maintainability, and enabling better dependency management.
A module is essentially a JavaScript file. Variables, functions, or classes defined in a module are private to that module by default. To make them accessible from other modules, you must explicitly export them. To use an exported entity in another module, you import it.
Key Concepts:
Section titled “Key Concepts:”export: Used to expose functions, objects, or primitive values from a module so they can be used by other programs/modules.import: Used to bring in exported members from another module.- Strict Mode: Modules are implicitly in strict mode.
- Scope: Each module has its own top-level scope. Variables declared in a module are not global.
Exporting from a Module
Section titled “Exporting from a Module”There are two main types of exports: named exports and default exports.
1. Named Exports
Section titled “1. Named Exports”A module can export multiple named entities. These can be exported as they are declared or in a single export statement at the end.
// utils.jsexport const PI = 3.14159;
export function add(a, b) { return a + b;}
export class Calculator { constructor() {} multiply(a, b) { return a * b; }}
// Alternatively, export at the end:// const PI = 3.14159;// function add(a, b) { ... }// class Calculator { ... }// export { PI, add, Calculator };2. Default Export
Section titled “2. Default Export”A module can have at most one default export. This is often used for the primary entity the module provides, like a class or a main function.
export default function logMessage(message) { console.log(`LOG: ${message}`);}
// Or for a class:// export default class User { ... }You can also have both named exports and a default export in the same module.
Importing into a Module
Section titled “Importing into a Module”To use exported members, you use the import statement.
1. Importing Named Exports
Section titled “1. Importing Named Exports”Use curly braces {} to specify which named exports to import.
// main.jsimport { PI, add, Calculator } from './utils.js';
console.log(PI);console.log(add(5, 3));const calc = new Calculator();console.log(calc.multiply(4, 5));
// You can also rename imports:// import { add as sumNumbers } from './utils.js';// console.log(sumNumbers(10, 2));
// Import all named exports as an object:// import * as Utils from './utils.js';// console.log(Utils.PI);// console.log(Utils.add(1,1));2. Importing a Default Export
Section titled “2. Importing a Default Export”You can choose any name for the imported default entity.
// main.js (continued)import myLogger from './logger.js'; // 'myLogger' can be any name
myLogger('Application started.');3. Importing Both Default and Named Exports
Section titled “3. Importing Both Default and Named Exports”// export const version = '1.0';// export default function greet() { console.log('Hello!'); }
// main.js// import greet, { version } from './anotherModule.js';Using ES Modules in Browsers
Section titled “Using ES Modules in Browsers”To use ES modules directly in a web browser, you need to tell the browser that a script is a module using type="module" in the <script> tag.
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>ES Modules Demo</title></head><body> <h1>Check the console for module output!</h1> <!-- The main.js script will import from utils.js and logger.js --> <script type="module" src="main.js"></script></body></html>Important notes for browser modules:
- Module scripts are deferred by default (they execute after the HTML is parsed).
- Paths in
importstatements are relative to the location of the importing file (e.g.,./utils.js) or absolute URLs. - You usually need to serve your HTML file and JavaScript modules via a web server (even a simple local one) due to CORS restrictions when using
file:///URLs for modules. - For older browsers that don’t support ES modules, you’d typically use a bundler like Webpack, Rollup, or Parcel, along with a transpiler like Babel, to convert ES modules into a format older browsers can understand.
Using ES Modules in Node.js
Section titled “Using ES Modules in Node.js”Node.js has support for ES modules. There are two main ways to enable it:
- Use the
.mjsfile extension for your module files. - Or, in your
package.jsonfile, add"type": "module". This tells Node.js to treat all.jsfiles in that project as ES modules.
Example with "type": "module" in package.json:
{ "name": "my-node-app", "version": "1.0.0", "type": "module", "main": "main.js"}Then your utils.js, logger.js, and main.js (as defined earlier) would work. You can run main.js using node main.js.
// main.js (Node.js example)import fs from 'fs'; // Importing a built-in Node.js moduleimport _ from 'lodash'; // Importing a third-party package (after npm install lodash)
fs.writeFileSync('test.txt', 'Hello from Node.js module!');console.log(_.capitalize('hello world'));Dynamic Imports (import())
Section titled “Dynamic Imports (import())”ES2020 introduced dynamic imports, which allow you to load modules on demand. The import() function returns a Promise.
async function loadUtility() { if (someCondition) { const utilsModule = await import('./utils.js'); utilsModule.add(10, 20); }}This is useful for code splitting, conditional loading, or loading modules whose paths are determined at runtime.
Benefits of Modules:
Section titled “Benefits of Modules:”- Organization: Breaks down large applications into smaller, manageable pieces.
- Reusability: Code can be easily reused across different parts of an application or in different projects.
- Encapsulation: Hides internal implementation details of a module, exposing only a public API.
- Dependency Management: Clearly defines dependencies between different parts of the code.