---
id: wiki-2026-0508-spa-라우트-전환-성능-최적화
title: SPA 라우트 전환 성능 최적화
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [SPA route transition perf, route transition optimization, SPA navigation perf]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [frontend, performance, spa, react, routing]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
  language: typescript
  framework: react
---

# SPA 라우트 전환 성능 최적화

## 매 한 줄
> **"매 route 전환은 매 사용자가 매 가장 자주 만나는 perf moment"**. SPA에서 매 route 전환 latency는 매 INP/Core Web Vitals에 매 직접 영향. 2026년에는 매 React Router 7, TanStack Router, Next 15 App Router가 매 표준이며, 매 streaming + prefetch + view-transitions가 매 키.

## 매 핵심

### 매 병목 분류
- **JS bundle**: 매 새 route chunk download/parse.
- **Data fetch**: 매 loader/query waterfall.
- **Render**: 매 new tree mount cost.
- **Asset**: 매 image/font 신규 load.

### 매 최적화 lever
- **Code-split** (route-level lazy).
- **Prefetch** (hover/viewport/intent).
- **Parallel data load** (loader pattern, no waterfall).
- **View Transitions API** (visual smoothing).
- **RSC streaming** (Next 15 App Router).

### 매 응용
1. 매 e-commerce: product list → detail 매 < 100ms 체감.
2. 매 dashboard: 매 widget data parallel.
3. 매 docs site: 매 instant hover prefetch.

## 💻 패턴

### 매 Route-level code split
```tsx
import { lazy, Suspense } from "react";
const Dashboard = lazy(() => import("./Dashboard"));

<Route path="/dashboard" element={
  <Suspense fallback={<Skeleton />}><Dashboard /></Suspense>
} />
```

### 매 Hover prefetch (TanStack Router)
```tsx
import { Link } from "@tanstack/react-router";
<Link to="/products/$id" params={{ id }} preload="intent">
  Product
</Link>
// 매 hover/focus → 매 chunk + loader data 미리.
```

### 매 Parallel loaders (waterfall 제거)
```tsx
// X — sequential
const route = createRoute({
  loader: async () => {
    const user = await fetchUser();   // 매 wait
    const orders = await fetchOrders(user.id); // 매 then wait
    return { user, orders };
  },
});

// O — parallel where possible
const route = createRoute({
  loader: async ({ params }) => {
    const [user, orders] = await Promise.all([
      fetchUser(params.id),
      fetchOrdersForId(params.id), // 매 user 의존 X로 변경
    ]);
    return { user, orders };
  },
});
```

### 매 View Transitions API
```tsx
// 매 navigation에 매 native cross-fade
import { unstable_ViewTransition as ViewTransition } from "react";

function App() {
  return (
    <ViewTransition>
      <Outlet />
    </ViewTransition>
  );
}
```

```css
::view-transition-old(root) { animation: fade-out 200ms; }
::view-transition-new(root) { animation: fade-in 200ms; }
```

### 매 RSC streaming (Next 15)
```tsx
// app/products/[id]/page.tsx
export default async function Page({ params }: { params: { id: string } }) {
  return (
    <>
      <ProductHeader id={params.id} /> {/* 매 빠른 part */}
      <Suspense fallback={<Skeleton />}>
        <ProductReviews id={params.id} /> {/* 매 느린 part stream */}
      </Suspense>
    </>
  );
}
```

### 매 Optimistic navigation
```tsx
// React 19 useOptimistic 응용
const [optimisticPath, setOptimisticPath] = useOptimistic(currentPath);

function navigate(to: string) {
  startTransition(() => {
    setOptimisticPath(to); // 매 즉시 UI 변경
    router.navigate(to);
  });
}
```

### 매 Bundle 분석 (rsdoctor / webpack-bundle-analyzer)
```bash
pnpm dlx @rsdoctor/cli analyze
# 매 route chunk 크기 매 visualize → 매 split point 매 결정
```

## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 small SPA | Route-split + hover prefetch. |
| 매 dashboard 다중 widget | Parallel loaders + Suspense streaming. |
| 매 SEO + perf | Next 15 App Router (RSC). |
| 매 highly interactive | TanStack Router + View Transitions. |
| 매 mobile-first | Aggressive prefetch는 매 신중 (data cost). |

**기본값**: Route-split + intent prefetch + parallel loaders. 매 modern routers는 매 default support.

## 🔗 Graph
- 부모: [[SPA]] · [[Web Performance]]
- 변형: [[Islands Architecture]]
- 응용: [[TanStack Router]]
- Adjacent: [[Core Web Vitals Optimization (INP, LCP 개선)|Core Web Vitals]] · [[INP]] · [[View Transitions]] · [[Code Splitting]]

## 🤖 LLM 활용
**언제**: 매 route 전환 매 느릴 때, 매 perf budget 책정, 매 prefetch 전략 설계.
**언제 X**: 매 MPA, 매 first-load 문제 (매 SSR/SSG 별도).

## ❌ 안티패턴
- **매 lazy 모든 component**: 매 too granular → 매 waterfall 악화.
- **매 prefetch 모든 link**: 매 모바일 데이터 burn.
- **매 loader에 매 sequential await**: 매 waterfall.
- **매 Suspense 없이 매 lazy**: 매 blank 화면.
- **매 view-transition 만 적용**: 매 underlying perf 안 고치고 cosmetic만.

## 🧪 검증 / 중복
- Verified (web.dev, React Router 7 docs, TanStack Router docs, Next 15 docs).
- 신뢰도 A.

## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 2026 router stack + View Transitions + RSC streaming |
