JavaScript's Dark Ages
How We Lost Our Way (2010-2020)
Full disclosure: This post was written by a human (me), polished by an AI (it fixed my grammar and made me sound smarter), then reviewed by me again (to make sure the AI didn't make me sound too smart). Any remaining errors are 100% organic, artisanal, human-made mistakes.
DHH called it the "dark ages" of JavaScript—the decade where web development went from simple and accessible to byzantine and exhausting. A period where setting up a build system took longer than building features, and where the average project'snode_modules folder could hold more files than the entire Windows 95 operating system.
The Descent into Complexity
Remember when web development was simple? You wrote HTML. You added some CSS. Maybe a sprinkle of jQuery. You uploaded files via FTP. Done. Users saw your changes instantly.
Then, around 2010, something shifted. JavaScript "grew up" and decided simplicity was for amateurs. The industry embraced a cascade of complexity:
Each tool solved a real problem. But together, they created a monster. A simple "Hello World" required downloading hundreds of megabytes of dependencies.
The Symptoms of the Dark Ages
"npm install" Became a Full-Time Job
DHH highlighted this absurdity: you'd start a new project, run npm install, and watch thousands of packages download. Each with its own dependencies. Each with potential security vulnerabilities. Each with breaking changes lurking in future updates.
"Looking at a node_modules folder and trying to understand what's actually in there—it's like archaeology. You have no idea what civilization built these ruins or why."
Framework Churn Burned Everyone Out
Learn Angular? It's obsolete—Angular 2 is completely different. Learn React class components? Hooks are the new way. Master Webpack 3? Time for Webpack 4, with a totally new configuration format.
Developers spent more time keeping up with tooling than building products. The knowledge half-life collapsed. What you learned last year was already outdated.
The Build Step Became Mandatory
Remember refreshing the browser and seeing changes? Now you needed a dev server, hot module replacement, and a Webpack configuration file that looked like tax code. The feedback loop that made web development accessible stretched from seconds to minutes.
// A "simple" webpack.config.js circa 2018
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader'],
},
// ... 100 more lines of configuration
],
},
plugins: [
new HtmlWebpackPlugin({ template: './src/index.html' }),
new MiniCssExtractPlugin(),
// ... more plugins
],
optimization: {
splitChunks: { chunks: 'all' },
},
devServer: {
hot: true,
port: 3000,
},
};Why Did This Happen?
DHH offered a compelling explanation: Facebook's organizational complexity leaked into their tools.
"When you have 15 specialized roles touching a single feature—a frontend engineer, a JavaScript specialist, a CSS expert, a designer, a PM, a data engineer—you need tooling that mediates between them. But most teams aren't Facebook. They don't have 15 specialists. They have 3 generalists."
— DHH on Lex Fridman Podcast
The industry imported Facebook's solutions for Facebook's problems. React solved real challenges at Facebook's scale. GraphQL made sense for Facebook's data complexity. But a startup with 5 engineers building a CRUD app? They didn't need any of it.
Yet the tools became "best practices." If you weren't using them, you weren't serious. Never mind that they added months to development timelines and required constant maintenance.
The Dawn After the Dark Ages
Around 2020, something shifted. Browser capabilities improved dramatically:
- ES Modules in browsers: No more bundlers required for basic projects
- HTTP/2: Multiple small files became efficient
- CSS improvements: Variables, Grid, Flexbox—no preprocessors needed
- Modern JavaScript: async/await, optional chaining, nullish coalescing
Suddenly, the preprocessing that defined the dark ages became... optional. You could write modern JavaScript, modern CSS, and ship it directly to browsers. Import maps let you manage dependencies without bundlers.
DHH and the Rails team embraced this with Rails 8's "no build" philosophy. The default Rails setup now works without any JavaScript preprocessing. You can still add it if you need it—but you don't have to.
Lessons from the Dark Ages
1. Complexity Has Compound Costs
Each tool added seems cheap—just one more dependency. But dependencies compound. They interact, conflict, and require updates. A hundred simple tools create exponential complexity.
2. "Best Practices" Often Aren't
What works for Facebook doesn't work for your 5-person startup. Question every "you should use X" with "why, specifically, for my situation?"
3. Simplicity Requires Courage
Saying "we don't need React" in 2017 took courage. The industry consensus was overwhelming. But the teams that resisted often shipped faster and with less pain.
4. The Platform Usually Catches Up
Browsers today can do what required complex tooling in 2015. Before adding dependencies, ask: "Will the platform support this natively soon?"
The Path Forward
We're not fully out of the dark ages. Many projects still carry the legacy of decade-old architectural decisions. But the escape path is clear: question every dependency, embrace browser capabilities, and remember that "npm install" should be a last resort, not a first instinct.
The developers who learned during the dark ages carry scars—and wisdom. They know the cost of complexity intimately. They're often the ones pushing hardest for simplicity now.
The best JavaScript is often no JavaScript at all.
And when you do need JavaScript, the best tooling is often the tooling you don't need to configure. The dark ages taught us that simplicity isn't primitive—it's sophisticated. It's the hardest thing to achieve.
Related Articles
Rails 8's 'No Build' Philosophy: Back to the Future
Why the '90s deployment model (FTP, instant updates) was actually ideal. How browser improvements finally enabled ditching build tools, and what import maps mean for the future of web development.
The Pieter Levels Model: One Developer, Simple Tools, Millions in Revenue
PHP, jQuery, SQLite powering million-dollar businesses. Why 'boring' technology wins, and what solo developer success stories teach us about the myth that you need modern frameworks to build real products.
The Complexity Industrial Complex: Who Profits From Overengineering?
Why consultants and tool vendors love complicated architectures. The career incentives that promote unnecessary complexity, how to resist the pressure to overcomplicate, and simplicity as a competitive advantage.