DEV Community

Cover image for πŸš€ Understanding the Critical Render Path in React & Vue (CSR) β€” And How It Differs from SSG & SSR
Vishwark
Vishwark

Posted on

πŸš€ Understanding the Critical Render Path in React & Vue (CSR) β€” And How It Differs from SSG & SSR

Modern SPAs (React & Vue) behave very differently from traditional websites when it comes to loading and rendering UI in the browser.
To understand performance, SEO, and UX, you must understand the Critical Rendering Path (CRP).

This post breaks down:

  • What happens from the moment the browser requests your page
  • What blocks rendering & why
  • How React and Vue CSR differ
  • How CSS strategies impact rendering
  • How SSG/SSR change the flow
  • What exactly is inside the main JavaScript bundle

Let’s go step by step.


🧠 1. What is the Critical Rendering Path?

The Critical Rendering Path (CRP) is:
➑️ The set of steps the browser performs to convert HTML/CSS/JS into pixels on the screen.

It contains 5 main stages:

1. HTML Download & Parsing β†’ DOM creation

2. CSS Download & Parsing β†’ CSSOM creation (render-blocking)

3. JavaScript Download & Execution (often render-blocking)

4. Render Tree Construction (DOM + CSSOM)

5. Layout β†’ Paint β†’ Composite

Let’s break these down in detail πŸ‘‡


🧡 2. Detailed CRP Steps & What Blocks Rendering

Step 1 β€” Load HTML & Build the DOM

What happens:

  • Browser downloads the HTML file.
  • Parses tags sequentially (top β†’ bottom).
  • Builds the DOM tree incrementally.

Render blocking?
❌ HTML itself is not render-blocking.
BUT:
βœ” External <script> tags block HTML parsing unless they use defer or type="module".
βœ” External <link rel="stylesheet"> blocks rendering until CSS finishes downloading.


Step 2 β€” Load & Parse CSS β†’ Build CSSOM

What happens:

  • Browser downloads all CSS files.
  • Parses them β†’ builds CSSOM.

Render blocking?
βœ” CSS is always render-blocking
βœ” Browser will not paint anything until CSSOM is ready
βœ” This is why CSS-in-JS slows down first paint

Because:
Browser needs CSS rules to compute layout safely.


Step 3 β€” Load & Execute JavaScript

What happens:

  • Browser downloads JS bundles.
  • Parses + executes them on the main thread.

Render blocking?
πŸ”Έ Inline & external JS (without defer or module) BLOCK HTML parsing.
πŸ”Έ Even deferred JS is execution-blocking for CSR frameworks.

Why?
React/Vue need to execute the main JS bundle to generate the UI.


Step 4 β€” Build Render Tree (DOM + CSSOM)

Browser merges:

  • DOM
  • CSSOM

Render tree is built β†’ only visible nodes with computed styles.

Render blocking?
βœ” Requires DOM & CSSOM (so CSS blocks rendering).
❌ Does NOT need JS unless JS mutates DOM (CSR apps do this).


Step 5 β€” Layout β†’ Paint β†’ Composite

Browser computes:

  • Size
  • Position
  • Colors
  • Layers

Then paints pixels on screen.

Render blocking?
βœ” Happens only after DOM + CSSOM + JS ready
βœ” Extra style recalculations or forced reflows can delay painting


πŸ›οΈ 3. The Main JavaScript Bundle β€” What’s Actually Inside?

This is the biggest performance bottleneck in CSR apps.

Your main JS bundle contains:

1. The framework runtime

  • React / Vue core libraries
  • Reconciliation logic
  • Virtual DOM implementation

2. All your components

Each component is:

  • JS functions (React)
  • Compiled templates β†’ render functions (Vue)

3. Router & route components

SPA routing logic is inside the bundle.

4. Application bootstrap code

For React:

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
Enter fullscreen mode Exit fullscreen mode

For Vue:

createApp(App).mount("#app");
Enter fullscreen mode Exit fullscreen mode

5. State management, utilities, and 3rd-party libraries

  • redux, zustand, jotai
  • axios
  • lodash
  • charts, maps, etc.

6. CSS-in-JS runtime (if used)

styled-components / emotion:

  • Parse JS styles
  • Generate CSS
  • Inject <style> tags dynamically
  • This blocks render tree creation

7. Code needed for hydration (only SSG/SSR)

React/Vue inject interactivity into existing HTML.


βš›οΈ 4. Critical Render Path in React CSR

🏁 Initial HTML

React CSR apps ship almost empty HTML:

<body>
  <div id="root"></div>
  <script src="/assets/main.js"></script>
</body>
Enter fullscreen mode Exit fullscreen mode

No UI. Just root.


