FrontEnd Atlas

Fundamentals

HTML

SEO (Search Engine Optimization)

  • Use semantic HTML elements (<article>, <section>, <nav>, <header>, <h1><h2> etc.)
  • Set meaningful <title> and <meta name="description" content="xxx"> for each page.
  • Use of <alt> Attributes on Images
  • Use <meta name="robots"> or robots.txt to control indexing.

Render Process

DOM + CSSOM => Render Tree
Layout(Size, Position) => Paint(Color, Background) => Composite
Recalculate Style => Reflow => Repaint => Compositing

Storage

  • localStorage
    • Persistent: Data persists even after browser/tab is closed.
    • Scope: Same-origin (same domain + port + protocol).
    • Capacity: About 5MB.
  • sessionStorage
    • Session-based: Data is cleared when the browser/tab is closed.
    • Scope: Same-origin, and only within the same tab.
    • Capacity: About 5MB.

Accessibility (a11y)

Use ARIA (Accessible Rich Internet Applications)

Script Tags

  • <script src="..."></script>: Downloads and executes the script immediately, blocking the HTML parsing.
  • <script src="..." async></script>: Loads the script asynchronously, allowing HTML parsing to continue. The script executes as soon as it is loaded.
  • <script src="..." defer></script>: Loads the script in the background and executes it after the HTML parsing is complete.

CSS

BFC (Block Formatting Context)

Characteristics:

  • It is a separate layout context
  • It prevents margin collapsing
  • It contains floats

How to create a BFC:

  • overflow: hidden / auto / scroll
  • position: absolute / fixed
  • display: flow-root / flex / grid
  • float: left / right

Flexbox / Grid

Flexbox is designed for one-dimensional layout, either in a row or a column. Grid is two-dimensional, allowing precise control over both rows and columns.

Responsive Design

viewport + rem:

1
<meta name="viewport" content="width=device-width, initial-scale=1.0">
1
2
3
4
5
6
html {
font-size: calc(100vw / 7.5);
}
.box {
width: 3rem;
}

Adaptive Design

Media Queries: @media (max-width: 600px) { ... }

CSS Modules

xxx.module.css file:

1
2
3
4
/* Button.module.css */
.button {
background: blue;
}
1
2
3
import styles from './Button.module.css';

<h1 className={styles.button}>Hi</h1>

After build:

1
<h1 class="Button_button__a1b2c">Hi</h1>

JavaScript

Event Loop

The Event Loop is the mechanism that handles the execution of multiple pieces of code over time, coordinating the call stack, microtasks, and macrotasks queues in a single-threaded environment.

  • Macrotask: Event callbacks, setTimeout, Node.js I/O, setImmediate
  • Microtask: Promise callbacks (fetch.then), process.nextTick(Node.js, priority over promises)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    console.log('start');

    setTimeout(() => {
    console.log('timeout');
    }, 0);

    Promise.resolve().then(() => {
    console.log('promise');
    });

    console.log('end');

    // Output:
    // start
    // end
    // promise
    // timeout

Async & Await: code after await is executed in the microtask queue, so it runs after the current stack and before the next macrotask.

1
2
3
4
5
6
7
8
9
10
11
12
async function test() {
console.log('1');
await Promise.resolve(); // creates a microtask for the code after await
console.log('3');
await Promise.resolve(); // creates a microtask
console.log('5');
}
console.log('0');
test();
console.log('2');
Promise.resolve().then(()=>console.log('4'))
// Output: 012345

Debounce & Throttle

Debounce: Ensures that a function is only called after a certain period of inactivity. Useful for events like resizing or scrolling.

1
2
3
4
5
6
7
8
9
function debounce(fn, delay = 300) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}

Throttle: Ensures that a function is called at most once in a specified time interval. Useful for events like scrolling or mouse movements.

1
2
3
4
5
6
7
8
9
10
function throttle(fn, wait = 300) {
let prev = 0;
return function (...args) {
const now = Date.now();
if (now - prev > wait) {
prev = now;
fn.apply(this, args);
}
};
}

Modules & Imports

ES Modules vs CommonJS Incompatibility: Use Babel、Webpack、Vite to transpile CJS to ES Modules.

Closures & Scope

A closure is a function that “remembers” the variables from its outer lexical scope even after that scope has closed. (When a function is defined inside another function, it forms a closure.)

let and const are block-scoped, meaning they are only accessible within the block they are defined in. var is function-scoped or globally scoped.

Prototypes & Inheritance

