|
| 1 | +### Terminology |
| 2 | + |
| 3 | +- SSR: server-side rendering |
| 4 | +- SSG |
| 5 | +- ISR |
| 6 | +- Edge |
| 7 | +- Lambda |
| 8 | + |
| 9 | +### DOM |
| 10 | + |
| 11 | +Document Object Model: The in-browser tree of HTML elements representing the page. |
| 12 | + |
| 13 | +### Client |
| 14 | + |
| 15 | +The user's environment, the browser. The front-end is the code running in that environment. |
| 16 | +On Compass, it can be any browser (Chrome, Firefox, etc.). |
| 17 | + |
| 18 | +### Server |
| 19 | + |
| 20 | +Any remote infrastructure, i.e., not running in the user's environment / OS. The back-end is the code that runs in that environment. |
| 21 | +On Compass, there are two servers: |
| 22 | +- Web server: hosted on Vercel at `compassmeet.com`, which mostly provides the web pages to the client. That's the server we are talking about in the rest of the document. |
| 23 | +- Core server: hosted on Google Cloud at `api.compassmeet.com`, a server with more resources and permissions to update the database. It's in charge of any operation related to non-web data (i.e., no HTML or CSS) such as accounts, profiles, messages, and votes. |
| 24 | + |
| 25 | +--- |
| 26 | +### React |
| 27 | + |
| 28 | +React is a client-side UI library. |
| 29 | +Its core job: create and update a **virtual DOM**, then reconcile that with the **real DOM** in the browser. |
| 30 | +React itself **does not** define routing, data fetching conventions, or server rendering (it allows it, but doesn’t provide a full system). |
| 31 | + |
| 32 | +**Key behavior:** |
| 33 | + |
| 34 | +- React components run on the **client** by default. |
| 35 | +- React can be rendered on the **server** (via frameworks like Next.js), but this requires additional tooling. |
| 36 | +- React uses a Virtual DOM to compute minimal changes, then applies them to the real DOM. |
| 37 | + |
| 38 | +--- |
| 39 | +### Hydration |
| 40 | + |
| 41 | +When a framework pre-renders HTML on the server, the browser receives static markup (HTML, JS and CSS). React then runs on the client and attaches event listeners and internal state to that markup. |
| 42 | +Hydration bridges static HTML (build time) and interactive React behavior (run time). |
| 43 | + |
| 44 | +You only need hydration if you have server-rendered HTML that must become interactive. |
| 45 | + |
| 46 | +--- |
| 47 | + |
| 48 | +### Next.js: What it adds |
| 49 | + |
| 50 | +Next.js is a React framework that controls **where** code runs (server vs client), **when** it runs (build vs request time), and how HTML is generated. It adds routing, rendering strategies, data fetching conventions, and server infrastructure. |
| 51 | + |
| 52 | +Next.js introduces: |
| 53 | + |
| 54 | +- Server Components vs Client Components |
| 55 | +- Route-based rendering |
| 56 | +- Built-in server rendering pipelines |
| 57 | +- Build-time optimizations |
| 58 | + |
| 59 | +--- |
| 60 | + |
| 61 | +### Client vs Server in Next.js |
| 62 | + |
| 63 | +**Server Components:** |
| 64 | + |
| 65 | +- Render **on the server**, never shipped to the client. |
| 66 | +- Can safely access databases, filesystem, secrets. |
| 67 | +- Output is serialized to HTML + a data format React uses to assemble the UI. |
| 68 | + |
| 69 | +**Client Components (`"use client"`):** |
| 70 | + |
| 71 | +- Render **in the browser**. |
| 72 | +- Shipped to the client as JS bundles. |
| 73 | +- Needed for interactivity (state, events, effects). |
| 74 | + |
| 75 | +Notes: |
| 76 | + |
| 77 | +- You can mix Server and Client components; the boundary matters for bundle size and where code executes. |
| 78 | +- Only Client Components hydrate. |
| 79 | + |
| 80 | +--- |
| 81 | + |
| 82 | +### Build-Time vs Run-Time |
| 83 | + |
| 84 | +#### Build-Time (during `next build`) |
| 85 | + |
| 86 | +- The compiler analyzes the app, identifies server boundaries, optimizes routing. |
| 87 | +- Static pages (SSG) are rendered to final HTML. |
| 88 | +- Partial data may be pre-fetched if using static data functions. |
| 89 | +- Bundles for client components are built. |
| 90 | + |
| 91 | +#### Run-Time |
| 92 | + |
| 93 | +- Server Components for SSR are executed on each request. |
| 94 | +- Serverless or edge functions run as needed. |
| 95 | +- Client Components hydrate and run effects in the browser. |
| 96 | + |
| 97 | +--- |
| 98 | + |
| 99 | +### Rendering Strategies |
| 100 | + |
| 101 | +#### SSR (Server-Side Rendering) |
| 102 | + |
| 103 | +- Used a webpage or API endpoint (to get server-side data like build ID). |
| 104 | +- Generated on **every request**. |
| 105 | +- Good for dynamic data that must be fresh. |
| 106 | +- Initial load: server renders HTML → client hydrates. |
| 107 | +- Runs server logic each time a user requests the page. |
| 108 | + |
| 109 | +Can be dynamic or edge. |
| 110 | +###### λ (Dynamic) |
| 111 | + |
| 112 | +- **Server-rendered on demand using Node.js** |
| 113 | +- Each request hits a Node.js server (or serverless function) |
| 114 | +- Full access to Node APIs, filesystem, secrets, DB connections |
| 115 | +- Typical use: **SSR pages with dynamic data** not suitable for edge |
| 116 | +- Latency depends on server location |
| 117 | + |
| 118 | +###### ℇ (Edge Runtime) |
| 119 | + |
| 120 | +- **Server-rendered on demand using Edge Runtime** |
| 121 | +- Runs on global edge nodes (CDN locations) |
| 122 | +- Faster response due to geographic proximity |
| 123 | +- Limited APIs: no filesystem, limited Node.js modules, mostly fetch and standard web APIs |
| 124 | +- Typical use: **low-latency SSR or ISR at the edge** |
| 125 | + |
| 126 | +#### SSG (Static Site Generation) |
| 127 | + |
| 128 | +- HTML is generated **at build time**. |
| 129 | +- Served as static files. |
| 130 | +- Zero server cost at request time. |
| 131 | +- Best for data that changes rarely. |
| 132 | + |
| 133 | +#### ISR (Incremental Static Regeneration) |
| 134 | + |
| 135 | +- A hybrid of SSG + scheduled revalidation. |
| 136 | +- Page is generated at build, then regenerated **in the background** after a specified interval. |
| 137 | +- Allows static pages with reasonably fresh content without full rebuilds. |
| 138 | + |
| 139 | +Example behavior: |
| 140 | + |
| 141 | +- First request after the revalidation window triggers a background regeneration. |
| 142 | +- Users keep seeing the old page until the new one is ready, then updates swap in. |
| 143 | + |
| 144 | +There are components that: |
| 145 | + |
| 146 | +- Run once **on the server** to generate HTML (SSR phase) |
| 147 | +- Then run again **in the browser** for hydration (client phase) |
| 148 | + |
| 149 | +--- |
| 150 | + |
| 151 | +### What Runs Where: Quick Table |
| 152 | + |
| 153 | +| Task / Code | Build Time | Server Run Time | Client Run Time | |
| 154 | +| -------------------------- | ---------- | ---------------- | --------------- | |
| 155 | +| Pre-rendering SSG pages | Yes | No | No | |
| 156 | +| ISR regeneration | No | Yes (background) | No | |
| 157 | +| SSR rendering | No | Yes | No | |
| 158 | +| React event handling | No | No | Yes | |
| 159 | +| `useEffect` | No | No | Yes | |
| 160 | +| Server Component rendering | No | Yes | No | |
| 161 | +| Client Component hydration | No | No | Yes | |
| 162 | + |
| 163 | +--- |
| 164 | + |
| 165 | +# 1. Component Type Detection |
| 166 | + |
| 167 | +## A. **Client Component (App Router)** |
| 168 | + |
| 169 | +A component is a **Client Component** if: |
| 170 | + |
| 171 | +- The file begins with `"use client"`, or |
| 172 | +- It uses **client-only hooks** (`useState`, `useEffect`, `useRef`, etc.), or |
| 173 | +- It references **browser APIs** (`window`, `document`, `localStorage`, etc.), or |
| 174 | +- It uses **client navigation** (`Router.replace`, `useRouter`), or |
| 175 | +- It uses **interactive JSX handlers**: `onClick`, `onSubmit`, etc. |
| 176 | + |
| 177 | +**Implications:** |
| 178 | + |
| 179 | +- Runs **only in browser** |
| 180 | +- **Hydrates** on the client |
| 181 | +- **No SSR** of its data |
| 182 | +- May receive HTML shell from server, but logic/data loads on client |
| 183 | + |
| 184 | +Client Components = browser-only, hydrated, interactive. |
| 185 | + |
| 186 | +--- |
| 187 | + |
| 188 | +## B. **Server Component (App Router)** |
| 189 | + |
| 190 | +A component is a **Server Component** if: |
| 191 | + |
| 192 | +- No `"use client"` |
| 193 | +- No client hooks |
| 194 | +- No browser APIs |
| 195 | +- No interactive handlers |
| 196 | +- Uses server-only capabilities (DB queries, file system, server fetch, secrets) |
| 197 | + |
| 198 | +**Implications:** |
| 199 | + |
| 200 | +- Runs on **server at build time** (if static) and/or **server at request time** |
| 201 | +- **No hydration** for the server part |
| 202 | +- Can output HTML directly |
| 203 | +- Can trigger SSG / SSR / ISR depending on cache mode or revalidate |
| 204 | + |
| 205 | +--- |
| 206 | + |
| 207 | +# 3. Rendering Strategy (Pages Router Rules) |
| 208 | + |
| 209 | +In the **Pages Router**, rendering is dictated entirely by which data-fetching function you export. |
| 210 | + |
| 211 | +Below are the functions and exactly what they imply. |
| 212 | + |
| 213 | +--- |
| 214 | + |
| 215 | +# 4. `getServerSideProps` — What It Does and What It Implies |
| 216 | + |
| 217 | +```js |
| 218 | +export async function getServerSideProps(context) { ... } |
| 219 | +``` |
| 220 | + |
| 221 | +### What it does: |
| 222 | + |
| 223 | +- Runs **on the server for every request**. |
| 224 | +- Provides props to the page component. |
| 225 | +- Has access to: |
| 226 | + - database |
| 227 | + - filesystem |
| 228 | + - environment variables |
| 229 | + - cookies, headers, auth context |
| 230 | + |
| 231 | +### What it implies: |
| 232 | + |
| 233 | +- The page is **SSR** (Server-Side Rendered). |
| 234 | +- HTML is generated **on each request**. |
| 235 | +- **No SSG** or ISR possible. |
| 236 | +- The page is never static. |
| 237 | + |
| 238 | +### Rendering outcome: |
| 239 | + |
| 240 | +- **SSR HTML** + hydration for any client-side React in the page. |
| 241 | + |
| 242 | +--- |
| 243 | + |
| 244 | +# 5. `getStaticProps` — What It Does and What It Implies |
| 245 | + |
| 246 | +```js |
| 247 | +export async function getStaticProps(context) { ... } |
| 248 | +``` |
| 249 | + |
| 250 | +### What it does: |
| 251 | + |
| 252 | +- Runs **once at build time**. |
| 253 | +- Fetches data needed for static generation. |
| 254 | +- Provides props to the component. |
| 255 | + |
| 256 | +### What it implies: |
| 257 | + |
| 258 | +- The page is **SSG** (Static Site Generated). |
| 259 | +- The output is static HTML + static JSON. |
| 260 | +- Zero server rendering at request time. |
| 261 | + |
| 262 | +### Rendering outcome: |
| 263 | + |
| 264 | +- **Purely static HTML** served from CDN. |
| 265 | +- Hydration if component includes client logic (but no server execution). |
| 266 | + |
| 267 | +### When ISR occurs: |
| 268 | + |
| 269 | +- If you return `{ revalidate: N }` from `getStaticProps`, the page becomes **ISR**. |
| 270 | + |
| 271 | +Example ISR config: |
| 272 | + |
| 273 | +```js |
| 274 | +export async function getStaticProps() { |
| 275 | + return { |
| 276 | + props: { ... }, |
| 277 | + revalidate: 60 // seconds |
| 278 | + } |
| 279 | +} |
| 280 | +``` |
| 281 | + |
| 282 | +--- |
| 283 | + |
| 284 | +# 6. `getStaticPaths` — What It Does and What It Implies |
| 285 | + |
| 286 | +Used for **dynamic SSG pages** (e.g., `[id].js`). |
| 287 | + |
| 288 | +```js |
| 289 | +export async function getStaticPaths() { ... } |
| 290 | +``` |
| 291 | + |
| 292 | +### What it does: |
| 293 | + |
| 294 | +- Runs **at build time**. |
| 295 | +- Tells Next.js which dynamic routes to pre-render. |
| 296 | +- Works together with `getStaticProps`. |
| 297 | + |
| 298 | +### What it implies: |
| 299 | + |
| 300 | +- Page is **SSG** or **ISR** depending on `getStaticProps`. |
| 301 | +- The routing structure is fixed at build time unless fallback mode is used. |
| 302 | + |
| 303 | +### Fallback modes define run-time: |
| 304 | + |
| 305 | +- `fallback: false` → Only pages listed exist; 404 for others |
| 306 | +- `fallback: true` → Generate pages at runtime, then cache them as static |
| 307 | +- `fallback: "blocking"` → Block until server generates static page |
| 308 | + |
| 309 | +Fallback generation effectively behaves like **ISR** for pages not pre-rendered. |
| 310 | + |
| 311 | +--- |
| 312 | + |
| 313 | +# 7. Summary Table (Pages Router) |
| 314 | + |
| 315 | +| Export | When It Runs | Rendering Model | Triggered By | |
| 316 | +| -------------------- | -------------------- | -------------------------------------- | --------------------------- | |
| 317 | +| `getServerSideProps` | On **every request** | **SSR** | Always dynamic | |
| 318 | +| `getStaticProps` | **Build time** | **SSG** (or **ISR** with `revalidate`) | No runtime server | |
| 319 | +| `getStaticPaths` | **Build time** | **SSG** for dynamic routes | Works with `getStaticProps` | |
| 320 | + |
| 321 | +--- |
| 322 | + |
| 323 | +# 8. Combining Rules: How to Infer Rendering from Code |
| 324 | + |
| 325 | +### If you see `getServerSideProps`: |
| 326 | + |
| 327 | +- The page is always **SSR** |
| 328 | +- Component receives props from server |
| 329 | +- Component itself is a normal React component rendered server-side then hydrated |
| 330 | +- No client data loading unless the component explicitly fetches in browser |
| 331 | + |
| 332 | +### If you see `getStaticProps`: |
| 333 | + |
| 334 | +- The page is **SSG** or **ISR** |
| 335 | +- Only runs again during revalidation |
| 336 | +- Component is static unless you add client-side fetching |
| 337 | + |
| 338 | +### If you see `getStaticPaths`: |
| 339 | + |
| 340 | +- The file uses dynamic **SSG** or **ISR** |
| 341 | +- Builds static versions of dynamic routes |
| 342 | + |
| 343 | +### If you see `"use client"`: |
| 344 | + |
| 345 | +- Entire file is **client-rendered** |
| 346 | +- Data in this component does **not** SSR |
| 347 | +- Even if the page uses SSG/SSR, this component runs only in browser |
| 348 | + |
| 349 | +### If you see hooks (`useState`, `useEffect`, etc.): |
| 350 | + |
| 351 | +- The component must be **client-side** |
| 352 | +- It must hydrate |
| 353 | +- It cannot participate in server rendering logic |
| 354 | +- SSG/SSR/ISR still occurs for the page shell, but the logic inside this component runs only in browser |
| 355 | + |
| 356 | +### If you see server-side code (DB queries, secrets): |
| 357 | + |
| 358 | +- Component must be **Server Component** (App Router) or handled inside `getServerSideProps`/`getStaticProps` |
| 359 | + |
| 360 | +--- |
| 361 | + |
| 362 | +### How to Think About It When Architecting |
| 363 | + |
| 364 | +1. **Default to Server Components** whenever no browser interactivity is needed. |
| 365 | + Reduces bundle size and avoids unnecessary hydration. |
| 366 | + |
| 367 | +2. **Use Client Components** only where interaction happens (buttons, forms, animations, local state). |
| 368 | + |
| 369 | +3. **Choose a rendering model based on data volatility**: |
| 370 | + - Rarely changing: SSG |
| 371 | + - Somewhat changing and OK with slightly stale: ISR |
| 372 | + - Must always be fresh or personalized: SSR |
| 373 | + |
| 374 | +4. **Remember:** Hydration cost scales with the amount of Client Components. Keep them narrow. |
| 375 | + |
| 376 | +5. **Consider caching**: |
| 377 | + Next.js can automatically cache server component results; knowing what is cached impacts performance heavily. |
| 378 | + |
| 379 | + |
| 380 | +### Backend vs Frontend on Next.js |
| 381 | + |
| 382 | +| Term | True Meaning | Might Confuse People Because… | |
| 383 | +| ------------ | ------------------------------------------------------------------------ | --------------------------------------------------------------------------- | |
| 384 | +| **Frontend** | Code that executes in the user’s environment (browser, WebView) | SSR code _belongs to frontend logic_ but executes on server | |
| 385 | +| **Backend** | Code that executes on remote infrastructure (server, VM, cloud function) | Some “backend-like” behavior can occur in browser via caching or local APIs | |
| 386 | + |
| 387 | +### Downtime |
| 388 | + |
| 389 | +To simulate downtime **you need the error to happen at runtime, not at build time**. That means the page must be **server-rendered**, not statically generated. |
0 commit comments