Key Code Examples
1. HTML5 Semantic Layout
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Portfolio</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<nav class="navbar">
<a href="/" class="logo">DevPortfolio</a>
<ul class="nav-links">
<li><a href="#about">About</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</header>
<main>
<section id="hero" class="hero">
<h1>Full-Stack Web Developer</h1>
<p>Building modern, responsive web applications</p>
<a href="#projects" class="btn btn-primary">View Projects</a>
</section>
<section id="about">
<h2>About Me</h2>
<article class="card">
<h3>Skills</h3>
<ul>
<li>JavaScript (ES6+)</li>
<li>React & Vue</li>
<li>Node.js & Express</li>
<li>Python & Django</li>
</ul>
</article>
</section>
</main>
<footer>
© 2026 DevPortfolio. All rights reserved.</p>
</footer>
</body>
</html>
2. CSS Grid & Flexbox Layout
/* styles.css */
/* CSS Custom Properties (Variables) */
:root {
--primary: #3b82f6;
--secondary: #1e293b;
--accent: #22c55e;
--max-width: 1200px;
--spacing: 1rem;
--radius: 8px;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
/* CSS Reset */
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: system-ui, -apple-system, sans-serif;
line-height: 1.6;
color: var(--secondary);
}
/* Flexbox Navigation */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--spacing) calc(var(--spacing) * 2);
background: white;
box-shadow: var(--shadow);
position: sticky;
top: 0;
z-index: 100;
}
.nav-links {
display: flex;
list-style: none;
gap: calc(var(--spacing) * 2);
}
.nav-links a {
text-decoration: none;
color: var(--secondary);
font-weight: 500;
transition: color 0.3s;
}
.nav-links a:hover { color: var(--primary); }
/* CSS Grid Layout */
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: calc(var(--spacing) * 2);
max-width: var(--max-width);
margin: 0 auto;
padding: calc(var(--spacing) * 2);
}
.card {
background: white;
border-radius: var(--radius);
padding: calc(var(--spacing) * 1.5);
box-shadow: var(--shadow);
transition: transform 0.3s, box-shadow 0.3s;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.15);
}
/* Responsive with Media Queries */
@media (max-width: 768px) {
.navbar { flex-direction: column; }
.nav-links { flex-wrap: wrap; justify-content: center; }
.grid-container { grid-template-columns: 1fr; }
}
/* Animations */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.hero {
animation: fadeIn 0.8s ease-out;
text-align: center;
padding: calc(var(--spacing) * 4) var(--spacing);
}
3. JavaScript โ DOM Manipulation & Events
// app.js โ Modern ES6+ JavaScript
// ===== DOM Selection =====
const navbar = document.querySelector('.navbar');
const navLinks = document.querySelectorAll('.nav-links a');
const themeToggle = document.getElementById('theme-toggle');
const projectCards = document.querySelectorAll('.project-card');
// ===== Event Handling =====
// Smooth scrolling for navigation links
navLinks.forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const targetId = link.getAttribute('href');
const target = document.querySelector(targetId);
target.scrollIntoView({ behavior: 'smooth' });
});
});
// Theme toggle with localStorage persistence
themeToggle.addEventListener('click', () => {
document.body.classList.toggle('dark-mode');
const isDark = document.body.classList.contains('dark-mode');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
});
// Restore saved theme
if (localStorage.getItem('theme') === 'dark') {
document.body.classList.add('dark-mode');
}
// ===== Fetch API โ Load Projects Dynamically =====
async function loadProjects() {
try {
const response = await fetch('/api/projects');
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const projects = await response.json();
const container = document.getElementById('projects-grid');
container.innerHTML = projects.map(project => `
${project.title}
${project.description}
${project.tags.map(tag =>
`${tag} `).join('')}
View Project โ
`).join('');
} catch (error) {
console.error('Failed to load projects:', error);
document.getElementById('projects-grid').innerHTML =
'
Failed to load projects. Please try again.
';
}
}
// ===== Form Handling with Validation =====
const contactForm = document.getElementById('contact-form');
contactForm.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(contactForm);
const data = Object.fromEntries(formData);
// Simple validation
if (!data.email.includes('@')) {
showError('Please enter a valid email address.');
return;
}
try {
const response = await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
const result = await response.json();
showSuccess('Message sent successfully!');
contactForm.reset();
} catch (error) {
showError('Failed to send message. Please try again.');
}
});
loadProjects();
4. React โ Component with Hooks
import React, { useState, useEffect, useCallback } from 'react';
// Custom Hook: useFetch
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
setLoading(true);
fetch(url, { signal: controller.signal })
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.then(data => { setData(data); setLoading(false); })
.catch(err => {
if (err.name !== 'AbortError') {
setError(err.message);
setLoading(false);
}
});
return () => controller.abort();
}, [url]);
return { data, loading, error };
}
// Task Manager Component
function TaskManager() {
const [tasks, setTasks] = useState([]);
const [newTask, setNewTask] = useState('');
const [filter, setFilter] = useState('all'); // all, active, completed
// Load tasks from localStorage
useEffect(() => {
const saved = localStorage.getItem('tasks');
if (saved) setTasks(JSON.parse(saved));
}, []);
// Save tasks to localStorage
useEffect(() => {
localStorage.setItem('tasks', JSON.stringify(tasks));
}, [tasks]);
const addTask = useCallback((e) => {
e.preventDefault();
if (!newTask.trim()) return;
setTasks(prev => [...prev, {
id: Date.now(),
text: newTask.trim(),
completed: false,
createdAt: new Date().toISOString(),
}]);
setNewTask('');
}, [newTask]);
const toggleTask = useCallback((id) => {
setTasks(prev => prev.map(task =>
task.id === id ? { ...task, completed: !task.completed } : task
));
}, []);
const deleteTask = useCallback((id) => {
setTasks(prev => prev.filter(task => task.id !== id));
}, []);
const filteredTasks = tasks.filter(task => {
if (filter === 'active') return !task.completed;
if (filter === 'completed') return task.completed;
return true;
});
return (
{['all', 'active', 'completed'].map(f => (
setFilter(f)}
className={filter === f ? 'active' : ''}>
{f.charAt(0).toUpperCase() + f.slice(1)}
))}
{tasks.filter(t => !t.completed).length} tasks remaining
);
}
export default TaskManager;
5. Node.js/Express โ REST API Server
const express = require('express');
const cors = require('cors');
const rateLimit = require('express-rate-limit');
const { body, validationResult } = require('express-validator');
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(cors());
app.use(express.json({ limit: '10mb' }));
app.use(express.static('public'));
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: { error: 'Too many requests, please try again later.' }
});
app.use('/api/', limiter);
// In-memory "database" (replace with real DB in production)
let products = [
{ id: 1, name: 'Laptop', price: 999.99, category: 'Electronics', stock: 50 },
{ id: 2, name: 'Headphones', price: 149.99, category: 'Electronics', stock: 100 },
{ id: 3, name: 'Desk Chair', price: 299.99, category: 'Furniture', stock: 25 },
];
// ===== Routes =====
// GET all products with filtering, sorting, pagination
app.get('/api/products', (req, res) => {
let result = [...products];
// Filter by category
if (req.query.category) {
result = result.filter(p =>
p.category.toLowerCase() === req.query.category.toLowerCase()
);
}
// Search by name
if (req.query.search) {
const search = req.query.search.toLowerCase();
result = result.filter(p =>
p.name.toLowerCase().includes(search)
);
}
// Sorting
if (req.query.sortBy) {
const order = req.query.order === 'desc' ? -1 : 1;
result.sort((a, b) => (a[req.query.sortBy] - b[req.query.sortBy]) * order);
}
// Pagination
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 10;
const start = (page - 1) * limit;
const paginated = result.slice(start, start + limit);
res.json({
data: paginated,
pagination: {
total: result.length,
page,
pages: Math.ceil(result.length / limit),
}
});
});
// GET single product
app.get('/api/products/:id', (req, res) => {
const product = products.find(p => p.id === parseInt(req.params.id));
if (!product) {
return res.status(404).json({ error: 'Product not found' });
}
res.json(product);
});
// POST create product (with validation)
app.post('/api/products',
body('name').trim().isLength({ min: 2 }).withMessage('Name must be at least 2 characters'),
body('price').isFloat({ min: 0 }).withMessage('Price must be positive'),
body('stock').isInt({ min: 0 }).withMessage('Stock must be non-negative'),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const product = {
id: products.length > 0 ? Math.max(...products.map(p => p.id)) + 1 : 1,
...req.body,
createdAt: new Date().toISOString(),
};
products.push(product);
res.status(201).json(product);
}
);
// PUT update product
app.put('/api/products/:id', (req, res) => {
const index = products.findIndex(p => p.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: 'Product not found' });
}
products[index] = { ...products[index], ...req.body, updatedAt: new Date().toISOString() };
res.json(products[index]);
});
// DELETE product
app.delete('/api/products/:id', (req, res) => {
const index = products.findIndex(p => p.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: 'Product not found' });
}
products.splice(index, 1);
res.status(204).send();
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Internal server error' });
});
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
6. SQL โ Database Schema Design
-- Complete e-commerce schema
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
is_admin BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
slug VARCHAR(100) UNIQUE NOT NULL,
parent_id INTEGER REFERENCES categories(id)
);
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
slug VARCHAR(255) UNIQUE NOT NULL,
description TEXT,
price DECIMAL(10, 2) NOT NULL CHECK (price >= 0),
stock_quantity INTEGER DEFAULT 0,
category_id INTEGER REFERENCES categories(id),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) NOT NULL,
status VARCHAR(20) DEFAULT 'pending'
CHECK (status IN ('pending', 'paid', 'shipped', 'delivered', 'cancelled')),
total_amount DECIMAL(10, 2) NOT NULL,
shipping_address TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE order_items (
id SERIAL PRIMARY KEY,
order_id INTEGER REFERENCES orders(id),
product_id INTEGER REFERENCES products(id),
quantity INTEGER NOT NULL CHECK (quantity > 0),
unit_price DECIMAL(10, 2) NOT NULL
);
-- Indexes for common queries
CREATE INDEX idx_products_category ON products(category_id);
CREATE INDEX idx_products_slug ON products(slug);
CREATE INDEX idx_orders_user ON orders(user_id);
CREATE INDEX idx_orders_status ON orders(status);
CREATE INDEX idx_order_items_order ON order_items(order_id);
-- Full-text search on products
CREATE INDEX idx_products_name_trgm ON products
USING gin (name gin_trgm_ops);
-- Trigger to update updated_at
CREATE OR REPLACE FUNCTION update_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_users_updated
BEFORE UPDATE ON users
FOR EACH ROW EXECUTE FUNCTION update_timestamp();
7. Authentication โ JWT with Refresh Tokens
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const crypto = require('crypto');
const JWT_SECRET = process.env.JWT_SECRET;
const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET;
const ACCESS_TOKEN_EXPIRY = '15m';
const REFRESH_TOKEN_EXPIRY = '7d';
// Hash password
async function hashPassword(password) {
return bcrypt.hash(password, 12);
}
// Verify password
async function verifyPassword(password, hash) {
return bcrypt.compare(password, hash);
}
// Generate access token (short-lived)
function generateAccessToken(user) {
return jwt.sign(
{ userId: user.id, email: user.email, role: user.role },
JWT_SECRET,
{ expiresIn: ACCESS_TOKEN_EXPIRY }
);
}
// Generate refresh token (long-lived, stored in DB)
function generateRefreshToken(user) {
const token = crypto.randomBytes(64).toString('hex');
// Store hashed token in database with user_id and expiry
// await db.refreshTokens.create({
// token: crypto.createHash('sha256').update(token).digest('hex'),
// userId: user.id,
// expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
// });
return token;
}
// Login endpoint
async function login(req, res) {
const { email, password } = req.body;
// Find user
const user = await User.findOne({ where: { email } });
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Verify password
const valid = await verifyPassword(password, user.password_hash);
if (!valid) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Generate tokens
const accessToken = generateAccessToken(user);
const refreshToken = generateRefreshToken(user);
// Set refresh token as HTTP-only cookie
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
});
res.json({ accessToken, user: { id: user.id, email: user.email } });
}
// Middleware to verify access token
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
jwt.verify(token, JWT_SECRET, (err, decoded) => {
if (err) {
return res.status(403).json({ error: 'Invalid or expired token' });
}
req.user = decoded;
next();
});
}
// Token refresh endpoint
async function refresh(req, res) {
const refreshToken = req.cookies.refreshToken;
if (!refreshToken) {
return res.status(401).json({ error: 'Refresh token required' });
}
// Verify refresh token against database
// const stored = await db.refreshTokens.findValid(refreshToken);
// if (!stored) return res.status(403).json({ error: 'Invalid refresh token' });
// Issue new access token
// const user = await User.findById(stored.userId);
// const newAccessToken = generateAccessToken(user);
// res.json({ accessToken: newAccessToken });
}
8. WebSocket โ Real-time Chat
// server.js โ WebSocket chat server
const WebSocket = require('ws');
const http = require('http');
const server = http.createServer();
const wss = new WebSocket.Server({ server });
// Track connected clients
const clients = new Map(); // userId -> ws
wss.on('connection', (ws, req) => {
let userId = null;
ws.on('message', (data) => {
try {
const message = JSON.parse(data);
switch (message.type) {
case 'join':
userId = message.userId;
clients.set(userId, ws);
ws.send(JSON.stringify({
type: 'system',
content: `Welcome, User ${userId}!`,
online: clients.size,
}));
broadcast({
type: 'system',
content: `User ${userId} joined`,
online: clients.size,
}, userId);
break;
case 'chat':
broadcast({
type: 'chat',
userId: userId,
content: message.content,
timestamp: new Date().toISOString(),
});
break;
case 'typing':
broadcast({
type: 'typing',
userId: userId,
isTyping: message.isTyping,
}, userId);
break;
}
} catch (err) {
console.error('Invalid message:', err);
}
});
ws.on('close', () => {
if (userId) {
clients.delete(userId);
broadcast({
type: 'system',
content: `User ${userId} left`,
online: clients.size,
});
}
});
});
function broadcast(message, excludeUserId = null) {
const data = JSON.stringify(message);
clients.forEach((ws, id) => {
if (id !== excludeUserId && ws.readyState === WebSocket.OPEN) {
ws.send(data);
}
});
}
server.listen(3001, () => console.log('WebSocket server on :3001'));
// ===== Client-side =====
const ws = new WebSocket('ws://localhost:3001');
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'join',
userId: 'user-123',
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
switch (msg.type) {
case 'chat':
displayMessage(msg.userId, msg.content);
break;
case 'typing':
showTypingIndicator(msg.userId, msg.isTyping);
break;
case 'system':
displaySystemMessage(msg.content);
updateOnlineCount(msg.online);
break;
}
};
function sendMessage(content) {
ws.send(JSON.stringify({ type: 'chat', content }));
}
9. CSS Animation & Transitions
/* Advanced CSS Animations */
/* Keyframe Animation */
@keyframes slideInLeft {
from { transform: translateX(-100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
@keyframes spin {
to { transform: rotate(360deg); }
}
@keyframes gradient-shift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* Utility Classes */
.animate-slide-in { animation: slideInLeft 0.5s ease-out; }
.animate-pulse { animation: pulse 2s infinite; }
.animate-spin { animation: spin 1s linear infinite; }
/* Gradient Animated Background */
.hero-gradient {
background: linear-gradient(135deg, #667eea, #764ba2, #f093fb);
background-size: 200% 200%;
animation: gradient-shift 8s ease infinite;
}
/* Card Hover Effect with 3D Transform */
.card-3d {
transition: transform 0.3s ease, box-shadow 0.3s ease;
transform-style: preserve-3d;
perspective: 1000px;
}
.card-3d:hover {
transform: translateY(-10px) rotateX(5deg);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
}
/* Loading Spinner */
.spinner {
width: 40px;
height: 40px;
border: 4px solid #e2e8f0;
border-top-color: #3b82f6;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
/* Smooth Page Transition */
.page-enter {
animation: fadeIn 0.3s ease-out;
}
/* Skeleton Loading */
.skeleton {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.5s infinite;
}
@keyframes skeleton-loading {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
/* Staggered List Animation */
.stagger-list > * {
animation: slideInLeft 0.4s ease-out backwards;
}
.stagger-list > *:nth-child(1) { animation-delay: 0.1s; }
.stagger-list > *:nth-child(2) { animation-delay: 0.2s; }
.stagger-list > *:nth-child(3) { animation-delay: 0.3s; }
.stagger-list > *:nth-child(4) { animation-delay: 0.4s; }
10. Performance Optimization Techniques
// ===== Frontend Performance =====
// 1. Lazy Loading Images
const images = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute('data-src');
imageObserver.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));
// 2. Debounce & Throttle
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
function throttle(fn, limit) {
let inThrottle;
return (...args) => {
if (!inThrottle) {
fn(...args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// Usage
window.addEventListener('resize', debounce(() => {
console.log('Window resized');
}, 250));
window.addEventListener('scroll', throttle(() => {
updateScrollPosition();
}, 100));
// 3. Memoization (cache expensive computations)
function memoize(fn) {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
}
const expensiveCalculation = memoize((n) => {
console.log('Computing...');
return n * n + 2 * n + 1;
});
// 4. Virtual Scrolling (render only visible items)
function createVirtualList(container, items, itemHeight) {
const totalHeight = items.length * itemHeight;
const viewport = document.createElement('div');
viewport.style.height = totalHeight + 'px';
viewport.style.position = 'relative';
const visibleCount = Math.ceil(container.clientHeight / itemHeight);
const buffer = 3;
function render() {
const scrollTop = container.scrollTop;
const start = Math.max(0, Math.floor(scrollTop / itemHeight) - buffer);
const end = Math.min(items.length, start + visibleCount + buffer * 2);
viewport.innerHTML = items.slice(start, end).map((item, i) => `
${item}
`).join('');
}
container.addEventListener('scroll', throttle(render, 16));
container.appendChild(viewport);
render();
}
// ===== Backend Performance =====
// Database query optimization
// 1. Use SELECT specific columns, not SELECT *
// 2. Add indexes on frequently queried columns
// 3. Use connection pooling
// 4. Implement caching (Redis)
// Redis caching example
const redis = require('redis');
const client = redis.createClient();
async function getProducts(category) {
const cacheKey = `products:${category}`;
const cached = await client.get(cacheKey);
if (cached) {
return JSON.parse(cached); // Cache hit
}
// Cache miss โ query database
const products = await db.query(
'SELECT id, name, price FROM products WHERE category = ?',
[category]
);
await client.setex(cacheKey, 300, JSON.stringify(products)); // Cache for 5 min
return products;
}
Core Concepts
Client-Server Architecture
Definition: A distributed application structure that partitions tasks between providers (servers) and requesters (clients).
Client: Browser/app that sends HTTP requests and renders UI
Server: Computer that processes requests and returns responses
Request/Response Cycle: Client sends HTTP request โ Server processes โ Server sends HTTP response โ Client renders
Stateless: Each HTTP request is independent; server doesn't remember previous requests (sessions/cookies solve this)
HTTP Protocol & Status Codes
Definition: Hypertext Transfer Protocol โ the foundation of data communication on the web.
Methods: GET (retrieve), POST (create), PUT (update), PATCH (partial update), DELETE (remove)
2xx Success: 200 OK, 201 Created, 204 No Content
3xx Redirection: 301 Moved Permanently, 302 Found, 304 Not Modified
4xx Client Errors: 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 429 Too Many Requests
5xx Server Errors: 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable
Responsive Web Design (RWD)
Definition: An approach that makes web pages render well on a variety of devices and window sizes.
Fluid Grids: Use relative units (%, rem) instead of fixed pixels
Flexible Images: Images scale with containers (max-width: 100%)
Media Queries: Apply different CSS rules for different screen sizes
Mobile-First: Design for mobile first, then enhance for larger screens
Breakpoints: Common: 640px (sm), 768px (md), 1024px (lg), 1280px (xl)
RESTful API Design
Definition: Representational State Transfer โ an architectural style for designing networked applications using HTTP.
Resources: Nouns (/users, /products, /orders) not verbs
HTTP Verbs: GET /users, POST /users, PUT /users/1, DELETE /users/1
Stateless: Each request contains all information needed
HATEOAS: Responses include links to related resources
Versioning: /api/v1/, /api/v2/ to manage changes
Pagination: ?page=1&limit=20 for large datasets
Web Security Fundamentals
XSS (Cross-Site Scripting): Injecting malicious scripts โ prevent with input sanitization and CSP headers
CSRF (Cross-Site Request Forgery): Unauthorized actions โ prevent with tokens and SameSite cookies
SQL Injection: Injecting malicious SQL โ prevent with parameterized queries
CORS: Cross-Origin Resource Sharing โ controls which domains can access your API
HTTPS: Encrypted communication using TLS/SSL certificates
Content Security Policy: Restricts sources for scripts, styles, and other resources
JavaScript Event Loop & Async Programming
Definition: The mechanism that allows JavaScript to perform non-blocking operations despite being single-threaded.
Call Stack: LIFO structure for function execution
Web APIs: Browser-provided APIs (setTimeout, DOM, fetch)
Task Queue: Callback queue for completed async operations
Microtask Queue: Higher priority โ Promises, queueMicrotask
Event Loop: Checks if call stack is empty, then moves tasks from queue to stack
CSS Preprocessors & Modern CSS
Definition: Tools and features that extend CSS with programming capabilities.
Sass/SCSS: Variables, nesting, mixins, functions, partials
Less: Similar to Sass with slightly different syntax
PostCSS: Transform CSS with plugins (autoprefixer, cssnano)
CSS Modules: Scoped CSS to avoid class name conflicts
Tailwind CSS: Utility-first CSS framework
CSS-in-JS: Write CSS inside JavaScript (styled-components, Emotion)
Web Performance Metrics
LCP (Largest Contentful Paint): Main content loaded โ target < 2.5s
FID (First Input Delay): Time to first interaction โ target < 100ms
CLS (Cumulative Layout Shift): Visual stability โ target < 0.1
TTFB (Time to First Byte): Server response time โ target < 600ms
TTI (Time to Interactive): Page fully interactive โ target < 3.8s
Core Web Vitals: Google's key metrics for user experience and SEO ranking
Worked Examples
Example 1: Build a Responsive Navigation Bar
Problem: Create a navigation bar that collapses into a hamburger menu on mobile.
Solution:
<nav class="navbar">
<div class="nav-container">
<a href="#" class="logo">Brand</a>
<button class="hamburger" aria-label="Toggle menu">
<span></span><span></span><span></span>
</button>
<ul class="nav-menu">
<li><a href="#home">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#services">Services</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</div>
</nav>
.nav-container {
display: flex;
justify-content: space-between;
align-items: center;
max-width: 1200px;
margin: 0 auto;
padding: 1rem 2rem;
}
.nav-menu {
display: flex;
list-style: none;
gap: 2rem;
}
.hamburger { display: none; }
@media (max-width: 768px) {
.hamburger { display: block; }
.nav-menu {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
flex-direction: column;
background: white;
padding: 1rem;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.nav-menu.active { display: flex; }
}
document.querySelector('.hamburger').addEventListener('click', () => {
document.querySelector('.nav-menu').classList.toggle('active');
});
Example 2: Implement Debounced Search
Problem: Create a search input that waits for the user to stop typing before making an API call.
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
const searchInput = document.getElementById('search');
const resultsDiv = document.getElementById('results');
const searchAPI = async (query) => {
if (!query) { resultsDiv.innerHTML = ''; return; }
const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
const data = await response.json();
resultsDiv.innerHTML = data.items.map(item =>
`
${item.name}
`
).join('');
};
const debouncedSearch = debounce(searchAPI, 300);
searchInput.addEventListener('input', (e) => {
debouncedSearch(e.target.value);
});
Example 3: CSS-Only Modal Dialog
Problem: Create a modal without JavaScript using only HTML/CSS.
<label for="modal-toggle" class="btn">Open Modal</label>
<input type="checkbox" id="modal-toggle" hidden>
<div class="modal-overlay">
<div class="modal">
<label for="modal-toggle" class="close">ร</label>
<h2>Modal Title</h2>
<p>This modal is pure CSS!</p>
</div>
</div>
.modal-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
justify-content: center;
align-items: center;
z-index: 1000;
}
#modal-toggle:checked ~ .modal-overlay {
display: flex;
}
.modal {
background: white;
padding: 2rem;
border-radius: 8px;
max-width: 500px;
animation: fadeIn 0.3s ease;
}
Example 4: Build a REST API CRUD
Problem: Create a complete CRUD API for a "notes" resource.
// Full CRUD for Notes resource
const express = require('express');
const router = express.Router();
// CREATE
router.post('/', async (req, res) => {
const note = new Note({ title: req.body.title, body: req.body.body });
await note.save();
res.status(201).json(note);
});
// READ all (with pagination)
router.get('/', async (req, res) => {
const { page = 1, limit = 10 } = req.query;
const notes = await Note.find()
.sort({ createdAt: -1 })
.skip((page - 1) * limit)
.limit(parseInt(limit));
const total = await Note.countDocuments();
res.json({ data: notes, total, page: parseInt(page) });
});
// READ one
router.get('/:id', async (req, res) => {
const note = await Note.findById(req.params.id);
if (!note) return res.status(404).json({ error: 'Not found' });
res.json(note);
});
// UPDATE
router.put('/:id', async (req, res) => {
const note = await Note.findByIdAndUpdate(
req.params.id, req.body, { new: true, runValidators: true }
);
if (!note) return res.status(404).json({ error: 'Not found' });
res.json(note);
});
// DELETE
router.delete('/:id', async (req, res) => {
const note = await Note.findByIdAndDelete(req.params.id);
if (!note) return res.status(404).json({ error: 'Not found' });
res.status(204).send();
});
module.exports = router;
Example 5: React Context for State Management
Problem: Implement a simple shopping cart using React Context API.
import { createContext, useContext, useReducer } from 'react';
const CartContext = createContext();
function cartReducer(state, action) {
switch (action.type) {
case 'ADD': {
const existing = state.items.find(i => i.id === action.item.id);
if (existing) {
return { ...state, items: state.items.map(i =>
i.id === action.item.id ? { ...i, qty: i.qty + 1 } : i
)};
}
return { ...state, items: [...state.items, { ...action.item, qty: 1 }] };
}
case 'REMOVE':
return { ...state, items: state.items.filter(i => i.id !== action.id) };
case 'CLEAR':
return { ...state, items: [] };
default:
return state;
}
}
function CartProvider({ children }) {
const [state, dispatch] = useReducer(cartReducer, { items: [] });
const total = state.items.reduce((sum, i) => sum + i.price * i.qty, 0);
return (
{children}
);
}
function useCart() { return useContext(CartContext); }
Practice Problems
Problem 1: Implement a Promise.all
Write a function that behaves like Promise.all, resolving when all promises resolve or rejecting when any rejects.
function promiseAll(promises) {
return new Promise((resolve, reject) => {
const results = [];
let completed = 0;
if (promises.length === 0) return resolve(results);
promises.forEach((promise, index) => {
Promise.resolve(promise).then(value => {
results[index] = value;
completed++;
if (completed === promises.length) {
resolve(results);
}
}).catch(reject);
});
});
}
// Test
promiseAll([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
]).then(console.log); // [1, 2, 3]
Problem 2: Implement Array.prototype.map
Write your own map function that works like Array.prototype.map.
function arrayMap(arr, callback, thisArg) {
const result = new Array(arr.length);
for (let i = 0; i < arr.length; i++) {
if (i in arr) {
result[i] = callback.call(thisArg, arr[i], i, arr);
}
}
return result;
}
// Test
const doubled = arrayMap([1, 2, 3, 4], x => x * 2);
console.log(doubled); // [2, 4, 6, 8]
const indexed = arrayMap(['a', 'b', 'c'], (val, i) => `${val}${i}`);
console.log(indexed); // ['a0', 'b1', 'c2']
Problem 3: Create a Responsive Card Grid
Build a card grid that shows 4 columns on desktop, 2 on tablet, 1 on mobile.
.card-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1.5rem;
padding: 2rem;
}
@media (max-width: 1024px) {
.card-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
.card-grid {
grid-template-columns: 1fr;
gap: 1rem;
padding: 1rem;
}
}
.card {
background: white;
border-radius: 12px;
padding: 1.5rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition: transform 0.2s;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.12);
}
Problem 4: Implement a Simple Router
Create a hash-based SPA router in vanilla JavaScript.
class Router {
constructor() {
this.routes = {};
window.addEventListener('hashchange', () => this.resolve());
}
on(path, handler) {
this.routes[path] = handler;
return this;
}
resolve() {
const hash = location.hash.slice(1) || '/';
const handler = this.routes[hash] || this.routes['*'];
if (handler) handler();
}
navigate(path) {
location.hash = path;
}
}
// Usage
const router = new Router();
router
.on('/', () => renderHome())
.on('/about', () => renderAbout())
.on('/contact', () => renderContact())
.on('*', () => render404());
router.resolve(); // Handle initial route
Problem 5: WebSocket Reconnection Logic
Implement a WebSocket client with automatic reconnection and exponential backoff.
class ReconnectingWebSocket {
constructor(url, options = {}) {
this.url = url;
this.options = { maxRetries: 10, initialDelay: 1000, ...options };
this.retryCount = 0;
this.delay = this.options.initialDelay;
this.connect();
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('Connected');
this.retryCount = 0;
this.delay = this.options.initialDelay;
this.onopen?.();
};
this.ws.onmessage = (event) => this.onmessage?.(event);
this.ws.onclose = () => {
this.onclose?.();
this.reconnect();
};
this.ws.onerror = (err) => this.onerror?.(err);
}
reconnect() {
if (this.retryCount >= this.options.maxRetries) {
console.error('Max reconnection attempts reached');
return;
}
console.log(`Reconnecting in ${this.delay}ms...`);
setTimeout(() => {
this.retryCount++;
this.delay *= 2; // Exponential backoff
this.connect();
}, this.delay);
}
send(data) {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(data);
}
}
}
Problem 6: Debounce a Search Input
Implement a search box that only fires the search 500ms after the user stops typing.
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
function search(query) {
console.log(`Searching for: ${query}`);
// fetch(`/api/search?q=${query}`).then(...)
}
const input = document.getElementById('search-input');
input.addEventListener('input', debounce((e) => {
search(e.target.value);
}, 500));
Problem 7: Implement localStorage with Expiry
Create a wrapper for localStorage that supports TTL (time-to-live).
const storage = {
set(key, value, ttlMs = null) {
const item = {
value,
expiry: ttlMs ? Date.now() + ttlMs : null
};
localStorage.setItem(key, JSON.stringify(item));
},
get(key) {
const raw = localStorage.getItem(key);
if (!raw) return null;
const item = JSON.parse(raw);
if (item.expiry && Date.now() > item.expiry) {
localStorage.removeItem(key);
return null;
}
return item.value;
},
remove(key) { localStorage.removeItem(key); }
};
// Usage
storage.set('token', 'abc123', 60000); // Expires in 1 minute
const token = storage.get('token'); // Returns 'abc123' or null if expired
Problem 8: CSS Sticky Header with Scroll Behavior
Create a header that shrinks when the user scrolls down.
.header {
position: sticky;
top: 0;
z-index: 100;
padding: 1.5rem 2rem;
background: white;
transition: padding 0.3s ease, box-shadow 0.3s ease;
}
.header.scrolled {
padding: 0.75rem 2rem;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.header .logo {
font-size: 1.5rem;
transition: font-size 0.3s ease;
}
.header.scrolled .logo {
font-size: 1.2rem;
}
// Add scroll listener
let lastScroll = 0;
window.addEventListener('scroll', () => {
const header = document.querySelector('.header');
if (window.scrollY > 100) {
header.classList.add('scrolled');
} else {
header.classList.remove('scrolled');
}
lastScroll = window.scrollY;
});
Problem 9: Implement Server-Sent Events (SSE)
Create a server endpoint that streams updates to connected clients.
// Server-side (Express)
app.get('/api/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.flushHeaders();
// Send periodic updates
const interval = setInterval(() => {
res.write(`data: ${JSON.stringify({ time: new Date().toISOString() })}\n\n`);
}, 1000);
// Send initial data
res.write(`data: ${JSON.stringify({ message: 'Connected' })}\n\n`);
req.on('close', () => {
clearInterval(interval);
res.end();
});
});
// Client-side
const eventSource = new EventSource('/api/events');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Received:', data);
};
eventSource.onerror = (err) => {
console.error('SSE error:', err);
};
Problem 10: Full-Stack Todo App
Design the database schema and API endpoints for a collaborative todo app with users, lists, and tasks.
-- Database Schema
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
display_name VARCHAR(100)
);
CREATE TABLE lists (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
title VARCHAR(200) NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE tasks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
list_id UUID REFERENCES lists(id) ON DELETE CASCADE,
title VARCHAR(300) NOT NULL,
completed BOOLEAN DEFAULT FALSE,
due_date TIMESTAMPTZ,
priority INTEGER DEFAULT 0,
position INTEGER DEFAULT 0
);
-- API Endpoints
-- POST /api/auth/register โ Create account
-- POST /api/auth/login โ Get JWT token
-- GET /api/lists โ Get all lists for user
-- POST /api/lists โ Create list
-- GET /api/lists/:id/tasks โ Get tasks in list
-- POST /api/lists/:id/tasks โ Add task
-- PATCH /api/tasks/:id โ Update task
-- DELETE /api/tasks/:id โ Delete task