Understanding JavaScript Module Systems: From Require to ES6 Imports
This article explains the evolution of JavaScript module patterns—including CommonJS, AMD, CMD, and ES6—by illustrating their syntax, loading behavior, and practical drawbacks, and shows how to simulate modularity with simple global objects and closures.
Preface
The keywords require and import introduce module concepts such as CommonJS, CMD, AMD, RequireJS, and SeaJS, which can be confusing for frontend beginners.
JavaScript Basics
Compared with import statements in Objective‑C, Swift, and Java, JavaScript’s dynamic nature changes how modules work.
<html>
<head>
<script type="text/javascript" src="index.js"></script>
</head>
<body>
<p id="hello"> Hello Wrold </p>
<input type="button" onclick="onPress()" value="Click me" />
</body>
</html> function onPress() {
var p = document.getElementById('hello');
p.innerHTML = 'Hello bestswifter';
}The <script> tag works like an import, allowing the button’s onclick handler to call onPress defined in index.js.
If the displayed text must be generated dynamically by another file, a simple index.js is insufficient. Suppose the logic resides in math.js:
function add(a, b) {
return a + b;
}Attempting to write index.js with an ES‑style import fails because JavaScript does not support that syntax natively:
import "math.js"
function onPress() {
var p = document.getElementById('hello');
p.innerHTML = add(1, 2);
}Instead, both scripts must be referenced in the HTML:
<html>
<head>
<script type="text/javascript" src="index.js"></script>
<script type="text/javascript" src="math.js"></script>
</head>
<body>
<p id="hello"> Hello Wrold </p>
<input type="button" onclick="onPress()" value="Click me" />
</body>
</html> function onPress() {
var p = document.getElementById('hello');
p.innerHTML = add(1, 2);
}This approach relies on the correct loading order of HTML scripts, which is fragile.
Initial Modularization
The main pain points are:
index.js cannot import modules directly and depends on HTML.
index.js lacks a namespace, making it impossible to distinguish the origin of functions like add.
One quick fix is to expose a simple namespace object:
function onPress() {
var p = document.getElementById('hello');
p.innerHTML = math.add(1, 2);
}
var math = {
base: 0,
add: function(a, b) { return a + b + base; }
};To hide internal state, wrap the module in a closure:
var math = (function() {
var base = 0;
return {
add: function(a, b) { return a + b + base; }
};
})();For a more Node‑like experience, introduce a global module object to store exports: var module = { exports: {} }; Expose the math module:
var math = (function() {
var base = 0;
return {
add: function(a, b) { return a + b + base; }
};
})();
module.exports.math = math;Consume it in index.js:
var math = module.exports.math;
function onPress() {
var p = document.getElementById('hello');
p.innerHTML = math.add(1, 2);
}Existing Modular Solutions
The simple approach still suffers from manual load order management, lack of asynchronous loading, and namespace collisions. Various standards have emerged to address these issues.
CommonJS
CommonJS, used by Node.js, loads modules synchronously, which works on the server but not in browsers where scripts must load asynchronously.
AMD
RequireJS implements the Asynchronous Module Definition (AMD) pattern, loading modules via importScripts and executing a callback after all dependencies are ready.
require(['myModule1', 'myModule2'], function (m1, m2) {
// main logic
m1.printName();
m2.printName();
});All listed modules are fetched in parallel, and the callback runs only after they have been loaded.
CMD
Sea.js follows the Common Module Definition (CMD) pattern, allowing dependencies to be declared near their usage and supporting both synchronous and asynchronous loading.
define(function (require, exports, module) {
var foo = require('foo'); // sync
foo.add(1, 2);
// async loading
require.async('math', function (math) {
math.add(1, 2);
});
});CMD loads modules in the order they appear in the source, preserving a predictable execution sequence.
ES6 Modules
ES6 introduces native export and import statements. Because most browsers still lack full support, tools like Babel transpile import to require. Nevertheless, using the ES6 syntax is encouraged for future‑proof code.
References
Can I access variables from another file?
浅谈 JavaScript 模块化编程
前端模块化
详解JavaScript模块化开发
requireJS实现原理研究
Javascript模块化编程(一):模块的写法
Javascript模块化编程(二):AMD规范
浏览器加载 CommonJS 模块的原理与实现
Node中没搞明白require和import,你会被坑的很惨
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITFLY8 Architecture Home
ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
