• Home
  • About
  • Agent Skills
  • Projects
  • Blog
  • Contact
Resume
Naser Rasouli

Author

Naser Rasouli

Front-End developer - sharing lessons learned, notes, and write-ups from real projects.

GitHubLinkedIn

Last posts

Optimistic UI in React Without the Common Bugs
2026-09-11•1 min read

Optimistic UI in React Without the Common Bugs

A practical React optimistic UI pattern using useOptimistic, transitions, failure recovery, and server reconciliation without duplicating authoritative state.

Debugging INP in React Apps: From Field Data to Profiler
2026-09-10•1 min read

Debugging INP in React Apps: From Field Data to Profiler

A practical workflow for tracing slow React interactions from field data and long tasks to event handlers, React renders, and main-thread work.

JavaScript SEO for React: What Google Actually Sees
2026-09-10•1 min read

JavaScript SEO for React: What Google Actually Sees

A practical React SEO guide to crawling, rendering, indexing, SSR and prerendering, internal links, metadata, and client-rendered content.

How to Diagnose Slow Vite Projects

How to Diagnose Slow Vite Projects

2026-09-07
viteperformancefrontendtoolingbuild

How to Diagnose Slow Vite Projects

Vite is usually extremely fast in small projects. As a codebase grows, more plugins, heavier dependencies, monorepo links, and thousands of modules can turn startup, HMR, or production builds into real bottlenecks.

The common mistake is to tune configuration before measuring. A better workflow is:

Measure → Isolate → Profile → Change → Remeasure

Define what is slow

"Vite is slow" is not specific enough. Separate:

  1. cold dev-server startup;
  2. initial page load;
  3. HMR;
  4. production build.

Each stage can have a different root cause.

Record a baseline

Measure before changing configuration. Do not mix cold and warm runs, and keep the environment as stable as possible.

For dev-page issues, browser extensions and DevTools cache settings can also distort the result.

Inspect plugins

Vite exposes transform debugging:

vite --debug plugin-transform

Look for plugins that run across too many files or perform expensive work without narrow filters.

Important hooks include:

config
configResolved
buildStart
resolveId
load
transform

A small per-file transform cost can become significant across thousands of modules.

Inspect transform timing and import waterfalls

vite --debug transform

This helps reveal expensive files and deep dependency chains:

main.tsx
  ↓
Dashboard.tsx
  ↓
charts/index.ts
  ↓
heavy-chart-library

On-demand transforms are one of Vite's strengths, but a long chain can still create a waterfall.

Audit barrel files with evidence

Barrels are not automatically bad, but a very broad index.ts can expand the amount of graph that needs resolution.

Instead of:

import { formatMoney } from "@/utils"

sometimes a direct import is worth testing:

import { formatMoney } from "@/utils/format-money"

Only keep the change if the measurement supports it.

Capture CPU profiles

For development:

vite --profile --open

For builds:

vite build --profile

The generated .cpuprofile can show where CPU time is actually being spent.

Use server.warmup selectively

When a small set of expensive modules is always needed on the first route, targeted warmup can help:

export default defineConfig({
  server: {
    warmup: {
      clientFiles: [
        "./src/pages/dashboard.tsx",
        "./src/lib/heavy-utils.ts",
      ],
    },
  },
})

Do not warm the entire application. That simply moves the cost into startup.

Do not treat --force as a permanent fix

Dependency optimization is automatic. If a project constantly needs vite --force, investigate the actual cache invalidation or linked-dependency behavior.

What changed in Vite 8?

Vite 8, released in March 2026, moved to Rolldown as a unified bundler. The official Vite release describes substantial build-performance improvements.

That still does not replace profiling. A slow custom plugin or a pathological import graph remains real work even with a faster bundler.

Vite 8.1 also introduced an experimental bundled dev mode aimed at very large applications where module count itself is the bottleneck. It is not a default recommendation for normal projects.

A repeatable audit workflow

1. Scope

cold start:
first load:
HMR:
build:

2. Environment

  • Node version
  • Vite version
  • package manager
  • plugin list
  • monorepo/linking

3. Plugin timing

vite --debug plugin-transform

4. Transform timing

vite --debug transform

5. CPU profiling

vite --profile --open
vite build --profile

6. Make one targeted change

For example:

  • narrow a plugin filter;
  • remove expensive work from startup hooks;
  • replace a problematic barrel import;
  • warm a small hot set;
  • upgrade Vite.

7. Remeasure

If the before/after result is not measurable, do not claim a performance win.

Conclusion

Vite performance is primarily a profiling problem, not a collection of magic configuration flags:

Slow Vite
   ↓
Classify
   ↓
Measure plugins/transforms
   ↓
CPU profile
   ↓
Find bottleneck
   ↓
Targeted change
   ↓
Remeasure

That workflow produces a defensible result instead of a pile of random tweaks.

References

  • https://vite.dev/guide/performance
  • https://vite.dev/blog/announcing-vite8
  • https://vite.dev/blog/announcing-vite8-1