While modern frameworks like Webpack paired with Vue, Angular, or React dominate front-end development today, RequireJS played a significant role in the era of modular JavaScript. This article revisits RequireJS by addressing a common issue encountered when deploying static HTML pages to a remote server.
The Problem: Unreliable Script Loading Order
Consider a simple page using the ECharts library to render a bar chart:
<html lang="zh-cn">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<style type="text/css">
#dom{width:200px;height:200px;}
</style>
</head>
<body>
<div id="dom"></div>
</body>
</html>
<script src="echart.min.js"></script>
<script src="my.js"></script>
In this setup, the browser loads scripts sequentially in the order they appear. However, in a real network environment, you might encounter the error: echarts is not defined. This happens because my.js executes before echart.min.js has fully loaded. Hitting refresh might temporarily fix it due to caching, but the core issue is unreliable dependency loading.
RequireJS solves this by managing dependencies and ensuring scripts load in the correct order.
Project Structure Without RequireJS
project/
├── echart.min.js
├── my.js
├── gongan.html
└── ...
The gongan.html file contained multiple <script> tags, leading to potential race conditions.
Integrating RequireJS
First, download RequireJS from the official site. Then modify the HTML to use a single entry point:
<html lang="zh-cn">
<head>
<meta charset="UTF-8" />
<title>公安主页</title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<meta name=viewport content="width=device-width, initial-scale=1,user-scalable=no">
<link rel="stylesheet" type="text/css" href="style/css/index.css">
<link rel="stylesheet" type="text/css" href="style/fonts/fonts.css">
<script src="style/lib/require.js" data-main="style/js/main" async=true defer></script>
</head>
<body class="iframe-body">
<div id="index-g">
<div class="today-data"></div>
<div class="im-working"></div>
<div class="last-three-items clearfix"></div>
<div class="index-footer-nav clearfix"></div>
</div>
</body>
</html>
data-main="style/js/main"points to the entry JavaScript file (RequireJS loads it automatically).async=trueanddeferensure non-blocking loading.
New Project Structure
project/
├── style/
│ ├── lib/
│ │ └── require.js
│ ├── js/
│ │ ├── main.js
│ │ ├── util.js
│ │ └── ...
│ └── ...
└── ...
Notice the addition of util.js, which replaces the logic from the original inner-index.js.
Original inner-index.js (procedural code)
// Traditional function-oriented code, called on window.onload
function drawChart() { ... }
function initData() { ... }
window.onload = function() {
drawChart();
initData();
};
New util.js (AMD module)
define(['echarts'], function(echarts) {
return {
drawChart: function() {
// Use echarts here
var myChart = echarts.init(document.getElementById('dom'));
// ...
},
initData: function() {
// ...
}
};
});
Configuration with main.js
require.config({
baseUrl: 'style/js',
paths: {
'echarts': '../lib/echart.min',
'jquery': '../lib/jquery-1.9.1.min'
},
shim: {
// For non-AMD libraries, see section below
}
});
require(['util'], function(util) {
util.drawChart();
util.initData();
});
baseUrl: Sets a base directory for module paths. Combined withpaths, it resolves module locations. For example,echartsresolves tostyle/js/../lib/echart.min.js— effectivelystyle/lib/echart.min.js.paths: Maps module names to file paths. The.jsextension is automatically appended.require(['util'], ...): loads theutilmodule and its dependencies (likeecharts) before executing the callback. This guarantees thatechartsis available whenutil.drawChart()runs.
By using define() with explicit dependencies, RequireJS ensures correct loading order. You can verify in the browser's Network tab that echart.min.js loads before util.js.
Hnadling Non-AMD (Traditional) Libraries
Not all libraries follow the AMD pattern. For example, suppose you have a1.js:
// a1.js
function aa() {
console.log(12345);
}
If you try require(['a1'], function(aa) { aa(); }), it will fail because aa is not returned by the module—it's a global function.
Use shim to configure dependencies for non-AMD scripts:
require.config({
baseUrl: 'style/js',
paths: {
'a1': 'path/to/a1'
},
shim: {
'a1': {
exports: 'aa' // Tell RequireJS that the module exports the global 'aa'
}
}
});
require(['a1'], function(aa) {
aa(); // Works now
});
If the library exports multiple globals:
// a1.js
function aa() { ... }
function bb() { ... }
Configure shim with an init function:
shim: {
'a1': {
init: function() {
return {
aa: aa,
bb: bb
};
}
}
}
// Usage
require(['a1'], function(a1) {
a1.aa();
a1.bb();
});
This approach makes any legacy script compatible with RequireJS's module system.