Ever wonder what really happens behind the scenes when you hit Enter in the address bar and your Single Page Application magically appears?
Let's pull back the curtain and walk through it step by step, from how the browser chews up your HTML to how your JavaScript bundle brings everything to life. I'm keeping it a bit high level for easier understanding.
1️⃣ The Browser Grabs Your HTML
When you type in a URL and hit Enter:
- The browser fires off an HTTP request to your server.
- The server responds with your main
index.html
file.
Usually, this file is pretty minimal, something like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My SPA</title>
<link rel="stylesheet" href="/styles.css" />
</head>
<body>
<div id="root"></div>
<script src="/bundle.js"></script>
</body>
</html>
2️⃣ HTML Parsing & DOM Building
The browser doesn't wait around—it starts parsing the HTML as soon as it starts receiving it:
- The HTML parser reads the markup and turns it into tokens.
- Those tokens get stitched together into the DOM tree.
- For example,
<div id="root"></div>
becomes a node in memory. - If it hits
<script>
tags without defer or async, parsing pauses while that script runs.
At this point:
✅ The DOM is taking shape
✅ No styles are applied yet
✅ No JavaScript has run
3️⃣ CSSOM: Making Things Pretty
When the parser comes across your <link rel="stylesheet">
tags:
- The browser fetches the CSS files.
- It parses them into the CSS Object Model (CSSOM).
- Your app won't render anything until both DOM and CSSOM are ready.
4️⃣ Building the Render Tree & Painting
Once both the DOM and CSSOM are good to go:
- The browser combines them into a Render Tree, which figures out what should be visible on the page.
- It calculates layout.
- Then it paints pixels to the screen.
5️⃣ Your JavaScript Bundle Arrives
The bundle is downloaded via <script src="/bundle.js">
. If it's defer, it waits until parsing finishes. Then the JavaScript starts running.
6️⃣ Webpack Bootstraps Your App
When the browser loads your JavaScript bundle:
Webpack's runtime kicks in—a small piece of code that knows how to load and execute your modules.
All modules are wrapped as functions and stored in an object (
{ id: fn }
).-
It uses a
__webpack_require__
function to:- Load the entry module (like
index.js
) - Resolve its dependencies recursively
- Cache modules so they only run once
- Load the entry module (like
Then it executes the entry module, which usually renders your app.
Think of it as:
- 🧳 Your app code = packed luggage
- 🧠 Webpack runtime = the guy who knows what bag to open and in what order
7️⃣ Initializing Your SPA
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
This mounts the app into the DOM and sets up routing.
8️⃣ Client-Side Routing Takes Over
- Routing happens via JS (history.pushState)
- Views are swapped without a full reload
9️⃣ Hydration (If Using SSR)
- Pre-rendered HTML comes from server
- JS attaches interactivity
🧠 Quick Recap
- Request: Get HTML
- Parse: DOM + CSSOM
- Render: Layout + Paint
- JS: Bundle executes
- App: Mounts and routes
⚡ Why This Matters
- Helps optimize load performance
- Debug layout/paint issues
- Improve time to interactive
🔥 Pro Tip: Use Chrome DevTools to watch this in action
🙌 That's the flow—now you know what's really happening when your SPA boots up.