pages

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

Usage

페이지는 Vue 컴포넌트이며 Nuxt가 지원하는 모든 유효한 확장자를 사용할 수 있습니다(기본값은 .vue, .js, .jsx, .mjs, .ts 또는 .tsx).

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

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

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

app.vue를 사용하는 경우, 현재 페이지를 표시하기 위해 <NuxtPage/> 컴포넌트를 사용하는 것을 잊지 마세요:

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

페이지는 페이지 간 라우트 전환을 허용하기 위해 반드시 하나의 루트 요소만 가져야 합니다. HTML 주석도 요소로 간주됩니다.

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

다음은 단일 루트 요소를 가진 페이지가 어떻게 보이는지 설명하는 몇 가지 예시입니다:

<template>
  <div>
    <!-- 이 페이지는 올바르게 하나의 루트 요소만 가지고 있습니다 -->
    Page content
  </div>
</template>

Dynamic Routes

대괄호 안에 무언가를 넣으면 동적 라우트 파라미터로 변환됩니다. 파일 이름이나 디렉터리 내에서 여러 파라미터와 비동적 텍스트를 섞어서 사용할 수 있습니다.

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

Directory Structure
-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue

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

app/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('Warning! Make sure user is authenticated!')
}
</script>
명명된 부모 라우트는 중첩된 동적 라우트보다 우선합니다. /foo/hello 라우트의 경우, ~/pages/foo.vue~/pages/foo/[slug].vue보다 우선합니다.
/foo/foo/hello를 서로 다른 페이지로 매칭하려면 ~/pages/foo/index.vue~/pages/foo/[slug].vue를 사용하세요,.

Catch-all Route

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

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

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

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

Nested Routes

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

예시:

Directory Structure
-| 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 컴포넌트를 표시하려면, app/pages/parent.vue 안에 <NuxtPage> 컴포넌트를 삽입해야 합니다:

pages/parent.vue
<template>
  <div>
    <h1>I am the parent view</h1>
    <NuxtPage :foobar="123" />
  </div>
</template>
pages/parent/child.vue
<script setup lang="ts">
const props = defineProps({
  foobar: String,
})

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

Child Route Keys

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

pages/parent.vue
<template>
  <div>
    <h1>I am the parent view</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 > 4 X > Examples > Routing > Pages.

Route Groups

경우에 따라, 파일 기반 라우팅에 영향을 주지 않는 방식으로 특정 라우트 집합을 그룹화하고 싶을 수 있습니다. 이를 위해, 괄호 - () - 로 감싸진 폴더 안에 파일을 넣을 수 있습니다.

예를 들어:

Directory structure
-| pages/
---| index.vue
---| (marketing)/
-----| about.vue
-----| contact.vue

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

Page Metadata

앱의 각 라우트에 대해 메타데이터를 정의하고 싶을 수 있습니다. 이는 definePageMeta 매크로를 사용하여 할 수 있으며, <script><script setup> 모두에서 동작합니다:

<script setup lang="ts">
definePageMeta({
  title: 'My home page',
})
</script>

이 데이터는 이후 앱의 다른 곳에서 route.meta 객체를 통해 접근할 수 있습니다.

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

console.log(route.meta.title) // My home page
</script>

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

defineEmits 또는 defineProps(참고: Vue 문서)와 마찬가지로, definePageMeta컴파일러 매크로입니다. 이는 컴파일 시 제거되므로, 컴포넌트 내에서 이를 참조할 수 없습니다. 대신, 여기에 전달된 메타데이터는 컴포넌트 밖으로 끌어올려집니다(hoist). 따라서 페이지 메타 객체는 컴포넌트를 참조할 수 없습니다. 그러나 가져온 바인딩(imported bindings)과 로컬에서 정의된 순수 함수는 참조할 수 있습니다.

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

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

const title = ref('')

definePageMeta({
  validate: validateIdParam,
  someData,
  title, // 이렇게 하지 마세요. ref는 컴포넌트 밖으로 끌어올려집니다
})
</script>

Special Metadata

물론, 앱 전반에서 자체적으로 사용할 메타데이터를 정의해도 됩니다. 하지만 definePageMeta로 정의된 일부 메타데이터는 특별한 목적을 가집니다:

alias

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

keepalive

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

부모 라우트의 상태를 유지하는 것이 목표라면, <NuxtPage keepalive /> 구문을 사용하세요. 또한 <KeepAlive>에 전달할 props를 설정할 수도 있습니다(전체 목록은 여기를 참고하세요).

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

key

위에서 보기.

layout

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

layoutTransition and pageTransition

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

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

middleware

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

name

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

path

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

props

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

Typing Custom Metadata

페이지에 커스텀 메타데이터를 추가하는 경우, 타입 안전한 방식으로 하고 싶을 수 있습니다. definePageMeta가 허용하는 객체의 타입을 보강(augment)하는 것이 가능합니다:

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

// 타입을 보강할 때는 항상 무언가를 import/export 하는 것이 중요합니다
export {}

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

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

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

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

Programmatic Navigation

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-Only Pages

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

Server-Only Pages

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

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

Custom Routing

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

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

Multiple Pages Directories

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

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

Directory Structure
-| 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 > 4 X > Guide > Going Further > Layers.