Use Object.prototype.toString.call() to check the type of an object. Yeah, shit happens.

This Loss

call, apply, bind and arrow function

Parasitic Combination Inheritance

Class is syntactic sugar over prototypal inheritance.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Parent
function Animal(name) {
this.name = name;
this.colors = ['black', 'white'];
}

// Parent's shared func
Animal.prototype.sayName = function () {
console.log(this.name);
};

// Son
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype); // change prototype
Dog.prototype.constructor = Dog; // recover constructor

// Son's shared func
Dog.prototype.sayBreed = function () {
console.log(this.breed);
};

Typescript

keyof, typeof, in, extends in types

1
2
3
4
5
6
7
8
9
10
type A = { name: string; age: number };
type Keys = keyof A; // 'name' | 'age'

const user = { id: 1, name: 'Tom' };
type UserType = typeof user;

type Props = 'a' | 'b';
type Obj = { [key in Props]: number };

type IsString<T> = T extends string ? true : false;

Pick, Omit, Partial, Required

1
2
3
4
5
6
type User = { id: number; name?: string };

type U1 = Pick<User, 'id'>; // { id: number }
type U2 = Omit<User, 'name'>; // { id: number }
type U3 = Partial<User>; // { id?: number; name?: string }
type U4 = Required<User>; // { id: number; name: string }

Generics

1
2
3
4
5
6
function identity<T>(arg: T): T {
return arg;
}

const num = identity<number>(123); // T => number
const str = identity<string>('abc'); // T => string

Type Guards

Type guards are functions that check the type of a variable at runtime.

1
2
3
function isString(value: any): value is string {
return typeof value === 'string';
}

FrontEnd Frameworks

React

Virtual DOM: A lightweight JavaScript representation of the real DOM used by React to optimize rendering.

Components Re-render: When props or state change, React re-renders the component and its children. Use React.memo to prevent unnecessary re-renders.

React Reconciliation: The process of comparing the new Virtual DOM with the previous one and updating the real DOM efficiently. If the components are the same, React reuses the existing DOM nodes instead of creating new ones. If the DOM nodes are different, React updates the real DOM with the new changes.

Fiber Architecture: React’s reconciliation algorithm that breaks down the rendering process into smaller units called fibers, allowing for more efficient updates and prioritization of tasks.

State Management

Unidirectional Data Flow: Data in React always flows from parent to child via props.

State Lifting: Moving state up to the nearest common ancestor to share state between components.

Context API

  • React.createContext(defaultValue)
  • <Provider value={...}>
  • useContext(Context) or Context.Consumer

Drawbacks:

  • Renders All Consumers on Any Value Change (React uses shallow comparison: Object.is(prev, next))

Redux

A functional state management library for React that ensures predictable state updates. with Unidirectional Data Flow.

  • Single Source of Truth: The entire application state is stored in a single store.
  • State is Read-Only: The only way to change the state is by dispatching actions.
  • Changes are Made with Pure Functions: Reducers are pure functions that take the current state and an action, and return a new state. They don’t mutate state and are side-effect free.
  • Predictable State Updates: The state is updated in a predictable manner, making it easier to debug and test.

Core Concepts:

  • Store: The centralized container that holds the application’s entire state.
  • State: The current data or status of the application stored in the store.
  • Actions: Plain JavaScript objects that describe what happened and how state should change.
  • Reducers: Pure functions that take the current state and an action, and return the new state.
    • extraReducers: Functions that handle actions defined outside the slice, allowing for more flexible state updates.
    • createAsyncThunk: A utility to create asynchronous actions that dispatch pending, fulfilled, and rejected actions based on the promise’s state.
  • Dispatch: A function that sends an action to the reducer to update the state.
  • Middleware: Functions that intercept dispatched actions before they reach the reducer, for side effects or logging.

React-redux:

  • createSlice(): A utility to create a slice of the Redux store with actions and reducers.
  • configureStore(): A function to create a Redux store with preconfigured settings.
  • <Provider>: A wrapper component that makes the Redux store available to the rest of the React app. ( Base on Context API )
  • useSelector(): A hook to read specific pieces of state from the Redux store.
    • rerenders the component when the selected state changes.
    • implemented using useReducer.
  • useDispatch(): A hook to dispatch actions to the Redux store.
  • connect(): A higher-order component (HOC) that connects class or function components to the Redux store.
    • mapStateToProps: A function that maps Redux state to component props.

