Docs
Guide
Code Splitting

Code Splitting

Code splitting과 lazy loading은 애플리케이션의 번들 크기와 로드 성능을 개선하는 강력한 기술입니다.

  • 초기 페이지 로드 시 로드해야 하는 코드 양을 줄입니다.
  • 요청이 있을 때 코드가 로드됩니다.
  • 더 작고 많은 청크로 나뉘어 브라우저가 쉽게 캐시할 수 있도록 합니다.

How does TanStack Router split code?

TanStack Router는 코드를 두 가지 범주로 나눕니다:

  • 중요 경로 구성 - 현재 경로를 렌더링하고 데이터를 가능한 빨리 로드하기 위해 필요한 코드입니다.

    • 경로 파싱/직렬화
    • 검색 매개변수 검증
    • 로더 및 사전 로드
    • 경로 컨텍스트
    • 정적 데이터
    • 링크
    • 스크립트
    • 스타일
    • 위에 나열되지 않은 모든 경로 구성
  • 비중요/지연 경로 구성 - 경로를 매칭하는 데 필요하지 않으며, 온디맨드로 로드할 수 있는 코드입니다.

    • 경로 컴포넌트
    • 에러 컴포넌트
    • 대기 컴포넌트
    • 404 컴포넌트

🧠 로더를 분할하지 않는 이유?

  • 로더는 이미 비동기 경계이므로, 청크를 가져오고 로더를 실행하는 데 두 배의 비용이 듭니다.

  • 로더는 컴포넌트보다 번들 크기에 기여할 가능성이 적습니다.

  • 기본 사전 로드 방식(예: 링크 위로 마우스를 올리는 경우)을 사용하는 경우, 로더는 경로에 가장 중요한 사전 로드 가능한 자산 중 하나이므로 추가 비동기 오버헤드 없이 사용할 수 있어야 합니다.

    로더를 분할하는 단점을 이해하고도 진행하고 싶다면 Data Loader Splitting 섹션을 참고하세요.

Approaches to code splitting

TanStack Router는 다양한 코드 분할 방법을 지원합니다. 코드 기반 라우팅을 사용하는 경우 Code-Based Splitting 섹션으로 바로 이동하세요.

파일 기반 라우팅을 사용하는 경우, 다음과 같은 방법으로 코드 분할을 사용할 수 있습니다:

Encapsulating a route's files into a directory

TanStack Router의 파일 기반 라우팅 시스템은 평면 및 중첩 파일 구조를 모두 지원하므로, 추가 구성 없이 경로 파일을 단일 디렉토리로 캡슐화할 수 있습니다.

경로 파일을 디렉토리로 캡슐화하려면, 경로 파일 자체를 동일한 이름의 디렉토리 안에 .route 파일로 이동합니다.

예를 들어, posts.tsx라는 경로 파일이 있다면, 새 디렉토리 posts를 만들고, posts.tsx 파일을 그 디렉토리로 이동한 후 이름을 route.tsx로 변경합니다.

변경 전

  • posts.tsx
  • posts.lazy.tsx

변경 후

  • posts
    • route.tsx
    • route.lazy.tsx

Using the .lazy.tsx suffix

파일 기반 라우팅을 사용하는 경우, .lazy.tsx 접미사를 사용해 코드를 별도의 파일로 이동하고, FileRoute 클래스나 createFileRoute 함수 대신 createLazyFileRoute 함수를 사용하면 코드 분할이 매우 간단해집니다.

createLazyFileRoute 함수에서 현재 지원하는 옵션은 다음과 같습니다:

Export NameDescription
component경로에 대해 렌더링할 컴포넌트입니다.
errorComponent경로 로드 중 에러가 발생할 때 렌더링할 컴포넌트입니다.
pendingComponent경로가 로드되는 동안 렌더링할 컴포넌트입니다.
notFoundComponent404 에러가 발생했을 때 렌더링할 컴포넌트입니다.

Exceptions to the .lazy.tsx rule

  • __root.tsx 경로 파일은 항상 렌더링되므로 코드 분할을 지원하지 않습니다.

Example code splitting with .lazy.tsx

.lazy.tsx를 사용할 때 경로를 두 파일로 나누어 코드 분할을 활성화할 수 있습니다.

변경 전 (단일 파일)

// src/routes/posts.tsx
import { createFileRoute } from "@tanstack/react-router";
import { fetchPosts } from "./api";
 
export const Route = createFileRoute("/posts")({
  loader: fetchPosts,
  component: Posts,
});
 
function Posts() {
  // ...
}

변경 후 (두 파일로 분리)

다음 파일은 중요 경로 구성을 포함합니다:

// src/routes/posts.tsx
 
import { createFileRoute } from "@tanstack/react-router";
import { fetchPosts } from "./api";
 
export const Route = createFileRoute("/posts")({
  loader: fetchPosts,
});

비중요 경로 구성은 .lazy.tsx 접미사를 사용하는 파일로 이동합니다:

// src/routes/posts.lazy.tsx
import { createLazyFileRoute } from "@tanstack/react-router";
 
export const Route = createLazyFileRoute("/posts")({
  component: Posts,
});
 
function Posts() {
  // ...
}

Using Virtual Routes

