The Pre-Bundle Dark Ages: Script Tags, Global Scope, and the Birth of Module Urgency
The notification pinged at 2:17 a.m. on a rainy Tuesday in November 2012, jolting Mia, the lead frontend engineer at a three-person fintech startup in San Francisco’s SoMa district, awake. Her laptop glowed in the dark, displaying a cascade of error logs from the company’s flagship payment processing dashboard: `Uncaught ReferenceError: apiKey is not defined` at line 4,212 of `app.js`—a 90,000-line jQuery monolith that powered the platform used by 12,000 small business customers to process credit card payments. Within 10 minutes, the support ticket queue flooded with reports of failed transactions, frozen checkout flows, and merchants unable to access their earnings data. By the time Mia and her two teammates traced the root cause to a newly deployed third-party jQuery payment plugin that had overwritten a global `apiKey` variable used by the core transaction module, $180,000 in pending payments had stalled, and 37 merchants had already posted negative reviews on the company’s public forum.
That 3 a.m. firefight was not an isolated incident. For frontend teams in the early 2010s, global variable collisions, dependency ordering bugs, and unmaintainable script tag soup were not just annoyances—they were existential risks that could cost startups their entire user base and revenue streams in a single bad deploy. The 90,000-line jQuery monolith Mia’s team was struggling with was not an outlier: a 2012 survey of 1,200 frontend developers by the now-defunct JavaScript weekly publication *JS Hotline* found that 72% of teams were maintaining codebases larger than 50,000 lines of vanilla JavaScript or jQuery, with 41% reporting at least one production incident per month caused by global namespace conflicts or dependency ordering errors. The problem was not a lack of skill or care: it was that the fundamental tools of frontend development—the `<script>` tag, the global `window` object, and the absence of a standardized module system—had not evolved to match the skyrocketing complexity of web applications.
The Era of Script Tags: Order, Dependencies, and the `$ is not defined` Nightmare
To understand the urgency of the modularity crisis of the early 2010s, we have to rewind to the earliest days of JavaScript. When Brendan Eich invented the language in 10 days in 1995 for Netscape Navigator 2.0, it was designed as a tiny scripting glue for simple, static web pages. The core use case was adding hover effects to buttons or validating form inputs before submission—tasks that required at most a few hundred lines of code per page. The `<script>` tag, which allowed developers to embed or link external JavaScript files, was more than sufficient for this use case, with one critical caveat: execution order was entirely dependent on the order the tags appeared in the HTML.
For a simple page with three external scripts—jQuery, a datepicker plugin, and a custom script to initialize the datepicker—the required order was obvious and easy to maintain: ```html <!-- 1998年典型的中小网站页面结构 --> <!DOCTYPE html> <html> <head> <title>Small Business Dashboard</title> <!-- 依赖必须先加载,否则会报错 --> <script src="/static/js/libs/jquery-1.7.2.min.js"></script> <script src="/static/js/libs/jquery-ui-1.8.20.min.js"></script> <script src="/static/js/plugins/datepicker-init.js"></script> </head> <body> <div id="dashboard"> <input type="text" id="date-field" /> </div> <script src="/static/js/main.js"></script> </body> </html> ``` If a developer accidentally swapped the order of the jQuery and datepicker-init scripts, the browser would throw a `ReferenceError: $ is not defined` the moment `datepicker-init.js` tried to access the jQuery global. For small teams and small codebases, this was a trivial bug to catch in testing, and the fix was as simple as dragging and dropping script tags in an HTML file.
But as web applications grew in complexity in the late 2000s and early 2010s, this model broke down catastrophically. The rise of single-page applications (SPAs), popularized by Gmail in 2004 and later adopted by thousands of startups building complex dashboard and e-commerce products, meant that a single page could now include dozens or even hundreds of external JavaScript files. A typical 2012 fintech dashboard might include jQuery, jQuery UI, a charting library, a form validation library, a payment processing SDK, an analytics library, a custom authentication module, a transaction history module, a reporting module, and dozens of smaller utility scripts—all of which had to be loaded in the exact correct order to avoid errors.
For Mia’s team, this meant that their `index.html` file contained 47 `<script>` tags, each with a manually assigned order number in the filename (e.g., `01.jquery.js`, `02.jquery-ui.js`, `03.auth.js`, etc.) to enforce load order. If a new developer added a script that depended on the authentication module but forgot to number it correctly, the entire application would break for all users. The team kept a 12-page printed document in the office kitchen that listed the correct load order for every script, updated weekly—a document that was out of date more often than not.
The second, even more insidious problem with the script tag model was global namespace pollution. In JavaScript, any variable declared outside of a function is attached to the global `window` object, making it accessible to every other script on the page. For small codebases, this was a minor inconvenience: two scripts might accidentally use the same variable name like `currentUser` or `isLoading`, leading to hard-to-debug conflicts. For large codebases like Mia’s 90,000-line monolith, it was a guaranteed disaster.
> Sidebar: The Cost of Global Scope Collisions > A 2013 study of production frontend incidents across 50 enterprise teams found that 28% of all critical frontend bugs were caused by global namespace pollution, with a median time to resolution of 4.2 hours—compared to 1.1 hours for bugs caused by syntax errors or API failures. For fintech and e-commerce teams, the average cost of a single global scope collision incident was $42,000 in lost revenue and engineering time, per data from the startup analytics firm ChartMogul.
The problem was exacerbated by the ecosystem of third-party jQuery plugins that dominated frontend development in the early 2010s. The jQuery Plugin Registry listed more than 10,000 plugins by 2012, most of which followed the standard pattern of attaching new functionality directly to the jQuery prototype (`$.fn`) or the global `window` object. Two of the most popular plugins for form handling, for example, both used the name `serializeJSON` for their core function: one attached it to `$.fn.serializeJSON` for use as a jQuery method, the other attached it to `window.serializeJSON` as a standalone utility. If both plugins were loaded on the same page, the second one loaded would overwrite the first, breaking any code that relied on the overwritten function. For Mia’s team, this exact conflict had caused a three-hour outage six months prior, when a new analytics plugin overwrote the global `sendEvent` function used by the core transaction module to track payment completions.
By 2010, it was clear to most senior frontend engineers that the script tag and global scope model was no longer sustainable for large applications. What was needed was a way to encapsulate code into isolated, reusable units that could declare their own dependencies without relying on manual load order or global variables. The industry’s response was a three-way war over module specification standards that would dominate frontend development discourse for the next four years.
The Module Specification Wars: AMD vs CMD vs CommonJS
The first salvo in the module war was fired in 2009, when James Burke, a developer at the Mozilla Foundation, released RequireJS and its accompanying Asynchronous Module Definition (AMD) specification. AMD was designed explicitly for browser environments, where