pages

Nuxt는 파일 기반 라우팅을 제공하여 웹 애플리케이션 내에서 라우트를 생성할 수 있습니다.
애플리케이션의 번들 크기를 줄이기 위해, 이 디렉토리는 선택적입니다. 즉, app.vue만 사용할 경우 vue-router가 포함되지 않습니다. pages 시스템을 강제로 사용하려면 nuxt.config에서 pages: true를 설정하거나 app/router.options.ts를 추가하세요.

사용법

페이지는 Vue 컴포넌트이며 Nuxt가 지원하는 유효한 확장자를 가질 수 있습니다(기본적으로 .vue, .js, .jsx, .mjs, .ts 또는 .tsx).

Nuxt는 ~/pages/ 디렉토리 내의 모든 페이지에 대해 자동으로 라우트를 생성합니다.

<template>
  <h1>Index page</h1>
</template>

pages/index.vue 파일은 애플리케이션의 / 라우트에 매핑됩니다.

app.vue를 사용하는 경우, 현재 페이지를 표시하려면 <NuxtPage/> 컴포넌트를 사용해야 합니다:

app.vue
<template>
  <div>
    <!-- 모든 페이지에서 공유되는 마크업, 예: NavBar -->
    <NuxtPage />
  </div>
</template>

페이지는 반드시 하나의 루트 엘리먼트만 가져야 하며, 페이지 간 라우트 전환을 가능하게 합니다. HTML 주석도 엘리먼트로 간주됩니다.

즉, 라우트가 서버에서 렌더링되거나 정적으로 생성될 때는 내용을 올바르게 볼 수 있지만, 클라이언트 사이드 내비게이션 중 해당 라우트로 이동하면 라우트 전환이 실패하고 해당 라우트가 렌더링되지 않습니다.

다음은 단일 루트 엘리먼트를 가진 페이지의 예시입니다:

<template>
  <div>
    <!-- 이 페이지는 올바르게 하나의 루트 엘리먼트만 가집니다 -->
    Page content
  </div>
</template>

동적 라우트

대괄호 안에 무언가를 넣으면, 동적 라우트 파라미터로 변환됩니다. 여러 파라미터와 동적이 아닌 텍스트를 파일명이나 디렉토리 내에서 혼합하여 사용할 수 있습니다.

파라미터를 _선택적_으로 만들고 싶다면, 이중 대괄호로 감싸야 합니다. 예를 들어, ~/pages/[[slug]]/index.vue 또는 ~/pages/[[slug]].vue//test 모두에 매칭됩니다.

디렉토리 구조
-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue

위 예시에서, 컴포넌트 내에서 $route 객체를 통해 group/id에 접근할 수 있습니다:

pages/users-[group]/[id].vue
<template>
  <p>{{ $route.params.group }} - {{ $route.params.id }}</p>
</template>

/users-admins/123로 이동하면 다음과 같이 렌더링됩니다:

<p>admins - 123</p>

Composition API를 사용하여 라우트에 접근하고 싶다면, Options API의 this.$route처럼 라우트에 접근할 수 있는 전역 useRoute 함수가 있습니다.

<script setup lang="ts">
const route = useRoute()

if (route.params.group === 'admins' && !route.params.id) {
  console.log('경고! 사용자가 인증되었는지 확인하세요!')
}
</script>
이름이 지정된 부모 라우트가 중첩된 동적 라우트보다 우선합니다. /foo/hello 라우트의 경우, ~/pages/foo.vue~/pages/foo/[slug].vue보다 우선합니다.
/foo/foo/hello를 서로 다른 페이지로 매칭하려면 ~/pages/foo/index.vue~/pages/foo/[slug].vue를 사용하세요.

캐치-올 라우트

캐치-올 라우트가 필요하다면 [...slug].vue와 같은 파일명을 사용하여 생성할 수 있습니다. 이 파일은 해당 경로 아래의 모든 라우트와 매칭됩니다.

pages/[...slug].vue
<template>
  <p>{{ $route.params.slug }}</p>
</template>

/hello/world로 이동하면 다음과 같이 렌더링됩니다:

<p>["hello", "world"]</p>

중첩 라우트

<NuxtPage>를 사용하여 중첩 라우트를 표시할 수 있습니다.

예시:

디렉토리 구조
-| pages/
---| parent/
-----| child.vue
---| parent.vue

이 파일 트리는 다음과 같은 라우트를 생성합니다:

[
  {
    path: '/parent',
    component: '~/pages/parent.vue',
    name: 'parent',
    children: [
      {
        path: 'child',
        component: '~/pages/parent/child.vue',
        name: 'parent-child'
      }
    ]
  }
]

child.vue 컴포넌트를 표시하려면, pages/parent.vue 내부에 <NuxtPage> 컴포넌트를 삽입해야 합니다:

pages/parent.vue
<template>
  <div>
    <h1>나는 부모 뷰입니다</h1>
    <NuxtPage :foobar="123" />
  </div>
</template>
pages/parent/child.vue
<script setup lang="ts">
const props = defineProps(['foobar'])

console.log(props.foobar)
</script>

자식 라우트 키

<NuxtPage> 컴포넌트가 다시 렌더링되는 시점을 더 세밀하게 제어하고 싶다면, pageKey prop을 통해 문자열이나 함수를 전달하거나, definePageMeta를 통해 key 값을 정의할 수 있습니다:

pages/parent.vue
<template>
  <div>
    <h1>나는 부모 뷰입니다</h1>
    <NuxtPage :page-key="route => route.fullPath" />
  </div>
</template>

또는 다음과 같이 할 수도 있습니다:

pages/parent/child.vue
<script setup lang="ts">
definePageMeta({
  key: route => route.fullPath
})
</script>
Read and edit a live example in Docs > Examples > Routing > Pages.

라우트 그룹

경우에 따라 파일 기반 라우팅에 영향을 주지 않으면서 라우트 집합을 그룹화하고 싶을 수 있습니다. 이를 위해 괄호 - ()로 감싼 폴더에 파일을 넣을 수 있습니다.

예시:

디렉토리 구조
-| pages/
---| index.vue
---| (marketing)/
-----| about.vue
-----| contact.vue

이렇게 하면 앱에 /, /about, /contact 페이지가 생성됩니다. marketing 그룹은 URL 구조상 무시됩니다.

페이지 메타데이터

앱의 각 라우트에 대한 메타데이터를 정의하고 싶을 수 있습니다. <script> 또는 <script setup>에서 사용할 수 있는 definePageMeta 매크로를 사용하여 이를 할 수 있습니다:

<script setup lang="ts">
definePageMeta({
  title: '나의 홈 페이지'
})
</script>

이 데이터는 앱의 나머지 부분에서 route.meta 객체를 통해 접근할 수 있습니다.

<script setup lang="ts">
const route = useRoute()

console.log(route.meta.title) // 나의 홈 페이지
</script>

중첩 라우트를 사용하는 경우, 이들 라우트의 페이지 메타데이터는 모두 하나의 객체로 병합됩니다. 라우트 메타에 대한 자세한 내용은 vue-router 문서를 참고하세요.

defineEmitsdefineProps(참고: Vue 문서)처럼, definePageMeta컴파일러 매크로입니다. 컴포넌트 내에서 참조할 수 없도록 컴파일 시 제거됩니다. 대신, 전달된 메타데이터는 컴포넌트 외부로 끌어올려집니다. 따라서, 페이지 메타 객체는 컴포넌트를 참조할 수 없습니다. 하지만, 임포트된 바인딩이나 로컬에서 정의된 순수 함수는 참조할 수 있습니다.

반응형 데이터나 부작용을 일으키는 함수를 참조하지 않도록 주의하세요. 예기치 않은 동작이 발생할 수 있습니다.
<script setup lang="ts">
import { someData } from '~/utils/example'

function validateIdParam(route) {
  return route.params.id && !isNaN(Number(route.params.id))
}

const title = ref('')

definePageMeta({
  validate: validateIdParam,
  someData,
  title,    // 이렇게 하면 안 됩니다. ref가 컴포넌트 밖으로 끌어올려집니다.
})
</script>

특수 메타데이터

물론, 앱 전반에서 자유롭게 사용할 수 있는 메타데이터를 정의할 수 있습니다. 하지만 definePageMeta로 정의된 일부 메타데이터는 특별한 목적을 가집니다:

alias

페이지 별칭을 정의할 수 있습니다. 이를 통해 서로 다른 경로에서 동일한 페이지에 접근할 수 있습니다. vue-router 문서에 정의된 대로 문자열 또는 문자열 배열이 될 수 있습니다.

keepalive

definePageMeta에서 keepalive: true를 설정하면 Nuxt가 페이지를 Vue <KeepAlive> 컴포넌트로 자동 래핑합니다. 예를 들어, 동적 자식 라우트가 있는 부모 라우트에서 라우트 변경 시 페이지 상태를 유지하고 싶을 때 유용합니다.

부모 라우트의 상태를 유지하려면 <NuxtPage keepalive /> 구문을 사용하세요. <KeepAlive>에 전달할 props도 설정할 수 있습니다(전체 목록 보기).

이 속성의 기본값은 nuxt.config에서 설정할 수 있습니다.

key

위에서 보기.

layout

라우트 렌더링에 사용할 레이아웃을 정의할 수 있습니다. false(레이아웃 비활성화), 문자열, 또는 반응형으로 만들고 싶다면 ref/computed가 될 수 있습니다. 레이아웃에 대해 더 알아보기.

layoutTransitionpageTransition