경로 파일의 모든 내용을 분리하여 파일이 비게 되는 경우, 해당 경로 파일을 삭제하면 됩니다. 이 경우 가상 경로가 자동으로 생성되어 코드 분할 파일의 앵커 역할을 합니다. 이 가상 경로는 생성된 경로 트리 파일 내에 위치합니다.

변경 전 (가상 경로)

// src/routes/posts.tsx
import { createFileRoute } from "@tanstack/react-router";
 
export const Route = createFileRoute("/posts")({
  // Hello?
});
// src/routes/posts.lazy.tsx
import { createLazyFileRoute } from "@tanstack/react-router";
 
export const Route = createLazyFileRoute("/posts")({
  component: Posts,
});
 
function Posts() {
  // ...
}

변경 후 (가상 경로)

// src/routes/posts.lazy.tsx
import { createLazyFileRoute } from "@tanstack/react-router";
 
export const Route = createLazyFileRoute("/posts")({
  component: Posts,
});
 
function Posts() {
  // ...
}

짜잔! 🎉

Using automatic code-splitting

autoCodeSplitting 기능을 사용할 때, TanStack Router는 위에서 언급한 비중요 경로 구성에 따라 경로 파일을 자동으로 코드 분할합니다.

[!IMPORTANT] 자동 코드 분할 기능은 지원되는 번들러와 파일 기반 라우팅에서만 작동합니다. CLI(@tanstack/router-cli)만 사용하는 경우 작동하지 않습니다.

이 과정을 계속 읽어보며 자세히 이해할 수 있습니다.

Code-Based Splitting

Manually Splitting Using route.lazy() and createLazyRoute

파일 기반 라우팅 시스템을 사용하지 않는 경우에도 route.lazy() 메서드와 createLazyRoute 함수를 사용하여 수동으로 코드를 분할할 수 있습니다. 다음 단계를 따르세요:

createLazyRoute 함수를 사용하여 lazy 경로를 생성합니다.

// src/posts.tsx
export const Route = createLazyRoute("/posts")({
  component: MyComponent,
});
 
function MyComponent() {
  return <div>My Component</div>;
}

그런 다음, app.tsx 파일에서 경로 정의에 .lazy 메서드를 호출하여 비중요 경로 구성과 함께 lazy/코드 분할된 경로를 가져옵니다.

// src/app.tsx
const postsRoute = createRoute({
  getParent: () => rootRoute,
  path: "/posts",
}).lazy(() => import("./posts.lazy").then((d) => d.Route));

Data Loader Splitting

⚠️ 데이터 로더를 분할하면 로더 데이터를 가져오기 위해 서버로 두 번의 왕복이 필요합니다. 첫 번째 왕복은 로더 코드 번들을 로드하기 위한 것이고, 두 번째 왕복은 로더 코드를 실행하고 데이터를 가져오기 위한 것입니다. 로더가 번들 크기에 충분히 기여하여 이러한 왕복이 필요하다고 확신하지 않는 한 진행하지 마세요.

Route의 loader 옵션을 사용하여 데이터 로딩 로직을 코드 분할할 수 있습니다. 이 과정은 로더에 전달된 매개변수의 타입 안전성을 유지하기 어렵게 만들지만, 일반적인 LoaderContext 타입을 사용하여 대부분의 문제를 해결할 수 있습니다:

import { LoaderContext } from "@tanstack/react-router";
 
const route = createRoute({
  path: "/my-route",
  component: MyComponent,
  loader: (...args) => import("./loader").then((d) => d.loader(...args)),
});
 
// 다른 파일에서...
export const loader = async (context: LoaderContext) => {
  /// ...
};

이 과정은 다소 복잡하게 느껴질 수 있으므로, TanStack Router는 이를 단순화하는 lazyFn이라는 유틸리티를 제공합니다. 이는 lazyRouteComponent와 매우 유사합니다.

import { lazyFn } from "@tanstack/react-router";
 
const route = createRoute({
  path: "/my-route",
  component: MyComponent,
  loader: lazyFn(() => import("./loader"), "loader"),
});
 
// 다른 파일에서...
export const loader = async (context: LoaderContext) => {
  /// ...
};

Manually accessing Route APIs in other files with the getRouteApi helper

컴포넌트 코드를 경로와 다른 파일에 배치하면 경로 자체를 사용하는 것이 어려울 수 있습니다. 이를 돕기 위해, TanStack Router는 getRouteApi라는 유용한 함수를 제공합니다. 이를 사용하면 경로를 가져오지 않고도 타입 안전한 API에 접근할 수 있습니다.

  • my-route.tsx
import { createRoute } from "@tanstack/react-router";
import { MyComponent } from "./MyComponent";
 
const route = createRoute({
  path: "/my-route",
  loader: () => ({
    foo: "bar",
  }),
  component: MyComponent,
});
  • MyComponent.tsx
import { getRouteApi } from "@tanstack/react-router";
 
const route = getRouteApi("/my-route");
 
export function MyComponent() {
  const loaderData = route.useLoaderData();
  //    ^? { foo: string }
 
  return <div>...</div>;
}

getRouteApi 함수는 다음과 같은 다른 타입 안전한 API에 접근하는 데 유용합니다:

  • useLoaderData
  • useLoaderDeps
  • useMatch
  • useParams
  • useRouteContext
  • useSearch