πŸ”„ React CSR CRP Workflow

Step 1: HTML β†’ Empty DOM

Browser sees only a <div id="root">.

Step 2: CSS Blocks Render

Global CSS / Tailwind downloaded and parsed.

Step 3: JS Blocks Interactivity

Browser runs the main bundle:

  • Initializes React runtime
  • Builds virtual DOM
  • Runs components
  • Reconciles to real DOM
  • Injects DOM into #root

🎯 Only now the UI appears.

Render-blocking in React CSR:

What Blocks? Why
CSS files βœ” Yes Needed to compute styles
JS main bundle βœ” Yes UI depends on React runtime
CSS-in-JS βœ” Extra blocking Needs JS to generate CSS
Tailwind βœ” Large CSS can slow CSSOM

🧩 CSS Scenarios in React CSR

Global CSS

➑️ Render-blocking but fast
➑️ CSSOM ready early

CSS Modules

➑️ Compiled into global CSS
➑️ Same CRP as global CSS

Tailwind CSS

➑️ Large CSS file
➑️ Slower CSSOM build

CSS-in-JS

➑️ Slowest
➑️ JS must run to create styles
➑️ Inject <style> tags after render
➑️ Causes layout thrashing


🌿 5. Critical Render Path in Vue CSR

Vue CSR is similar but with key differences:

  • Templates are pre-compiled into render functions
  • Scoped CSS introduces attribute selectors (slightly slower)

🏁 Initial HTML

<body>
  <div id="app"></div>
  <script src="/main.js"></script>
</body>
Enter fullscreen mode Exit fullscreen mode

πŸ”„ Vue CSR CRP Workflow

Step 1 β€” HTML β†’ DOM with empty root

Step 2 β€” Global CSS renders

Step 3 β€” JS executes

  • Vue runtime starts
  • Templates (compiled to render functions) execute
  • Virtual DOM created
  • Vue mounts to #app
  • Scoped styles applied

Vue has smaller runtime & faster template execution.


🧩 CSS Scenarios in Vue CSR

Global CSS

➑️ Fastest

Scoped CSS

➑️ Uses attributes like [data-v-123abc]
➑️ Slightly slower CSSOM

CSS Modules in Vue

➑️ Similar to JS frameworks
➑️ Compiled into global CSS

CSS-in-JS

➑️ Rare in Vue but slow like React

Tailwind

➑️ Same implications as React


πŸ₯‡ 6. CSR vs SSG vs SSR β€” CRP Comparison

Mode Initial HTML FCP JS Need Hydration Best For
CSR Empty shell Slowest Mandatory ❌ No Internal apps
SSG Pre-rendered Fast Needed for interactivity βœ” Yes Blogs/docs/marketing
SSR Server-rendered Fast Needed for interactivity βœ” Yes Dynamic pages (dashboards)

🧱 7. What Changes in SSG?

SSG = HTML generated at build time.

SSG CRP:

  1. Browser downloads full HTML (content visible immediately)
  2. CSSOM parsed
  3. Browser paints early = fast FCP
  4. JS loads later β†’ hydration
  5. App becomes interactive

🎯 Content visible early
❌ Interaction delayed


🧱 8. What Changes in SSR?

SSR = HTML generated on server per request.

SSR CRP:

  1. Browser receives pre-rendered HTML
  2. DOM built immediately
  3. CSS render-blocking
  4. Early paint
  5. JS hydrates to make it interactive

🎯 Best FCP
⚠️ Hydration is heavy β†’ may hurt TTI


πŸ“Œ 9. Commonly Overlooked CRP Realities in SPA Apps

1. JavaScript is the biggest performance bottleneck

CSR requires JS to create UI β†’ slow on low-end devices.

2. Hydration is expensive in SSR/SSG

More components = slower hydration = poor TTI.

3. CSS-in-JS is always slower

  • Execution cost
  • Style injection
  • Extra layout & paint cycles

4. Tailwind improves maintainability but affects CSSOM size

Large CSS file blocking rendering.

5. Rendering depends on device capability

JS execution time is 10Γ— slower on low-end Android devices.


πŸŽ‰ Final Summary

React CSR

  • Empty HTML
  • JS must run to render UI
  • CSS strategies heavily affect CRP

Vue CSR

  • Similar to React but template compilation is faster
  • Scoped CSS adds minor cost

SSG

  • Best FCP
  • Requires hydration

SSR

  • Early paint
  • Heavy hydration

Understanding CRP helps you optimize what truly matters:

  • Reduce JS bundle size
  • Avoid CSS-in-JS unless necessary
  • Prefer SSR/SSG for public-facing pages
  • Minimize CSS blocking

Top comments (0)