라우팅

라우팅 (Routing)

Nuxt의 가장 큰 특징 중 하나가 파일 시스템 라우팅이에요. app/pages/ 디렉터리 안에 Vue 파일을 하나 만들면, 그 파일 이름에 해당하는 URL(경로)이 자동으로 생깁니다. 경로를 별도로 등록하는 라우터 설정 없이, 페이지 파일을 만들고 지우는 것만으로 화면 전환이 정리되는 구조예요.

출처: 공식문서

본문

Nuxt는 파일 시스템 라우터를 써서 app/pages/ 디렉터리의 모든 Vue 파일이 대응하는 URL(route)을 만들게 해요. 각 페이지를 동적 임포트(dynamic import)로 불러오면서 코드 스플리팅(code-splitting)을 활용해, 요청된 경로에 필요한 만큼만 최소한의 자바스크립트를 전달하죠.

코드 스플리팅은 기본으로 켜져 있고 대부분의 앱에서 권장돼요. 굳이 단일 번들로 묶어야 할 이유가 있다면 nuxt.config에서 끌 수 있는데, 보통은 이득보다 초기 다운로드가 커져서 권장하지 않아요. 정말 도움이 된다고 측정했을 때만 꺼보세요.

// nuxt.config.ts
export default defineNuxtConfig({
  vite: {
    $client: {
      build: {
        rolldownOptions: {
          output: {
            codeSplitting: false,
          },
        },
      },
    },
  },
})

Pages

Nuxt 라우팅은 vue-router를 바탕으로 하고, app/pages/ 디렉터리에 만든 컴포넌트의 파일 이름을 기준으로 경로를 생성해요. 이 파일 시스템 라우팅은 이름 규칙을 이용해 동적·중첩 경로를 만들어 줘요.

-| pages/
---| about.vue
---| index.vue
---| posts/
-----| [id].vue

<NuxtLink> 컴포넌트가 페이지 사이를 이어줘요. 내부적으로 <a> 태그를 렌더링하는데, href는 해당 페이지의 경로로 설정되죠. 앱이 하이드레이션된 뒤에는 페이지 전환이 자바스크립트로 일어나서 브라우저 URL만 바뀌고, 전체 새로고침 없이 애니메이션 전환이 가능해요.

또 클라이언트에서 <NuxtLink>가 뷰포트에 들어오면, Nuxt가 연결된 페이지의 컴포넌트와 페이로드(생성된 페이지)를 미리 가져와서(prefetch) 더 빠르게 이동하게 도와줘요.

<!-- app/pages/index.vue -->
<template>
  <header>
    <nav>
      <ul>
        <li><NuxtLink to="/about">About</NuxtLink></li>
        <li><NuxtLink to="/posts/1">Post 1</NuxtLink></li>
        <li><NuxtLink to="/posts/2">Post 2</NuxtLink></li>
      </ul>
    </nav>
  </header>
</template>

Route Parameters

현재 경로 정보는 useRoute() 컴포저블로 접근해요. <script setup> 블록이나 Vue 컴포넌트의 setup() 메서드에서 쓸 수 있어요.

<!-- pages/posts/[id].vue -->
<script setup lang="ts">
const route = useRoute()

// /posts/1 에 접근하면 route.params.id 는 1
console.log(route.params.id)
</script>

Route Middleware

Nuxt는 특정 경로로 이동하기 전에 실행할 코드를 빼내기 좋은, 커스터마이즈 가능한 라우트 미들웨어 프레임워크를 제공해요. 이름이 비슷해서 헷갈리기 쉬운데, 이 라우트 미들웨어는 Vue 부분에서 돌아가며 서버에서 도는 Nitro 서버 미들웨어와는 완전히 달라요. 라우트 미들웨어는 서버 경로(예: /api/*)나 다른 서버 요청에는 돌지 않으니, 그런 요청에는 서버 미들웨어를 쓰세요.

라우트 미들웨어는 세 가지 종류가 있어요.

  • 익명(인라인) 미들웨어 — 사용하는 페이지 안에 직접 정의
  • 이름 있는 미들웨어app/middleware/ 디렉터리에 두고, 페이지에서 쓰일 때 비동기 임포트로 자동 로드. 이름은 kebab-case로 정규화되어 someMiddlewaresome-middleware가 돼요
  • 전역 미들웨어app/middleware/ 디렉터리에 .global 접미사를 붙여 두면, 모든 경로 변경마다 자동 실행

/dashboard 페이지를 보호하는 auth 미들웨어 예시를 볼게요.

// middleware/auth.ts
function isAuthenticated (): boolean { return false }

// ---cut---

export default defineNuxtRouteMiddleware((to, from) => {
  // isAuthenticated() 인증 여부를 확인하는 예시 메서드
  if (isAuthenticated() === false) {
    return navigateTo('/login')
  }
})

Route Validation

경로 검증도 지원해요. 검증하고 싶은 각 페이지에서 definePageMeta()validate 속성을 쓰면 돼요. validateroute를 인자로 받고, 이 페이지로 렌더링해도 되는 경로인지를 판단한 불리언 값을 돌려줘요. false를 돌려주면 404 에러가 나고, status/statusText가 담긴 객체를 직접 돌려주면 반환할 에러를 커스터마이즈할 수도 있어요. 더 복잡한 케이스라면 익명 라우트 미들웨어를 쓰면 돼요.

<!-- pages/posts/[id].vue -->
<script setup lang="ts">
definePageMeta({
  validate (route) {
    // id 가 숫자로만 이뤄졌는지 확인
    return typeof route.params.id === 'string' && /^\d+$/.test(route.params.id)
  },
})
</script>

더 알아보기

  • Pages · Middleware 등 파일 구조에 대한 내용은 Directory Structure 문서에서 다뤄요
  • <NuxtLink>useRoute(), definePageMeta()의 세부 옵션은 API 문서를 참고하세요