Web Development (Advanced) — Node.js, React, Vue, Build Tools, UI Frameworks
The basic post covered HTML, CSS, vanilla JS, jQuery. Modern web development sits on top of that base: Node.js as a JS runtime everywhere, package managers to wire dependencies, bundlers (Vite, esbuild, webpack) to produce production assets, component frameworks (React, Vue, Svelte) to manage state + UI, CSS frameworks (Tailwind, Bootstrap) to keep styles consistent, icon sets (Font Awesome, Lucide) for visuals, and a deployment story for shipping the result. This post is a survey of the stack and the trade-offs. (3D / WebGL / Three.js has its own dedicated series — see the link at the end.)
Learning Outcome
- Install and use Node.js + npm / pnpm / yarn.
- Initialise a project with Vite, understand the dev server + build output.
- Read and write a React or Vue component with state, props, events.
- Pick between React, Vue, Svelte for a new project.
- Use a CSS framework (Tailwind / Bootstrap) effectively.
- Add icons with Font Awesome or Lucide.
- Call REST / GraphQL APIs from the browser.
- Deploy a static site (Vercel / Netlify / Cloudflare Pages / S3+CloudFront).
Chapter 1 — Node.js as a JS runtime
Node.js is V8 (Chrome's JS engine) outside the browser. It powers:
- Build tools (Vite, webpack, esbuild, Rollup).
- Local dev servers.
- The package manager (npm).
- Many backend frameworks (Express, Fastify, NestJS, Next.js API routes).
- Build pipelines in CI.
Install via nodejs.org (LTS) or nvm (manage multiple versions). Verify:
1
2
3
node --version # v20+ in 2026
npm --version
Run a script:
1
2
node app.js
REPL: node opens an interactive prompt similar to Python's.
Chapter 2 — Package managers
Three contenders today:
| Tool | Speed | Disk | Notes |
|---|---|---|---|
| npm | OK | duplicates per-project | ships with Node |
| pnpm | fastest | content-addressed store, hard-linked | modern default for many teams |
| yarn (Berry) | fast | Plug'n'Play option | corporate use, monorepos |
Pick one per project and stick with it. The lockfile (package-lock.json / pnpm-lock.yaml / yarn.lock) is committed.
Common commands (npm flavour)
1
2
3
4
5
6
7
8
npm init -y # create package.json
npm install react # add dependency
npm install -D vite # add devDependency
npm install # restore from lockfile (after clone)
npm run dev # run a script defined in package.json
npm uninstall pkg
npx some-cli # run a CLI without installing globally
A typical package.json:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"name": "my-app",
"version": "0.1.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint src",
"format": "prettier --write ."
},
"dependencies": {
"react": "^18.3.0",
"react-dom": "^18.3.0"
},
"devDependencies": {
"vite": "^5.0.0",
"@vitejs/plugin-react": "^4.0.0",
"eslint": "^8.0.0",
"prettier": "^3.0.0"
}
}
Chapter 3 — Build tools (Vite + ESM)
Old days: webpack + Babel + a 200-line config; cold start 30 sec, HMR 2-5 sec. Modern: Vite uses native ES modules in dev (zero bundling) and esbuild / Rollup for production builds. Cold start < 500 ms, HMR < 100 ms.
1
2
3
4
5
6
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run dev # opens http://localhost:5173
npm run build # outputs to dist/
Templates: vanilla, vanilla-ts, react, react-ts, vue, vue-ts, svelte, svelte-ts, solid, lit, preact, qwik. TypeScript is the default in modern teams.
Why ESM matters
1
2
<script type="module" src="/src/main.js"></script>
The browser fetches each import-ed module separately. Dev servers serve them un-bundled — only re-process the file you changed. Production builds still bundle (fewer requests, tree-shaking).
Chapter 4 — React vs Vue vs Svelte
The three live framework families. Brief comparison:
| React | Vue | Svelte | |
|---|---|---|---|
| Released | 2013 | 2014 | 2016 |
| Maintainer | Meta | core team | core team |
| Component file | .jsx / .tsx |
.vue (HTML+JS+CSS in one) |
.svelte |
| State | hooks (useState, useReducer) |
reactivity (ref, reactive) |
language-level (let x = 0) |
| Templating | JSX (JS-like) | HTML template + directives | HTML + minimal directives |
| Bundle size baseline | ~45 KB gzipped | ~30 KB | ~5 KB (compiles away) |
| Job market | dominant | strong, especially APAC | growing |
| Best for | huge ecosystem, hiring | balance of approachability + power | smallest output, first-time learners |
There is no universally best. React if hiring + ecosystem matters most. Vue for a balanced learning curve. Svelte for performance + simplicity at small-to-medium scale.
Chapter 5 — React essentials
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// src/App.tsx
import { useState } from 'react';
export default function App() {
const [count, setCount] = useState(0);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(c => c + 1)}>+1</button>
<ChildList items={['a', 'b', 'c']} />
</div>
);
}
function ChildList({ items }: { items: string[] }) {
return (
<ul>
{items.map((x, i) => <li key={i}>{x}</li>)}
</ul>
);
}
Rules of thumb:
- JSX — HTML-like syntax that compiles to
React.createElement(...). useStatefor local state.useEffectfor side effects (data fetching, subscriptions).- Props are read-only inputs from parent.
- Always give array children a stable
keyprop. - Component names are PascalCase.
Fetching data
1
2
3
4
5
6
7
8
9
10
import { useEffect, useState } from 'react';
export default function Users() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('/api/users').then(r => r.json()).then(setUsers);
}, []); // empty deps → run once on mount
return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}
For real apps, use TanStack Query (@tanstack/react-query) or SWR instead of hand-rolling effects.
Routing
React itself does not include routing. Add React Router (react-router-dom) for SPA routes, or use Next.js / Remix for a more opinionated framework with file-based routing + server rendering.
Chapter 6 — Vue essentials (composition API)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- App.vue -->
<script setup>
import { ref } from 'vue';
const count = ref(0);
const inc = () => count.value++;
</script>
<template>
<h1>Count: {{ count }}</h1>
<button @click="inc">+1</button>
</template>
<style scoped>
h1 { color: navy; }
</style>
Single-file components bundle template + logic + styles. ref wraps a value; access with .value in JS, unwrapped automatically in templates.
Routing: vue-router. State: pinia. Full-stack framework: Nuxt.
Chapter 7 — CSS frameworks
| Approach | Example | When |
|---|---|---|
| Utility classes | Tailwind, UnoCSS | rapid prototyping, design systems, modern teams |
| Component CSS | Bootstrap, Bulma | quick admin/dashboard, less custom design |
| CSS-in-JS | styled-components, Emotion | React apps with dynamic styling |
| CSS Modules | (built into Vite) | scoped styles per component, no framework |
| Hand-written | nothing | full control, small projects, design-led |
Tailwind (the modern default)
1
2
3
4
5
6
7
8
<div class="flex items-center gap-4 p-4 bg-white rounded-xl shadow">
<img src="..." class="h-12 w-12 rounded-full">
<div>
<p class="font-semibold">Ada Lovelace</p>
<p class="text-sm text-gray-500">Mathematician</p>
</div>
</div>
Install:
1
2
3
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Configure content: ["./index.html", "./src/**/*.{js,jsx,ts,tsx,vue}"] in tailwind.config.js and include @tailwind base; @tailwind components; @tailwind utilities; in your CSS entry.
Bootstrap (still widely used)
1
2
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3/dist/css/bootstrap.min.css" rel="stylesheet">
1
2
3
4
5
6
7
8
<button class="btn btn-primary">Click</button>
<div class="container">
<div class="row">
<div class="col-md-6">Left</div>
<div class="col-md-6">Right</div>
</div>
</div>
Heavier visual opinion, faster to assemble admin dashboards. Pair with the JS plugins (modals, dropdowns, tooltips).
Trick: mixing Tailwind + Bootstrap in the same project usually fights — both impose layout opinions. Pick one. For new projects, Tailwind almost always wins; for legacy + content-heavy, Bootstrap can still shine.
Chapter 8 — Icons
| Library | Bundle | Use |
|---|---|---|
| Font Awesome | huge if loaded all; tree-shake-friendly via React/Vue packages | mainstream brand-icons + many UI icons |
| Lucide (fork of Feather) | small, MIT, modern | most React/Vue teams default in 2026 |
| Heroicons | from Tailwind team | pairs with Tailwind nicely |
| Material Symbols | Android / Material Design feel | |
| Tabler Icons | huge free set | open-source designers' favourite |
React usage (Lucide):
1
2
3
4
import { Search, Settings } from 'lucide-react';
<button><Search size={16} /> Search</button>
Avoid loading the whole Font Awesome CSS bundle in 2026 — too heavy. Use the per-icon import pattern for any library.
Chapter 9 — APIs: REST + GraphQL
REST
1
2
3
4
5
6
7
8
9
10
11
12
13
// GET
const r = await fetch('/api/users');
const users = await r.json();
// POST
const r2 = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify({ name: 'Ada' }),
});
if (!r2.ok) throw new Error(`HTTP ${r2.status}`);
const created = await r2.json();
GraphQL
Single endpoint, client picks fields:
1
2
3
4
5
6
7
8
9
10
11
12
const query = `
query {
user(id: 1) { id name email posts { title } }
}
`;
const r = await fetch('/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query }),
});
const { data } = await r.json();
Tools: Apollo Client (React/Vue), urql, graphql-request.
Data-fetching libraries (the time-saver)
Hand-rolling fetch + loading + error state in every component is repetitive. Use:
- TanStack Query (
@tanstack/react-query,@tanstack/vue-query) - SWR (React)
- Pinia Colada (Vue)
They handle caching, deduplication, retries, background refresh, pagination, and devtools. Standard in modern apps.
Chapter 10 — TypeScript (briefly)
JavaScript with optional static types. Catches whole classes of bugs at compile time + improves IDE autocomplete.
1
2
3
4
5
6
type User = { id: number; name: string; email: string };
function greet(u: User): string {
return `Hello, ${u.name}`;
}
Vite templates ship with TS preconfigured. Use TS for any project bigger than a one-page demo — the productivity payoff comes quickly.
Chapter 11 — Deployment
| Target | Tool | Best for |
|---|---|---|
| Static hosting | Vercel, Netlify, Cloudflare Pages, GitHub Pages | SPAs, marketing sites, docs |
| S3 + CloudFront | AWS | full control, fits a wider AWS stack |
| Full-stack edge | Vercel (Next.js), Cloudflare Workers, Deno Deploy | SSR + APIs + edge |
| Containers | Fly.io, Render, AWS ECS/Fargate | Node.js servers, WebSockets, background jobs |
| VPS | DigitalOcean, Hetzner, Linode | hand-rolled, cheap |
A typical Vite build → static deploy:
1
2
3
4
5
npm run build # outputs dist/
# Vercel: just `vercel deploy` or git-push integration
# Netlify: drag-and-drop dist/ in the dashboard, or `netlify deploy --prod`
# Cloudflare Pages: connect GitHub repo
For React/Vue SPAs that need a backend, the easiest stack in 2026 is Next.js on Vercel or Nuxt on Vercel/Cloudflare — they unify frontend + serverless backend + edge functions in one deployment.
Chapter 12 — Performance baseline
Hit these targets in Lighthouse for a polished site:
| Metric | Target |
|---|---|
| LCP (Largest Contentful Paint) | < 2.5 s |
| INP (Interaction to Next Paint) | < 200 ms |
| CLS (Cumulative Layout Shift) | < 0.1 |
| First-load JS (uncompressed) | < 200 KB |
| Image format | AVIF / WebP, not PNG/JPG raw |
| Fonts | font-display: swap, subset, self-host |
Tools: Lighthouse (in DevTools), PageSpeed Insights, WebPageTest.
Common wins:
- Lazy-load below-the-fold images (
loading="lazy"). - Code-split routes (
React.lazy, dynamicimport()). - Compress images (use a build-time tool —
@astrojs/image,sharp). - Preload the hero font.
- Remove unused JS (the bundle analyzer flags it).
Practice Exercises
Exercise 1 — Vite + React/Vue starter
npm create vite@latest. Build a single-page counter app. Push to GitHub. Deploy to Vercel.
Exercise 2 — TanStack Query
Fetch https://jsonplaceholder.typicode.com/users with TanStack Query. Render the list with loading + error states. Add a refresh button.
Exercise 3 — Tailwind UI
Build a 3-card pricing layout with Tailwind. Responsive: stacked on mobile, 3 columns on desktop. Use Lucide icons in the feature lists.
Exercise 4 — Full mini-app
A note-taking app: list + create + delete + edit. State via React Context or Pinia. Data fetched via TanStack Query against a mock JSON server (json-server). TypeScript. Tailwind. Deploy to Vercel.
Cheat-sheet
| What | How |
|---|---|
| Init project | npm create vite@latest |
| Add dep | npm install pkg |
| Add dev dep | npm install -D pkg |
| Run script | npm run dev |
| React state | const [x, setX] = useState(0) |
| React effect | useEffect(() => { ... }, [deps]) |
| Vue state | const x = ref(0) |
| Vue effect | watchEffect(() => { ... }) |
| Routing (React) | react-router-dom / Next.js |
| Routing (Vue) | vue-router / Nuxt |
| Data fetching | TanStack Query / SWR |
| Style toolkit | Tailwind (modern) / Bootstrap (legacy) |
| Icon | Lucide / Heroicons / Font Awesome |
| Types | TypeScript everywhere |
| Deploy static | Vercel / Netlify / Cloudflare Pages |
| Deploy full-stack | Next.js on Vercel |
| Audit perf | Lighthouse / PageSpeed Insights |
Where to next
For 3D, WebGL, WebGPU, Three.js, React Three Fiber, shaders, instancing, physics, AI-assisted 3D and the rest — see the dedicated Three.js series (posts threejs_00 through threejs_13). That topic deserved its own multi-post arc rather than a single chapter.
Other areas that warrant their own deep-dive posts in future:
- Next.js / Nuxt — full-stack frameworks built on React / Vue with file-based routing, server components, edge.
- State management — Zustand, Jotai, Redux Toolkit (React); Pinia (Vue).
- Testing — Vitest + Testing Library, Playwright for E2E.
- Animations — Framer Motion (React), GSAP, View Transitions API.
- PWA — service workers, offline, install-to-home-screen.
- WebSockets / real-time — Socket.IO, native WebSocket, SSE.
- Web Components / Lit — framework-agnostic components.
- Astro / Qwik — modern islands / resumability frameworks for content sites.
References
- MDN Web Docs
- React docs
- Vue docs
- Svelte docs
- Vite docs
- Tailwind docs
- TanStack Query
- web.dev — Google's modern web practices.
Note: this post is in progress. Planned additions: Next.js full walkthrough, Server Components explained, deep dive on Web Animations API. (WebGPU + Three.js is covered in the separate Three.js series.)









