Most developers learn JavaScript piece by piece — first in the browser, then frameworks, then something like React or Node, but rarely do they step back and understand the whole ecosystem and how all the parts fit together.
This article walks from the very beginning — what JavaScript really is — to modern concepts like React Server-Side Rendering (SSR), in a clear, logical progression.
1️⃣ What Is JavaScript Really?
JavaScript is a programming language, just like Python, Go, or C#. But unlike many languages, JavaScript was originally designed to run inside the browser to make web pages interactive.
Example (browser JavaScript):
document.querySelector("button").onclick = () => alert("Clicked!");
JavaScript the language does not define:
documentwindow- DOM manipulation
- networking
- file access
Those features come from the browser environment, not from JavaScript itself.
2️⃣ Who Controls JavaScript?
The JavaScript language standard is maintained by:
TC39, part of ECMA International.
It includes representatives from:
- Google (V8)
- Apple (JavaScriptCore)
- Mozilla (SpiderMonkey)
- Microsoft
- Meta, Shopify, and others
TC39 defines language features like:
async/await- optional chaining (
?.) - classes
- generators
- array methods (
flat,at,findLast)
Once approved, JavaScript engines implement them.
3️⃣ JavaScript Engines
A JavaScript engine is a program that executes JavaScript code.
Examples:
| Engine | Used In |
|---|---|
| V8 | Chrome, Node.js, Deno |
| JavaScriptCore | Safari, Bun |
| SpiderMonkey | Firefox |
The engine parses, optimizes, and executes code — but it doesn’t provide APIs like fs, window, or fetch.
Those come from the runtime.
4️⃣ JavaScript in the Browser
In the browser, JavaScript runs alongside:
- HTML (structure)
- CSS (appearance)
- DOM APIs (interaction)
Example:
<input id="name">
<script>
document.getElementById("name")
.addEventListener("input", e => {
console.log("User typed:", e.target.value);
});
</script>
Browser JavaScript can:
✔ Update UI ✔ Handle input ✔ Fetch remote data
But cannot:
❌ access the local filesystem ❌ open random network ports ❌ directly access hardware
Browsers intentionally sandbox JavaScript for security.
5️⃣ JavaScript on the Server (Node.js, Bun, Deno)
In 2009, Node.js introduced the idea of running JavaScript outside the browser using Google’s V8 engine.
Example (Node):
import http from "http";
http.createServer((req, res) => {
res.end("Hello from Node");
}).listen(3000);
Example (Bun):
Bun.serve({
port: 3000,
fetch() {
return new Response("Hello from Bun");
}
});
Server JavaScript can:
✔ read/write files ✔ process requests ✔ connect to databases ✔ send emails ✔ run scheduled tasks
Here, JavaScript behaves like Python, PHP, or Go.
6️⃣ Browser vs Server: Same Language, Different Powers
| Feature | Browser | Node / Bun |
|---|---|---|
DOM (document) |
✔ Yes | ❌ No |
| File system access | ❌ No | ✔ Yes |
| Can render UI | ✔ Yes | ❌ No |
| Can run a server | ❌ No | ✔ Yes |
The syntax is the same, but the capabilities differ depending on the runtime environment.
7️⃣ How JavaScript Produces a Web Page
Whenever you visit a site, this happens:
Browser → sends request to server
Server → sends HTML, CSS, JS files
Browser → renders HTML and applies CSS
Browser → executes JavaScript
JavaScript may then:
- fetch more data
- update the page
- respond to user actions
8️⃣ What Is React?
React is a JavaScript library created to manage UI and state efficiently.
Before React, updating the DOM manually was complex and error-prone.
React lets developers write UI declaratively:
<button onClick={() => setCount(count + 1)}>
{count}
</button>
React decides how to update the browser’s DOM intelligently.
9️⃣ JSX Is Not JavaScript
JSX looks like HTML inside JavaScript:
<h1>Hello</h1>
But browsers cannot execute JSX directly. JSX must be compiled into:
React.createElement("h1", null, "Hello");
Without a bundler, we must write the React.createElement version manually.
🔟 React SSR (Server-Side Rendering)
React can run on the server to generate HTML before the browser loads the JavaScript.
Example:
import { renderToString } from "react-dom/server";
renderToString(<App />);
This produces:
<h1>Hello</h1>
Benefits:
- Faster first render
- SEO-friendly output
- Better perceived performance
1️⃣1️⃣ Hydration: Making Server-Rendered HTML Interactive
Once the browser receives HTML, React JavaScript loads and hydrates it:
ReactDOM.hydrate(<App />, document.getElementById("root"));
Hydration attaches event listeners and turns the static HTML into a fully interactive React app.
For hydration to work, the server and browser must generate the same markup.
1️⃣2️⃣ Why Sometimes We Don’t Import React
If React is loaded via a CDN script tag:
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
React becomes a global variable (window.React), so imports aren’t necessary.
With ES modules and bundlers, we must import React explicitly:
import React from "react";
🔥 Practical Examples
Below are three runnable examples showing how rendering works differently depending on the environment.
Example 1 — Browser-Only Rendering (CSR)
<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script>
function App() {
return React.createElement("h1", null, "Rendered in Browser");
}
ReactDOM.createRoot(document.getElementById("root"))
.render(React.createElement(App));
</script>
The browser receives empty HTML and React builds the UI.
Example 2 — SSR with Node.js
server.js
import express from "express";
import React from "react";
import ReactDOMServer from "react-dom/server";
function App({ name }) {
return React.createElement("h1", null, `Hello, ${name}`);
}
const app = express();
app.use(express.static("public"));
app.get("/", (req, res) => {
const html = ReactDOMServer.renderToString(React.createElement(App, { name: "Node.js" }));
res.send(`
<html>
<body>
<div id="root">${html}</div>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="/client.js"></script>
</body>
</html>
`);
});
app.listen(3000);
public/client.js
function App({ name }) {
return React.createElement("h1", null, `Hello, ${name}`);
}
ReactDOM.hydrate(
React.createElement(App, { name: "Node.js" }),
document.getElementById("root")
);
Example 3 — SSR with Bun
server.js
import React from "react";
import ReactDOMServer from "react-dom/server";
function App({ name }) {
return React.createElement("h1", null, `Hello, ${name}`);
}
Bun.serve({
port: 3000,
fetch(req) {
if (new URL(req.url).pathname === "/client.js") {
return new Response(Bun.file("public/client.js"));
}
const html = ReactDOMServer.renderToString(React.createElement(App, { name: "Bun" }));
return new Response(`
<html>
<body>
<div id="root">${html}</div>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="/client.js"></script>
</body>
</html>
`, { headers: { "Content-Type": "text/html" } });
}
});
console.log("SSR App running at http://localhost:3000");
public/client.js
function App({ name }) {
return React.createElement("h1", null, `Hello, ${name}`);
}
ReactDOM.hydrate(
React.createElement(App, { name: "Bun" }),
document.getElementById("root")
);