페이지와 레이아웃

Nuxt 2에서 Nuxt 3로 페이지와 레이아웃을 마이그레이션하는 방법을 알아보세요.

app.vue

Nuxt 3는 ~/app.vue를 통해 앱의 중앙 진입점을 제공합니다.

소스 디렉터리에 app.vue 파일이 없다면, Nuxt는 자체 기본 버전을 사용합니다.

이 파일은 앱이 시작될 때 한 번만 실행되어야 하는 사용자 정의 코드나, 앱의 모든 페이지에 공통으로 존재하는 컴포넌트를 넣기에 좋은 위치입니다. 예를 들어, 레이아웃이 하나만 있다면 이를 app.vue로 옮길 수 있습니다.

Read more in Docs > 4 X > Directory Structure > App > App.
Read and edit a live example in Docs > 4 X > Examples > Hello World.

마이그레이션

app.vue 파일을 생성하고, 앱의 최상위에서 한 번만 실행되어야 하는 로직을 이곳에 포함하는 것을 고려해 보세요. 여기 예시를 참고할 수 있습니다.

레이아웃

앱에서 여러 페이지에 레이아웃을 사용하고 있다면, 약간의 변경만 필요합니다.

Nuxt 2에서는 현재 페이지를 렌더링하기 위해 레이아웃 안에서 <Nuxt> 컴포넌트를 사용했습니다. Nuxt 3에서는 레이아웃이 슬롯을 사용하므로, 해당 컴포넌트를 <slot />으로 교체해야 합니다. 이는 이름 있는 슬롯과 범위가 지정된 슬롯 같은 고급 사용 사례도 가능하게 합니다. 레이아웃에 대해 더 읽어보기.

또한 페이지에서 사용되는 레이아웃을 정의하는 방식도 definePageMeta 컴파일러 매크로를 사용하도록 변경해야 합니다. 레이아웃 이름은 케밥 케이스(kebab-case)가 됩니다. 따라서 app/layouts/customLayout.vue는 페이지에서 참조할 때 custom-layout이 됩니다.

마이그레이션

  1. <Nuxt /><slot />으로 교체
    app/layouts/custom.vue
      <template>
        <div id="app-layout">
          <main>
    -       <Nuxt />
    +       <slot />
          </main>
        </div>
      </template>
    
  2. definePageMeta를 사용해 페이지에서 사용할 레이아웃을 선택합니다.
    app/pages/index.vue
    + <script setup>
    + definePageMeta({
    +   layout: 'custom'
    + })
    - <script>
    - export default {
    -   layout: 'custom'
    - }
      </script>
    
  3. ~/layouts/_error.vue~/error.vue로 이동합니다. 에러 처리 문서를 참고하세요. 이 페이지가 레이아웃을 사용하도록 보장하고 싶다면, error.vue 안에서 <NuxtLayout>을 직접 사용할 수 있습니다:
    error.vue
    <template>
      <div>
        <NuxtLayout name="default">
          <!-- -->
        </NuxtLayout>
      </div>
    </template>
    

페이지

Nuxt 3는 소스 디렉터리에 app/pages/ 디렉터리가 존재할 때 활성화되는 선택적 vue-router 통합을 제공합니다. 페이지가 하나만 있다면, 더 가벼운 빌드를 위해 이를 app.vue로 옮기는 것을 고려할 수 있습니다.

동적 라우트

Nuxt 3에서 동적 라우트를 정의하는 형식은 Nuxt 2와 약간 다르므로, app/pages/ 안의 일부 파일 이름을 변경해야 할 수 있습니다.

  1. 이전에 동적 라우트 파라미터를 정의하기 위해 _id를 사용했다면 이제는 [id]를 사용합니다.
  2. 이전에 캐치올(catch-all) 라우트를 정의하기 위해 _.vue를 사용했다면 이제는 [...slug].vue를 사용합니다.

중첩 라우트

Nuxt 2에서는 <Nuxt><NuxtChild>를 사용해 (부모와 자식 컴포넌트가 있는) 중첩 라우트를 정의했습니다. Nuxt 3에서는 이들이 하나의 <NuxtPage> 컴포넌트로 대체되었습니다.

페이지 키와 keep-alive 속성

<Nuxt>에 사용자 정의 페이지 키나 keep-alive 속성을 전달하고 있었다면, 이제는 definePageMeta를 사용해 이러한 옵션을 설정하게 됩니다.

Read more in Docs > 4 X > Directory Structure > App > Pages#special Metadata.

페이지 및 레이아웃 트랜지션

페이지나 레이아웃에 대한 트랜지션을 컴포넌트 옵션에서 직접 정의하고 있었다면, 이제는 definePageMeta를 사용해 트랜지션을 설정해야 합니다. Vue 3 이후로 -enter 및 -leave CSS 클래스 이름이 변경되었습니다. <Nuxt>style prop은 <slot>에서 사용될 때 더 이상 트랜지션에 적용되지 않으므로, 스타일을 -active 클래스에 옮기세요.

Read more in Docs > 4 X > Getting Started > Transitions.

마이그레이션

  1. 동적 파라미터를 가진 모든 페이지의 이름을 새 형식에 맞게 변경합니다.
  2. <Nuxt><NuxtChild><NuxtPage>로 업데이트합니다.
  3. Composition API를 사용 중이라면, this.$routethis.$routeruseRouteuseRouter 컴포저블을 사용하도록 마이그레이션할 수 있습니다.

예시: 동적 라우트

- URL: /users
- Page: /pages/users/index.vue

- URL: /users/some-user-name
- Page: /pages/users/_user.vue
- Usage: params.user

- URL: /users/some-user-name/edit
- Page: /pages/users/_user/edit.vue
- Usage: params.user

- URL: /users/anything-else
- Page: /pages/users/_.vue
- Usage: params.pathMatch

예시: 중첩 라우트와 definePageMeta

<template>
  <div>
    <NuxtChild
      keep-alive
      :keep-alive-props="{ exclude: ['modal'] }"
      :nuxt-child-key="$route.slug"
    />
  </div>
</template>

<script>
export default {
  transition: 'page', // 또는 { name: 'page' }
}
</script>

전역 NuxtLink 컴포넌트의 대부분의 문법과 기능은 동일합니다. <NLink> 단축 형식을 사용하고 있었다면, 이를 <NuxtLink>로 업데이트해야 합니다.

<NuxtLink>는 이제 외부 링크를 포함한 모든 링크에 대해 바로 사용할 수 있는 대체재입니다. 이에 대해 더 읽어보고, 이를 확장해 자신만의 링크 컴포넌트를 제공하는 방법을 알아볼 수 있습니다.

Read more in Docs > 4 X > API > Components > Nuxt Link.

프로그래매틱 내비게이션

Nuxt 2에서 Nuxt 3로 마이그레이션할 때, 사용자에게 프로그래매틱하게 내비게이션하는 방식을 업데이트해야 합니다. Nuxt 2에서는 this.$router로 기본 Vue Router에 접근할 수 있었습니다. Nuxt 3에서는 navigateTo() 유틸리티 메서드를 사용할 수 있으며, 이를 통해 라우트와 파라미터를 Vue Router에 전달할 수 있습니다.

항상 navigateToawait 하거나, 함수에서 반환하여 그 결과를 체이닝하도록 하세요.
<script>
export default {
  methods: {
    navigate () {
      this.$router.push({
        path: '/search',
        query: {
          name: 'first name',
          type: '1',
        },
      })
    },
  },
}
</script>