What Are JavaScript Modules?
Modules are reusable pieces of code that can be exported from one file and imported into another. They allow you to:
- Encapsulate Functionality: Keep specific logic or functionality separate.
- Reuse Code: Share common code across different files or projects.
- Maintain Clean Code: Organize the codebase, making it more readable and maintainable.
Types of JavaScript Modules
- ES6 Modules (Standardized)
The modern way to handle modules in JavaScript using export and import keywords. - CommonJS (Node.js)
A module system primarily used in Node.js with module.exports and require(). - AMD (Asynchronous Module Definition)
Used in browsers for asynchronous loading of modules.
Exporting and Importing in ES6 Modules
1) Exporting Code:
You can export functions, objects, or variables from a module to make them available in other files.
a. Named Export:
Export multiple entities using their names.
Example:
// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
b. Default Export:
Export a single default entity.
Example:
// greet.js
export default function greet(name) {
return `Hello, ${name}!`;
}
2) Importing Code:
a. Named Import:
Use curly braces to import specific entities.
Example:
// main.js
import { add, subtract } from './math.js';
console.log(add(5, 3)); // Output: 8
console.log(subtract(5, 3)); // Output: 2
b. Default Import:
Import the default entity without curly braces.
Example:
// main.js
import greet from './greet.js';
console.log(greet('John')); // Output: Hello, John!
c. Combined Import:
Import both named and default exports.
Example:
// utilities.js
export default function defaultFunction() {
console.log('Default function');
}
export function namedFunction() {
console.log('Named function');
}
// main.js
import defaultFunction, { namedFunction } from './utilities.js';
defaultFunction(); // Output: Default function
namedFunction(); // Output: Named function
Benefits of Using JavaScript Modules
- Code Reusability: Easily reuse functions and logic across files.
- Encapsulation: Prevent variable and function name conflicts by isolating code in modules.
- Maintainability: Organize code into smaller, manageable pieces.
- Lazy Loading: Load modules dynamically only when needed.
Dynamic Imports
Dynamic imports allow you to load modules at runtime using the import() function. This is especially useful for optimizing performance by loading modules on-demand.
Example:
function loadModule() {
import('./math.js')
.then((module) => {
console.log(module.add(10, 5)); // Output: 15
})
.catch((error) => {
console.error('Error loading module:', error);
});
}
loadModule();
Working with Modules in Browsers
In browsers, ES6 modules work by using the type=”module” attribute in the <script> tag.
Example:
<!-- index.html -->
<script type="module" src="main.js"></script>
Make sure the files are served over HTTP(S) or are part of a local server, as modules don’t work with local file paths (file://).
Real-World Example: Creating a Utility Library
Step 1: Create a Module
// utilities.js
export function formatDate(date) {
return new Intl.DateTimeFormat('en-US').format(date);
}
export function generateRandomNumber() {
return Math.floor(Math.random() * 100);
}
Step 2: Use the Module
// app.js
import { formatDate, generateRandomNumber } from './utilities.js';
console.log(formatDate(new Date())); // Output: 11/25/2024
console.log(generateRandomNumber()); // Output: (random number between 0 and 99)
Handling Module Errors
Module Not Found:
Ensure file paths are correct and extensions are included if necessary.
Example:
// Correct file path
import { func } from './module.js';
Cyclic Dependencies:
Avoid circular dependencies by restructuring your modules.