Steps:

  1. createSlice(): defines state logic (reducer + actions)
  2. configureStore(): registers slices into one global store
  3. <Provider store>: makes the store available to your app
  4. Use:
    • useSelector(): read state
    • useDispatch(): update state

Recoil

  • Atoms: Units of state that can be read from and written to from any component.
  • Selectors: Pure functions that derive state from atoms or other selectors.
  • useRecoilState(): A hook to read and write an atom’s state.

React Hooks

useEffect:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
let hookIndex = 0;
let hooks = [];
let currentComponent = null;
let effects = [];

function useState(initialValue) {
const stateIndex = hookIndex;

if (hooks[stateIndex] === undefined) {
hooks[stateIndex] = initialValue;
}

function setState(newValue) {
hooks[stateIndex] = newValue;
render(currentComponent); // trigger re-render
}

hookIndex++;
return [hooks[stateIndex], setState];
}

function useEffect(callback, deps) {
const effectIndex = hookIndex;
const prevDeps = hooks[effectIndex];

const hasChanged = !prevDeps || deps.some((dep, i) => dep !== prevDeps[i]);

if (hasChanged) {
effects.push(() => {
// execute cleanup
if (hooks[effectIndex]?.cleanup) {
hooks[effectIndex].cleanup();
}
const cleanup = callback();
hooks[effectIndex] = deps;
if (typeof cleanup === 'function') {
hooks[effectIndex].cleanup = cleanup;
}
});
}

hookIndex++;
}

function render(Component) {
hookIndex = 0;
currentComponent = Component;
Component();
effects.forEach(fn => fn());
effects = [];
}

useInterval:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function useInterval(callback: () => void, delay: number | null) {
const savedCallback = useRef(callback);

// Always keep latest callback
useEffect(() => {
savedCallback.current = callback;
}, [callback]);

useEffect(() => {
if (delay === null) return;

const id = setInterval(() => savedCallback.current(), delay);

return () => clearInterval(id); // cleanup function
}, [delay]);
}

// Usage
useInterval(() => {
setCount(c => c + 1);
}, delay);

HOC

A Higher-Order Component (HOC) is a function that takes a component and returns a new component, allowing for code reuse and separation of concerns.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// HOC that adds loading behavior
function withLoading(Component) {
return function WrappedComponent({ isLoading, ...props }) {
if (isLoading) return <div>Loading...</div>;
return <Component {...props} />;
};
}

// Usage
function UserList({ users }) {
return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}

const UserListWithLoading = withLoading(UserList);

React Router

BrowserRouter

BrowserRouter uses HTML5 history API. Server-side configuration is required to handle routes. It is SEO-friendly. (SPA)

HashRouter

HashRouter uses URL hash. No need for server-side configuration, but not SEO-friendly.

  • Routes: Defines route paths and the components that should render for each path.
  • Route: Represents a single route mapping a URL path to a React component.
  • Link: Navigational component to change the URL without causing a full page reload.
  • useNavigate: Hook to programmatically navigate to different routes.
  • Outlet: Placeholder for rendering nested child routes.
  • Navigate: Component to redirect to another route.

React Error

Use Error Boundaries to catch JavaScript errors in components and display a fallback UI instead of crashing the entire app. ErrorBoundaries are class components that implement the componentDidCatch lifecycle method and the static getDerivedStateFromError method. which allows them to catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.

React Native

JavaScript Bridge is the communication layer in React Native that connects JavaScript and native code, enabling data exchange and function calls between the two realms.

Next.js

Build pages as server-rendered components for fast, SEO-friendly static or dynamic content, and embed client components only where interactivity is needed. Routing is automatic via the file system, so you don’t manually configure routes or use libraries like react-router-dom. This design merges server rendering and client interactivity into one smooth developer experience.

Pages Router: Use getServerSideProps for server-side rendering (SSR) to fetch data on each request, and getStaticProps for static site generation (SSG) to pre-render pages at build time.

App Router: Use app/page.js (or .tsx) as server components by default. To create client components, add 'use client' at the top of the file. In server components, fetch data using await fetch() or React’s use hook.

Hydration is the process where React takes server-rendered HTML and attaches event listeners to make it interactive in the browser — without rebuilding the DOM.

Advantages:

  • SEO-friendly: Pre-rendering improves search engine indexing.
  • Performance: Reduces client-side rendering time.
  • Automatic Code Splitting: Only loads the necessary JavaScript for each page.

