Nuxt는 웹 애플리케이션 내에서 경로를 생성하기 위한 파일 기반 라우팅을 제공한다.
애플리케이션의 번들 크기를 줄이기 위해 이 디렉터리는 선택 사항이다. 즉, app.vue만 사용하는 경우 vue-router가 포함되지 않는다. 페이지 시스템을 강제하려면 nuxt.config에서 페이지를 true로 설정하거나 app/router.options.ts를 설정하자.
페이지는 Vue 구성 요소이며 Nuxt가 지원하는 유효한 확장자(기본적으로 .vue, .js, .jsx, .mjs, .ts 또는 .tsx)를 가질 수 있다.
Nuxt는 ~/pages/ 디렉토리의 모든 페이지에 대한 경로를 자동으로 생성한다.
pages/index.vue
<!--
pages/index.vue
-->
<template>
<h1>Index page</h1>
</template>
pages/index.ts
// pages/index.ts
// https://vuejs.org/guide/extras/render-function.html
export default defineComponent({
render () {
return h('h1', 'Index page')
}
})
pages/index.tsx
// pages/index.tsx
// https://nuxt.com/docs/examples/advanced/jsx
// https://vuejs.org/guide/extras/render-function.html#jsx-tsx
export default defineComponent({
render () {
return <h1>Index page</h1>
}
})
pages/index.vue 파일은 애플리케이션 경로 '/' 에 매핑된다.
app.vue 을 사용하는 경우 <NuxtPage/> 컴포넌트를 사용하여 현재 페이지를 표시해야 한다.
app.vue
<!--
app.vue
-->
<template>
<div>
<!-- Markup shared across all pages, ex: NavBar -->
<NuxtPage />
</div>
</template>
페이지단일 루트 요소가 있어야 한다. 트랜지션 페이지 사이의 HTML 주석도 엘리먼트로 간주된다.
즉, 경로가 서버에서 렌더링되거나 정적으로 생성되면 내용을 올바르게 볼 수 있지만 클라이언트 측 탐색 중에 해당 경로를 탐색하면 경로 간 전환이 실패하고 경로가 렌더링되지 않는 걸 보게된다.
다음은 단일 루트 엘리먼트가 있는 페이지의 모습을 보여주는 몇 가지 예이다.
pages/working.vue
<!--
pages/working.vue
-->
<template>
<div>
<!-- This page correctly has only one single root element -->
Page content
</div>
</template>
pages/bad-1.vue
<!--
pages/bad1-vue
-->
<template>
<!-- This page will not render when route changes during client side navigation, because of this comment -->
<div>Page content</div>
</template>
pages/bad-2.vue
<!--
pages/bad-2.vue
-->
<template>
<div>This page</div>
<div>Has more than one root element</div>
<div>And will not render when route changes during client side navigation</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
<!--
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)
포괄 경로가 필요한 경우 [...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 구성요소를 표시하려면 <NuxtPage> 구성요소를 pages/parent.vue 안에 삽입해야 한다.
pages/parent.vue
<!--
pages/parent.vue
-->
<template>
<div>
<h1>I am the parent view</h1>
<NuxtPage :foobar="123" />
</div>
</template>
하위 경로 키
<NuxtPage> 컴포넌트가 다시 렌더링될 때(예: 트랜지션의 경우) 더 많은 제어를 원할 경우 pageKey prop을 통해 문자열이나 함수를 전달하거나 definePageMeta 를 통해 키 값을 정의할 수 있다.
pages/parent.vue
<!--
pages/parent.vue
-->
<template>
<div>
<h1>I am the parent view</h1>
<NuxtPage :page-key="route => route.fullPath" />
</div>
</template>
대안으로
pages/child.vue
<!--
pages/child.vue
-->
<script setup lang="ts">
definePageMeta({
key: route => route.fullPath
})
</script>
다음 예는 pages/ 디렉터리가 앱 경로를 생성하는지 보여주는 예이다.
app.vue
<!--
app.vue
-->
<script setup lang="ts">
const router = useRouter()
const nav = [
{ label: 'Home', to: '/' },
{ label: 'About', to: '/about' },
{ label: 'Parent (index)', to: '/parent' },
{ label: 'Parent (b)', to: '/parent/b' },
{ label: 'Keyed child', onClick: () => router.push(`/parent/reload-${(Math.random() * 100).toFixed()}`) },
{ label: 'Non-Keyed child', onClick: () => router.push(`/parent/static-${(Math.random() * 100).toFixed()}`) },
]
</script>
<template>
<NuxtExampleLayout dir="routing/pages" :nav="nav" current-route>
<NuxtLoadingIndicator />
<NuxtPage />
</NuxtExampleLayout>
</template>
페이지 메타데이터
앱의 각 경로에 대한 메타데이터를 정의할 수 있다. <script>와 <script setup> 모두에서 작동하는 definePageMeta 매크로를 사용하여 이 작업을 수행할 수 있다.
<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는 컴파일러 매크로이기 때문에 컴포넌트 내에서 참조할 수 없도록 컴파일된다. 대신 전달된 메타데이터가 컴포넌트 밖으로 끌어올려진다. 따라서 페이지 메타 개체는 컴포넌트(또는 컴포넌트에 정의된 값)를 참조할 수 없지만, 가져온 바인딩을 참조할 수는 있다.
<script setup lang="ts">
import { someData } from '~/utils/example'
const title = ref('')
definePageMeta({
title, // This will create an error
someData
})
</script>
특수한 메타데이터
물론 앱 전체에서 사용할 메타데이터를 정의할 수도 있습니다. 그러나 definePageMeta로 정의된 일부 메타데이터에는 특별한 목적이 있다.
alias
페이지 별칭을 정의할 수 있다. 이를 통해 다른 경로에서 동일한 페이지에 액세스할 수 있다. vue-router 문서에 정의된 대로 문자열이거나 문자열 배열일 수 있다.
keepalive
definePageMeta에서 keepalive: true를 설정하면 Nuxt는 자동으로 Vue <KeepAlive> 컴포넌트에서 페이지를 래핑한다. 예를 들어 동적 하위 경로가 있는 상위 경로에서 경로 변경 시 페이지 상태를 유지하려는 경우 이 작업을 수행하는 것이 유용할 수 있다.
상위 경로의 상태를 보존하는 것이 목표인 경우 <NuxtPage keepalive /> 구문을 사용하. <KeepAlive>에 전달되도록 속성을 설정할 수도 있다(여기에서 전체 목록 참조).
nuxt.config에서 이 속성에 대한 기본값을 설정할 수 있다.
key
위 '하위 경로 키' 섹션의 pages/child.vue 참조
layout
경로를 렌더링하는데 사용되는 레이아웃을 정의할 수 있다. 어떤 방식으로든 반응적으로 만들려는 경우 false(레이아웃을 비활성화하기 위해), 문자열 또는 ref/computed 될 수 있다. 레이아웃에 대해 자세히 알아보려면...
layoutTransition 과 pageTransition
페이지와 레이아웃을 래핑하는 <transition> 컴포넌트에 대한 트랜지션 속성을 정의하거나 false를 전달하여 해당 경로에 대한 <transition> 래퍼를 비활성화할 수 있다. 여기에서 전달할 수 있는 옵션 목록을 보거나 트랜지션 작동 방식에 대해 자세히 알아볼 수 있다.
nuxt.config에서 이러한 속성에 대한 기본값을 설정할 수 있다.
middleware
이 페이지를 로드하기 전에 적용할 미들웨어를 정의할 수 있다. 일치하는 상위/하위 경로에 사용되는 다른 모든 미들웨어와 병합된다. 문자열, 함수(전역 사전 보호 패턴을 따르는 익명/인라인 미들웨어 함수- anonymous/inlined middleware function following the global before guard pattern) 또는 문자열/함수의 배열일 수 있다. 명명된 미들웨어에 대해 자세히 알아보자.
name
이 페이지 경로의 이름을 정의할 수 있다.
path
파일 이름으로 표현할 수 있는 것보다 더 복잡한 패턴이 있는 경우 경로 일치자(path matcher)를 정의할 수 있다. 자세한 내용은 vue-router 문서를 참조하자.
사용자 정의 메타데이터 타입
페이지에 사용자 정의 메타데이터를 추가하는 경우 타입이 안전한 방식으로 수행되는 것이 좋다. definePageMeta 에서 허용하는 객체 유형을 확장할 수 있다.
index.d.ts
// index.d.ts
declare module '#app' {
interface PageMeta {
pageType?: string
}
}
// It is always important to ensure you import/export something when augmenting a type
export {}
네비게이션
Nuxt 3에서는 navigateTo() 유틸리티 메소드를 통해 프로그래밍 방식으로 탐색할 수 있습니다. 이 유틸리티 메서드를 사용하면 앱에서 사용자를 프로그래밍 방식으로 탐색할 수 있다. 이는 사용자로부터 입력을 받아 애플리케이션 전체에서 동적으로 탐색하는 데 유용하다. 아래 예에는 사용자가 검색 양식을 제출할 때 호출되는 navigate() 라는 간단한 메서드가 있다.
항상 await navigateTo 하거나 함수를 반환하여 결과를 연결하자.
<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>
커스텀 라우팅
앱이 점점 더 커지고 복잡해지면 라우팅에 더 많은 유연성이 필요할 수 있다. 이러한 이유로 Nuxt는 다양한 방식으로 사용자 정의를 위한 라우터, 경로 및 라우터 옵션을 직접 노출한다.
참고) Docs > Guide > Going Further > 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
// nuxt.config.ts
export default defineNuxtConfig({
extends: ['./some-app'],
})
참고) Docs > Guide > Going Further > Layers
'Nuxt 공식문서 번역 > Directories' 카테고리의 다른 글
public (0) | 2023.12.17 |
---|---|
plugins (1) | 2023.12.17 |
node_modules (0) | 2023.12.17 |
modules (0) | 2023.12.17 |
middleware (1) | 2023.12.17 |