What Is JavaScript Modules?
October 25, 2024
In This Article You Will Learn
- The evolution and importance of front-end modularization
- What are CommonJS, AMD, CMD, UMD, ES Module, and Module Bundler
In interviews, questions about bundling tools are very common. It's almost inevitable that you'll be asked why bundling tools are necessary or how front-end engineering is implemented. Before answering these questions, it's essential to understand front-end modularization. In this article, we'll explore the evolution and benefits of front-end modularization.
What is Modularization?
Modularization is the process where developers divide code or a system into different modules. Each module represents a complete small program or functionality. When all modules are assembled together, they form a complete system that meets the required functionalities.
Node.js has supported modularization almost from the start. In contrast, modularization in web development progressed more slowly. However, today there are many tools that support front-end modularization.
Why Do We Need Front-End Modularization?
Let's imagine how JavaScript would run in the browser without bundling tools or modular syntax:
Method 1: Each feature is a separate JavaScript
<script>
file loaded individually. This approach makes the code hard to scale, loading too many scripts can cause network bottlenecks, and there are dependency issues related to the order of loading.Method 2: Use one
large .js
file that contains all functionalities. This leads to maintenance and readability problems.
Before modular bundling tools existed, developers used solutions like Immediately Invoked Function Expressions (IIFE) to address these issues. IIFEs leverage JavaScript's closure feature to achieve data privacy and share methods.
Here's an example:
const moduleB = (function () {
return {
number: 200,
};
})();
const moduleA = (function (otherModule) {
let number = 100;
function getNumber() {
console.log(number + otherModule.number);
}
return { getNumber };
})(moduleB);
`
With moduleA, you can access the getNumber
method while keeping the number
variable private, preventing external access. Additionally, moduleA
can incorporate other modules, allowing you to use functionalities from different modules within moduleA
. This approach solves many problems related to code organization and dependency management.
moduleA.getNumber(); // 300
moduleA.number; // undefined
The concept of modularization today stems from the practices used in IIFEs. As the demand for modules in front-end development grew, various modularization solutions emerged, evolving into standard specifications like CommonJS and ES Modules (ESM). The next section introduces these universal modular standards.
For further reading, check out: What is an Immediately Invoked Function Expression (IIFE) in JavaScript? Pros and Cons
JavaScript Modular Standards
CommonJS
When Node.js was released, it introduced new challenges. Since JavaScript wasn't running in a browser environment, there were no HTML files or <script>
tags to add modules. So, how should Node applications load different pieces of code? The answer was through CommonJS.
Developed by the community in 2009, the CommonJS specification introduced the require and export syntax for declaring modules. Each file is treated as a separate module and is loaded synchronously, making it well-suited for server-side development.
AMD (Asynchronous Module Definition)
AMD stands for Asynchronous Module Definition. It originated from the Dojo Toolkit, a JavaScript library for building web applications. AMD was designed specifically for the browser from the beginning. The most popular implementation of AMD is RequireJS, a JavaScript module loader.
AMD can automatically determine dependencies and loads modules asynchronously, preventing blocking issues. It also allows multiple modules to be defined within a single file.
CMD (Common Module Definition)
CMD emerged later, with Sea.js promoting it starting in 2012. It combines the strengths of both CommonJS and AMD specifications and is tailored for asynchronous module loading in the browser. In this standard, each file represents a single module.
UMD (Universal Module Definition)
AMD and CommonJS are the two most popular module standards, each with its own advantages and disadvantages. Developers typically choose a standard based on their specific needs. However, using code developed with different standards can lead to compatibility issues. UMD addresses this by allowing both AMD and CommonJS to use the same file, ensuring broader compatibility.
ES Module (ESM)
With the release of ES6, JavaScript finally achieved native module functionality, combining the benefits of both CommonJS and AMD:
Like CommonJS, it uses simple syntax with export and import, treating each file as a module. Similar to AMD, it supports asynchronous loading.
The Role of Module Bundlers
The previous section introduced various module standards and tools like RequireJS that enable module usage in the browser. However, despite these modularization tools, differences in browser support can make it challenging to use third-party modules (e.g., packages from npm) smoothly.
Due to compatibility issues with browser module mechanisms, the front-end industry developed tools like Webpack to help developers bundle modules. If your code uses an npm package, Webpack assists in bundling it, making it behave like a module you wrote yourself. This effectively resolves issues related to browser support for module features.
Moreover, tools like Webpack do more than just manage module loading. They extend support to different types of resources, allowing various assets (like images, fonts, and stylesheets) to become modules. Additionally, they offer optimizations that enhance both user and developer experiences.