Modules – Organizing Code with ES6 Modules
The introduction of ES6 Modules (also known as ES2015 Modules) has revolutionized the way we structure and organize JavaScript code. Modules allow developers to break code into reusable, isolated units, improving the maintainability and readability of applications. In this article, we will explain the basics of ES6 Modules and show how they can be used in practice.
What are ES6 Modules?
A Module is a file that has its own scope and can export certain parts (variables, functions, classes) to the outside. Other modules can then import and use these exported parts. This promotes a clean separation of concerns and prevents name conflicts.
Why Use Modules?
- Better Organization: Modules help divide code into logical units.
- Reusability: Once written modules can be used in different parts of the application or even in other projects.
- Isolated Scope: Variables and functions within a module are not globally available by default, preventing unexpected overwrites.
Basics: Export and Import
Exporting Modules
There are two types of exports in ES6 Modules:
- Named Exports: Multiple exports per module are possible.
- Default Exports: Only one default export per module.
Example of Named Exports:
File: mathUtils.js
// Export functions
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
// Export variable
export const PI = 3.1415;
Example of Default Export:
File: logger.js
export default function log(message) {
console.log(`[Log]: ${message}`);
}
Importing Modules
Named Imports:
import { add, multiply, PI } from './mathUtils.js';
console.log(add(2, 3)); // 5
console.log(multiply(4, 5)); // 20
console.log(PI); // 3.1415
Renaming Imports:
import { add as sum, multiply as product } from './mathUtils.js';
console.log(sum(2, 3)); // 5
console.log(product(4, 5)); // 20
Importing All Exports as Object:
import * as math from './mathUtils.js';
console.log(math.add(2, 3)); // 5
console.log(math.multiply(4, 5)); // 20
console.log(math.PI); // 3.1415
Default Import:
import log from './logger.js';
log('This is a message'); // [Log]: This is a message
Combination of Default and Named Exports
A module can have both a default export and named exports.
File: toolkit.js
export default function greet(name) {
console.log(`Hello, ${name}!`);
}
export const version = '1.0.0';
export function farewell(name) {
console.log(`Goodbye, ${name}!`);
}
Importing:
import greet, { version, farewell } from './toolkit.js';
greet('Anna'); // Hello, Anna!
console.log(version); // 1.0.0
farewell('Anna'); // Goodbye, Anna!
Using Modules in Browsers
In modern browsers, ES6 Modules can be used directly by setting the type="module" attribute in the <script> tag.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Module Example</title>
</head>
<body>
<script type="module" src="main.js"></script>
</body>
</html>
File: main.js
import { add } from './mathUtils.js';
console.log(add(10, 20)); // 30
Important: When loading modules in the browser, files must be served through a web server. Directly opening the HTML file via the file system (file://) leads to CORS errors.
Using Modules in Node.js
From Node.js version 12, ES6 Modules can be used with the file extension .mjs or by setting "type": "module" in the package.json.
Option 1: Using .mjs
File: mathUtils.mjs
export function subtract(a, b) {
return a - b;
}
File: main.mjs
import { subtract } from './mathUtils.mjs';
console.log(subtract(10, 5)); // 5
Execution:
node main.mjs
Option 2: Setting "type": "module"
In package.json
{
"name": "module-project",
"version": "1.0.0",
"type": "module"
}
After that, .js files can be used with ES6 Modules.
Practical Tips
- Use Relative Paths: When importing, relative paths must be specified with
./or../if it’s not a module fromnode_modules. - Specify File Extensions: In browsers and Node.js, file extensions
.jsor.mjsmust be specified when importing. - Avoid Circular Dependencies: Modules should be designed so that they don’t create circular dependencies to avoid errors.
Comparison with CommonJS
Before ES6, modules in JavaScript were frequently used with the CommonJS format, especially in Node.js.
CommonJS Example:
File: mathUtils.js
function divide(a, b) {
return a / b;
}
module.exports = { divide };
Importing:
const { divide } = require('./mathUtils.js');
console.log(divide(10, 2)); // 5
Differences:
- Syntax: ES6 uses
importandexport, while CommonJS usesrequireandmodule.exports. - Evaluation Time: ES6 Modules are static and evaluated at compile time, while CommonJS is dynamically evaluated at runtime.
- Asynchronous Loading: ES6 Modules support asynchronous loading, which is useful in browsers.
Conclusion
ES6 Modules provide a standardized and efficient method to organize JavaScript code. By using import and export, code becomes more modular, maintainable, and easier to understand. Whether you’re developing a small library or a large application, using ES6 Modules is an important step toward modern JavaScript development.
Start using ES6 Modules in your projects today and experience the difference in structure and quality of your code!