페이지와 레이아웃을 감싸는 <transition> 컴포넌트에 대한 전환 속성을 정의하거나, 해당 라우트에 대해 <transition> 래퍼를 비활성화하려면 false를 전달할 수 있습니다. 전달 가능한 옵션 목록 또는 전환 동작에 대해 더 알아보기를 참고하세요.

이 속성의 기본값은 nuxt.config에서 설정할 수 있습니다.

middleware

이 페이지를 로드하기 전에 적용할 미들웨어를 정의할 수 있습니다. 일치하는 모든 부모/자식 라우트에서 사용된 다른 미들웨어와 병합됩니다. 문자열, 함수(글로벌 before 가드 패턴을 따르는 익명/인라인 미들웨어 함수), 또는 문자열/함수 배열이 될 수 있습니다. 이름이 지정된 미들웨어에 대해 더 알아보기.

name

이 페이지의 라우트에 이름을 정의할 수 있습니다.

path

파일명으로 표현할 수 없는 더 복잡한 패턴이 필요한 경우, 경로 매처를 정의할 수 있습니다. 자세한 내용은 vue-router 문서를 참고하세요.

props

라우트 params를 페이지 컴포넌트에 전달되는 props로 접근할 수 있게 해줍니다. 자세한 내용은 vue-router 문서를 참고하세요.

커스텀 메타데이터 타입 지정

페이지에 커스텀 메타데이터를 추가하는 경우, 타입 안전하게 하고 싶을 수 있습니다. definePageMeta에서 허용하는 객체의 타입을 확장할 수 있습니다:

index.d.ts
declare module '#app' {
  interface PageMeta {
    pageType?: string
  }
}

// 타입을 확장할 때는 항상 무언가를 import/export 해야 합니다
export {}

내비게이션

앱의 페이지 간 내비게이션을 위해서는 <NuxtLink> 컴포넌트를 사용해야 합니다.

이 컴포넌트는 Nuxt에 기본 포함되어 있으므로, 다른 컴포넌트처럼 import할 필요가 없습니다.

pages 폴더의 index.vue 페이지로 이동하는 간단한 링크 예시:

<template>
  <NuxtLink to="/">Home page</NuxtLink>
</template>
<NuxtLink> 사용법에 대해 더 알아보기.

프로그래밍 방식 내비게이션

Nuxt는 navigateTo() 유틸리티 메서드를 통해 프로그래밍 방식의 내비게이션을 허용합니다. 이 유틸리티 메서드를 사용하면 앱 내에서 사용자를 프로그래밍적으로 이동시킬 수 있습니다. 이는 사용자 입력을 받아 동적으로 내비게이션할 때 유용합니다. 아래 예시에서는 사용자가 검색 폼을 제출할 때 호출되는 navigate()라는 간단한 메서드가 있습니다.

항상 navigateToawait 하거나 함수에서 반환하여 결과를 체이닝하세요.
<script setup lang="ts">
const name = ref('');
const type = ref(1);

function navigate(){
  return navigateTo({
    path: '/search',
    query: {
      name: name.value,
      type: type.value
    }
  })
}
</script>

클라이언트 전용 페이지

.client.vue 접미사를 붙여 클라이언트 전용 페이지로 정의할 수 있습니다. 이 페이지의 내용은 서버에서 렌더링되지 않습니다.

서버 전용 페이지

.server.vue 접미사를 붙여 서버 전용 페이지로 정의할 수 있습니다. 클라이언트 사이드 내비게이션(즉, vue-router로 제어)으로 해당 페이지로 이동할 수 있지만, 자동으로 서버 컴포넌트로 렌더링되므로 페이지 렌더링에 필요한 코드는 클라이언트 번들에 포함되지 않습니다.

서버 전용 페이지는 반드시 하나의 루트 엘리먼트만 가져야 합니다. (HTML 주석도 엘리먼트로 간주됩니다.)

커스텀 라우팅

앱이 커지고 복잡해질수록 라우팅에 더 많은 유연성이 필요할 수 있습니다. 이를 위해 Nuxt는 라우터, 라우트, 라우터 옵션을 다양한 방식으로 직접 커스터마이즈할 수 있도록 노출합니다.

Read more in Docs > Guide > Recipes > Custom Routing.

다중 페이지 디렉토리

기본적으로 모든 페이지는 프로젝트 루트의 하나의 pages 디렉토리에 있어야 합니다.

하지만, Nuxt Layers를 사용하여 앱의 페이지를 그룹화할 수 있습니다:

디렉토리 구조
-| some-app/
---| nuxt.config.ts
---| pages/
-----| app-page.vue
-| nuxt.config.ts
some-app/nuxt.config.ts
// some-app/nuxt.config.ts
export default defineNuxtConfig({
})
nuxt.config.ts
export default defineNuxtConfig({
  extends: ['./some-app'],
})
Read more in Docs > Guide > Going Further > Layers.