Disadvantages:

  • Increased complexity: Requires understanding of both server-side and client-side rendering.
  • Server load: More server resources are required for SSR compared to client-side rendering.

Build Tools

Webpack

  • Entry: Entry point of the application.
  • Output: Where to emit the bundled files.
  • Loaders: Transform files (e.g., Babel for JS, CSS loader).
  • Plugins: Extend functionality (e.g., HTMLWebpackPlugin).
  • Hot Module Replacement (HMR): Allows modules to be updated in the browser without a full reload.
  • Tree Shaking: Removes unused code from the final bundle.
  • Code Splitting: Splits code into smaller chunks to load only what is needed.

Babel

Transpiles modern JavaScript to older versions for compatibility. Like ES6+ to ES5, JSX, TypeScript, etc.

Polyfill

A polyfill is JavaScript code that implements a modern feature on older browsers that do not support it. Like Promise, fetch, Object.assign, etc.

Fullstack

Node.js

Express.js

Express’s next() function cannot wait

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const express = require('express');
const app = express();

// Middleware
app.use(express.json()); // Body parser

// Routing
app.get('/hello/:name', (req, res) => {
res.send(`Hello, ${req.params.name}`);
});

// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});

// Start server
app.listen(3000, () => console.log('Server running on port 3000'));

Implementation of next()

1
2
3
4
5
6
7
8
9
10
11
function next(err) {
// find the next middleware in the stack
const layer = stack[i++];
if (!layer) return;

try {
layer.handle(req, res, next);
} catch (e) {
next(e);
}
}

Koa.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const Koa = require('koa');
const app = new Koa();

// Logger Middleware
app.use(async (ctx, next) => {
console.log(`${ctx.method} ${ctx.url}`);
await next(); // Middleware Onion Model
});

// Response Middleware
app.use(async ctx => {
ctx.body = 'Hello from Koa!';
});

// Error Handling
app.on('error', (err, ctx) => {
console.error('Server error:', err);
});

app.listen(3000, () => console.log('Koa server running on port 3000'));

Implementation of next()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function compose(middlewares) {
return function (ctx) {
return dispatch(0);

function dispatch(i) {
const fn = middlewares[i];
if (!fn) return Promise.resolve(); // Last resolved Promise

try {
return Promise.resolve(
fn(ctx, () => dispatch(i + 1)) // pass next to next middleware
);
} catch (err) {
return Promise.reject(err);
}
}
};
}

Nest.js

Like Java Spring Boot. It has dependency injection, modules, controllers, services, and middleware.

  • Module: for organizing and managing application code
  • Controllers: handle incoming client requests
  • Services: contain business logic and data processing, implementing the actual functionalities. They often interact with databases or third-party APIs. Controllers call services to perform real business operations.
  • Middleware: like express’s middleware, intercepting and processing requests to perform common tasks (e.g., logging, authentication, body parsing). They are not business logic but support the request flow. ( cannot awit next() )
  • Dependency Injection (DI): is a design pattern where dependencies (services or objects a class needs) are provided to a class instead of the class creating them itself. This promotes loose coupling, easier testing, and better maintainability.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { Module, Controller, Get, Injectable } from '@nestjs/common';

// Service (Provider)
@Injectable()
class AppService {
getHello(): string {
return 'Hello NestJS!';
}
}

// Controller
@Controller()
class AppController {
constructor(private readonly appService: AppService) {}

@Get()
getHello(): string {
return this.appService.getHello();
}
}

// Module
@Module({
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

Deployment

CI/CD

  • Continuous Integration (CI): Automatically build and test code changes to ensure they integrate well with the existing codebase.
  • Continuous Deployment (CD): Automatically deploy code changes to production after passing tests, ensuring that the latest code is always live.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    name: Deploy
    on: [push]
    jobs:
    build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - run: npm install
    - run: npm run build

Nginx

A high-performance HTTP server used to serve static files and reverse-proxy backend services.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
listen 80; # Listen on HTTP port 80

server_name yourdomain.com; # Replace with your actual domain name

location / {
root /var/www/html; # Serve static files from this directory (e.g., React/Vue build output)

try_files $uri /index.html;
# Try to serve the requested file
# If the file is not found, fallback to index.html (for SPA routing support)
}

location /api/ {
proxy_pass http://localhost:3000/;
# Reverse proxy requests starting with /api/ to your backend server (e.g., Express)
# Example: /api/user -> http://localhost:3000/api/user
}
}

CDN

Use Webpack’s publicPath or Vite’s base option to set the CDN URL for static assets. Then, upload the generated assets (e.g. from the dist/ folder) to a CDN as part of the CI/CD pipeline.

1
2
3
4
5
6
// webpack.config.js
module.exports = {
output: {
publicPath: 'https://cdn.example.com/assets/',
},
};

Testing

Jest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// test()
test('1 + 2 should equal 3', () => {
expect(1 + 2).toBe(3);
});

// expect()
expect(value).toBe(expected); // ===
expect(value).toEqual(obj); // deep equality
expect(arr).toContain(item); // checks if array contains item
expect(str).toMatch(/regex/); //
expect(func).toThrow(); // should throw an error

// describe(): Group tests together
describe('Math utils', () => {
test('adds correctly', () => {
expect(1 + 2).toBe(3);
});

test('multiplies correctly', () => {
expect(2 * 3).toBe(6);
});
});

// beforeAll / afterAll / beforeEach / afterEach
beforeEach(() => {
});

afterAll(() => {
});

// Mock
const mockFn = jest.fn();
mockFn('hello');
expect(mockFn).toHaveBeenCalledWith('hello'); // the mock function was called with params 'hello'

Error Handling

Error types:

  • Synchronous Errors: Errors thrown during synchronous execution
  • Asynchronous Errors: Errors from fetch, setTimeout, etc.
  • Event Handler Errors: Errors in event listeners
  • Unhandled Promise Errors: Promises without .catch(). use window.onunhandledrejection to catch unhandled promise rejections.
  • Global Uncaught Errors: Use window.onerror or window.addEventListener('error', ...) to catch uncaught errors globally.
  • Syntax Errors: Parse-time errors. Prevent via build tools
  • Resource Loading Errors: Failed image/script loading.use element.onerror listener

White Screen Detection

  1. DOM Content Check
    1
    2
    3
    4
    5
    6
    7
    window.addEventListener('load', () => {
    const root = document.getElementById('root');
    if (!root || root.innerHTML.trim() === '') {
    console.warn('Potential white screen detected');
    // Report incident
    }
    });
  2. Key DOM Elements Check (Position, Color). Use Canvas get a snapshot of the screen.
  3. Performance Timing API
    1
    2
    const [fp, fcp] = performance.getEntriesByType("paint");
    console.log("FP:", fp.startTime, "FCP:", fcp.startTime);

Performance

Web Vitals

  • TTFB (Time to First Byte): Time to first byte from server.
  • FCP (First Contentful Paint): Time to first contentful paint.
  • LCP (Largest Contentful Paint): Time to largest contentful paint.
  • CLS (Cumulative Layout Shift): Measures layout shifts during page load.
  • FID (First Input Delay): Measures delay between first user interaction and browser response.
  • INP (Interaction to Next Paint): Measures time from user interaction to next paint.

Use Chrome DevTools and Lighthouse to measure these metrics.

Optimization

  • Network:
    • Tree Shaking: Eliminate unused code from the final bundle to reduce size. (Only works with ES modules and side-effect-free code.)
    • Code Splitting: Split the application into smaller bundles that are loaded on demand.
    • Lazy Loading: Load components or resources only when needed, reducing initial load time.
      • Use IntersectionObserver to detect when an element is in the viewport and load it dynamically.
    • Caching
    • CDN: Serve static assets from edge locations closer to the user to reduce latency.
    • Preloading & Prefetching:
      • Preload: Load critical resources early in the page load process.
      • Prefetch: Load resources that might be needed in the future, after the current page has loaded.
  • Rendering:
    • Virtualization: Render only the visible portion of large lists or tables to improve performance.
    • Avoid reflows and repaints
    • Rate Limiting: Debouncing, throttling and requestAnimationFrame
    • React re-render optimization: Use React.memo, useMemo, and useCallback to prevent unnecessary re-renders.

Networking

GraphQL & REST API

  • REST API is resource-based with fixed endpoints.
  • GraphQL allows clients to query only the needed data via a single endpoint.

CDN

A Content Delivery Network (CDN) is a distributed network of servers that delivers web content to users based on their geographic location, improving load times and reducing latency.

Cache invalidation is done using versioning (changing file names), or cache-control headers.

HTTP Caching

HTTP caching is a mechanism to store copies of resources to reduce server load and improve performance. It uses headers like Cache-Control, Expires, ETag, and Last-Modified to control caching behavior.

  • Strong Cache: A browser-side cache that allows reusing previously fetched resources without contacting the server. Browser receives Cache-Control: max-age=3600 or Expires: <timestamp>.
  • Negotiated Cache: When strong cache expires or doesn’t apply, the browser sends a conditional request to the server using validation headers:
    • If-None-Match (paired with ETag)
    • If-Modified-Since (paired with Last-Modified)

Cache Flow Overview

  1. Browser checks local cache.
  2. If strong cache is valid → serve directly.
  3. If expired → send conditional request.
  4. Server validates and replies with 304 or the data itself.

Cookies

Cookies are small key-value pairs stored in the browser. Use Set-Cookie header to set cookies, and Cookie header to send cookies with requests. Attributes:

  • name=value
  • expires (old)
  • max-age: higher priority than expires (HTTP 1.1 new)
  • path: restricts cookie to a specific path (e.g., /api)
  • domain
  • secure: Only sent over HTTPS
  • HttpOnly: Not accessible via JavaScript
  • SameSite: Controls cross-site request behavior
    • Strict: Cookie is sent only for same-site requests. No cookies sent when navigating from another domain. (cannot send even with CORS credentials and Access-Control-Allow-Credentials: true)
    • Lax (default):
      • Cookies are sent with top-level navigation (like links, not ajax).
      • Blocked on cross-origin POST/PUT/DELETE, iframes, or fetch/XHR.
    • None: Cookies are sent with all cross-origin requests — including iframes, fetches, or POSTs. Must be marked Secure, i.e., only sent over HTTPS. Used for third-party cookies.

POST & GET

GET:

  • Used for retrieving resources.
  • Parameters are sent in the URL (query string). Data is visible in browser history and logs.
  • Can be cached.
  • Can be bookmarked.
  • Limited data size (due to URL length).
  • Idempotent (safe to repeat).
  • Does not change server state.

POST:

  • Used for creating or updating resources.
  • Parameters are sent in the request body. Data is not visible in the URL.
  • Not cached by default.
  • Cannot be bookmarked.
  • Supports large payloads (e.g. file upload, JSON).
  • Not idempotent (can have side effects).
  • Can change server state.

Cross-Origin Resource Sharing (CORS)

CORS is a security mechanism that allows or restricts resources on a web page to be requested from another domain outside the domain from which the resource originated.

Browsers block cross-origin requests by default. Origin = protocol + domain + port

Allow cross-origin requests by:

  • The browser sends an Origin header with each request.
  • The server must respond with the appropriate Access-Control-Allow-* headers.

Preflighted Requests

For non-simple requests (e.g., methods other than GET/POST, custom headers), the browser sends a preflight request using the OPTIONS method.

Server responds CORS Headers:

  • Access-Control-Allow-Origin: Specifies allowed origin(s). Use * to allow all (unsafe for credentials).
  • Access-Control-Allow-Methods: Lists allowed HTTP methods.
  • Access-Control-Allow-Headers: Lists allowed custom headers.
  • Access-Control-Allow-Credentials: Allows cookies or HTTP auth. Requires specific origin (not *).
  • Access-Control-Max-Age: Caches preflight response duration (in seconds).

HTTP Protocols

HTTP/1.1

  • Uses a new TCP connection per request (with optional keep-alive).
  • Head-of-line blocking: Later requests wait for earlier ones to complete.
  • Text-based headers with redundancy (no compression).
  • Limited parallelism (browsers typically allow 6 concurrent requests per domain).

HTTP/2

  • Multiplexing over a single TCP connection: Multiple requests run in parallel.
  • Uses binary framing for better performance.
  • Usually requires TLS/HTTPS.
  • Reduces head-of-line blocking (but still at the TCP layer).
  • Supports header compression (HPACK) and server push.

HTTP/3

  • Based on QUIC, which runs over UDP. (Not TCP)
  • Eliminates head-of-line blocking entirely with independent streams.
  • Faster connection setup with 0-RTT ((Zero Round Trip Time)) support.
  • Always encrypted with TLS 1.3.
  • Server Push is deprecated (not widely used).

WebSockets & SSE

WebSocket

  • A full-duplex communication protocol over a single TCP connection.
  • Enables real-time, bidirectional data exchange between client and server.
  • Useful for chat apps, gaming, live updates, etc.
  • After the handshake, data frames can be sent independently by either side anytime.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // Node.js
    const WebSocket = require('ws');
    const wss = new WebSocket.Server({ port: 8080 });

    wss.on('connection', ws => {
    console.log('Client connected');

    ws.on('message', message => {
    console.log('Received:', message);
    ws.send(`Server received: ${message}`);
    });

    ws.send('Welcome to WebSocket server!');
    });
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // Client-side JavaScript
    const ws = new WebSocket('ws://localhost:8080');

    ws.onopen = () => {
    console.log('Connected to server');
    ws.send('Hello server!');
    };

    ws.onmessage = event => {
    console.log('Message from server:', event.data);
    };

Security

XSS (Cross-Site Scripting)

Injecting malicious scripts into a trusted website. excute in the context of the user’s browser, potentially stealing cookies, session tokens, or other sensitive information.

Types:

  • Stored XSS: Malicious code saved in the database.
  • Reflected XSS: Injected via URL or query parameters.
  • DOM-based XSS: Exploits client-side JavaScript directly.

Prevention:

  • Escape user input (<, >, &, etc.)
  • Use frameworks that auto-escape (e.g. React, Vue).
  • Set proper HTTP headers (e.g., Content-Security-Policy).

CSRF (Cross-Site Request Forgery)

An attacker tricks the user’s browser into submitting a request to a site the user is authenticated on. eg: Unintended form submission from a malicious site using user’s cookie.

Prevention:

  • Use CSRF tokens (stored outside cookies) to protect state-changing requests that rely on cookies for authentication.
  • Use SameSite cookies (Strict or Lax).
  • Check Origin or Referer headers.

CSP (Content Security Policy)

CSP is enforced by the browser based on HTTP headers from the server. It blocks unauthorized script execution and resource loading before they happen, acting as a powerful defense against XSS and other injection attacks.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Content-Security-Policy:
default-src 'self';
# Default policy: allow only same-origin for all resources not explicitly covered below.
script-src 'self' https://cdn.example.com 'nonce-abc123';
# Allow scripts from same origin and from CDN. Also allow inline scripts with the specified nonce.
style-src 'self' 'unsafe-inline';
# Allow styles from same origin, and inline styles (less secure).
img-src 'self' data:;
# Allow images from same origin and data URIs (for embedded images like base64).
connect-src 'self' https://api.example.com;
# Allow AJAX/fetch/WebSocket connections to same origin and API server.
frame-ancestors 'none';
# Prevent the page from being embedded in any <iframe> (anti clickjacking).
report-uri /csp-report;
# Send CSP violation reports to this endpoint (deprecated in CSP Level 3).

Business logic

OAuth

  • Resource Owner: The user who owns the data or resource.
  • Client: The application requesting access to the user’s resources.
  • Authorization Server: Issues access tokens after authenticating the resource owner and obtaining authorization.
  • Resource Server: Hosts the protected user resources and validates access tokens.
  • Access Token: A credential that allows the client to access protected resources on behalf of the user.
  • Refresh Token: A long-lived token used to obtain new access tokens without requiring the user to re-authenticate.

Flow:

  1. User initiates login on the client app.
  2. Client redirects user to Authorization Server to ask for permission.
  3. User logs in and authorizes the client.
  4. Authorization Server redirects back with an authorization code.
  5. Client exchanges authorization code for access token by calling Authorization Server.
  6. Client uses access token to request protected resources from Resource Server

JWT

Structure:

  • Header: Metadata about the token, including the signing algorithm name.
  • Payload: Contains the claims (data) about the user and token.
  • Signature: Used to verify the integrity of the token and ensure it was not tampered with

Advantages:

  • Stateless: No need to store session data on the server.
  • Compact: Small size, easy to pass in URLs, headers, or cookies.
  • Self-contained: Contains all necessary information in the token itself.

SSO

  • IdP (Identity Provider): The authority that authenticates users
  • SP (Service Provider): Applications that rely on the IdP for authentication
  • Token / Ticket: A credential issued by the IdP after successful login (e.g., JWT)
  • Session: The authenticated session maintained by the IdP after the user logs in

QR Code Login

  • Desktop Client (Application): Displays the QR code and polls for authentication status.
  • Mobile App (Registered Authenticator): An already logged-in app that scans the QR code and authorizes the login.
  • Auth Service (Security Verify): Generates QR token, handles scan and login confirmation logic. Handles user identity verification, session creation, and token issuance.

Captcha

Team Collaboration

Monorepo

Why monorepo?

  • Dependency management: shared code, libraries, and tools in one place.
  • Cross-project collaboration: Easily make atomic changes across multiple packages without separate releases.
  • Versioning: single version for all packages, easier to manage.
  • CI/CD: unified build and test process for all packages.

Workspaces

  • Monorepo: A single Git repository containing multiple packages.
  • Workspace: A folder designated as a package (with its own package.json).
  • Dependency Hoisting: Shared dependencies are installed at the root to avoid duplication.
  • Local Linking: Internal workspace packages are symlinked for local development.

Lerna

Versioning Modes:

  • fixed: all packages share one version.
  • independent: each package has its own version.

Lerna Commands:

  • lerna bootstrap: Install dependencies and link local packages.
  • lerna publish: Publish changed packages to npm.
  • lerna run <script>: Runs the specified npm script across all packages in the monorepo.

Nx

  • Dependency Graph: Nx automatically analyzes the dependencies between projects and libraries in your repo, building a graph. This helps Nx determine what needs rebuilding or retesting, saving time by running only affected tasks.
  • Task Orchestration and Caching: Nx runs tasks like builds, tests, and linting efficiently using parallelization, smart scheduling, and caching. Results of previous tasks are cached so they don’t have to be rerun unnecessarily.

Review Checklist

  • Code follows ESLint rules and team style guide.
    • Use Prettier for code formatting.
  • PR title and description are clear and useful.
  • Includes tests for new logic.
  • No unnecessary logs or commented code.
  • Edge cases handled properly.
  • Performance and security concerns considered.

Systems Design & Architecture

Process

  1. Requirements: Gather functional and non-functional requirements.
  2. Architecture Design:
    • SPA vs MPA vs SSR vs Microfrontends vs mixed.
    • Pages, Routing, Components, state management (Redux vs Context), APIs (REST vs GraphQL), and data flow.
  3. Performance
  4. Security Design
    • Authentication (OAuth, SSO, JWT)
    • Secure communication (HTTPS, CORS)
    • XSS, CSRF, CSP
  5. Maintainability & Scalability:
    • ESLint, Prettier, TypeScript, Documentation
    • Modular architecture (components, utilities) to reuse.
    • Scalability (devices: iOS, or PC, ipad, i18n, a11y)
    • Stability (errors, offline)
    • Testing
  6. Deployment & Release:
    • Build tools (Webpack, Babel, Vite)
    • CI/CD pipelines
    • Versioning, rollback strategies
    • Canary Release / Gradual Rollout
  7. Monitoring & Feedback:
    • Error tracking (Sentry)
    • Performance monitoring (Web Vitals, Lighthouse)
    • User feedback (surveys, analytics)

Microfrontends

Micro‑Frontends extend the microservices ideology into front-end architecture—enabling a large UI to be split into smaller, independently developed, deployed, and maintained sub‑applications (or “micro‑apps”).

Each micro‑app runs separately, and they are integrated at runtime (or build‑time) into a cohesive user experience.

pros:

  • Autonomous teams & independent cycles: Features can be built and deployed independently. Avoid monolithic releases.
  • Technology flexibility: Teams choose their own frameworks (React, Vue, Angular, etc.)
  • Incremental modernization: Legacy parts can coexist alongside new implementations

cons:

  • Increased complexity: Routing, integration, orchestrating micro‑apps requires planning.
  • Bundle size/performance hit: Multiple JS/CSS bundles loaded separately can slow down load time.
  • Global style collision: Risks if CSS is not properly scoped (avoid global selectors).
  • Shared dependencies: Must manage duplicate versions (e.g. React) to avoid bloat or conflicts.
  • Cross‑micro‑app communication: Requires deliberate strategy (pub/sub, shared utilities, messaging).

OOP (Object-Oriented Programming)

  • Class: Blueprint for creating objects. Defines structure and behavior.
  • Object: An instance of a class.
  • Encapsulation: Bundles data and methods. Hides internal implementation details.
  • Inheritance: Allows one class to extend another. Promotes code reuse.
  • Polymorphism: Same interface, different implementations (e.g. method overriding).
  • Abstraction: Hides complexity, exposing only essential features.

Functional Programming

Functional Programming emphasizes pure functions, immutability, and function composition. It avoids shared state and side effects, making code easier to test and reason about.

  • Pure Functions: Given same inputs, always return same output, no side effects
  • Immutability: State is never modified, new values are returned instead
  • First-class functions: Functions can be passed as arguments and returned from other functions
  • Higher-order functions: Functions that operate on other functions
  • Function composition: Combine smaller functions into more complex logic
Author

Cheng

Posted on

2025-07-24

Updated on

2025-08-05

Licensed under

Comments