nuxt logo

문서 번역(비공식)

useNuxtApp

Nuxt 애플리케이션의 공유 런타임 컨텍스트에 접근합니다.

useNuxtApp은 Nuxt의 공유 런타임 컨텍스트에 접근할 수 있는 방법을 제공하는 내장된 컴포저블입니다. 이는 Nuxt 컨텍스트로도 알려져 있으며, 클라이언트와 서버 측에서 모두 사용 가능합니다 (하지만 Nitro 경로 내에서는 사용 불가). 이를 통해 Vue 앱 인스턴스, 런타임 훅, 런타임 구성 변수 및 ssrContextpayload 같은 내부 상태에 접근할 수 있습니다.

app.vue
const nuxtApp = useNuxtApp()

만약 런타임 컨텍스트가 범위 내에서 사용 불가능하다면, useNuxtApp을 호출할 때 예외가 발생합니다. nuxtApp이 필요하지 않은 컴포저블이나 예외 없이 컨텍스트가 사용 가능한지 단순히 확인하기 위해서는 tryUseNuxtApp을 대신 사용할 수 있습니다.

Methods

provide (name, value)

nuxtAppNuxt 플러그인을 사용하여 확장할 수 있는 런타임 컨텍스트입니다. provide 함수를 사용하여 Nuxt 플러그인을 생성하고 모든 컴포저블과 컴포넌트에서 사용할 수 있는 값과 헬퍼 메서드를 Nuxt 애플리케이션에 제공합니다.

provide 함수는 namevalue 매개변수를 받습니다.

const nuxtApp = useNuxtApp()
nuxtApp.provide('hello', (name) => `Hello ${name}!`)

// "Hello name!"을 출력합니다.
console.log(nuxtApp.$hello('name'))

위의 예에서 볼 수 있듯이, $hellonuxtApp 컨텍스트의 새로운 사용자 정의 부분이 되었으며, nuxtApp에 접근할 수 있는 모든 곳에서 사용 가능합니다.

hook(name, cb)

nuxtApp에서 사용할 수 있는 훅은 Nuxt 애플리케이션의 런타임 측면을 사용자 정의할 수 있게 합니다. Vue.js 컴포저블과 Nuxt 플러그인에서 런타임 훅을 사용하여 렌더링 라이프사이클에 연결할 수 있습니다.

hook 함수는 특정 시점에서 렌더링 라이프사이클에 연결하여 사용자 정의 로직을 추가하는 데 유용합니다. hook 함수는 주로 Nuxt 플러그인을 생성할 때 사용됩니다.

Nuxt에서 호출되는 사용 가능한 런타임 훅은 Runtime Hooks를 참조하세요.

plugins/test.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('page:start', () => {
    /* 여기에 코드를 작성하세요 */
  })
  nuxtApp.hook('vue:error', (..._args) => {
    console.log('vue:error')
    // if (import.meta.client) {
    //   console.log(..._args)
    // }
  })
})

callHook(name, ...args)

callHook는 기존의 훅 중 하나를 호출할 때 프라미스를 반환합니다.

await nuxtApp.callHook('my-plugin:init')

Properties

useNuxtApp()은 앱을 확장하고 사용자 정의하며 상태, 데이터 및 변수를 공유하는 데 사용할 수 있는 다음의 속성을 노출합니다.

vueApp

vueAppnuxtApp을 통해 접근할 수 있는 글로벌 Vue.js 애플리케이션 인스턴스입니다.

유용한 메서드:

  • component() - 이름 문자열과 컴포넌트 정의를 모두 전달하면 글로벌 컴포넌트를 등록하거나, 이름만 전달하면 이미 등록된 것을 검색합니다.
  • directive() - 이름 문자열과 지시문 정의를 모두 전달하면 글로벌 사용자 정의 지시문을 등록하거나, 이름만 전달하면 이미 등록된 것을 검색합니다(예제).
  • use() - **Vue.js 플러그인**을 설치합니다(예제).
이것도 참고 vuejs.org > api > application.html

ssrContext

ssrContext는 서버 사이드 렌더링 중에 생성되며 서버 측에서만 사용 가능합니다.

Nuxt는 ssrContext를 통해 다음의 속성을 노출합니다:

  • url (string) - 현재 요청 URL.
  • event (h3js/h3 요청 이벤트) - 현재 경로의 요청 및 응답에 접근합니다.
  • payload (object) - NuxtApp 페이로드 객체.

payload

payload는 서버 측에서 클라이언트 측으로 데이터와 상태 변수를 노출합니다. 서버 측에서 전달된 후 클라이언트에서 사용할 수 있는 키는 다음과 같습니다:

  • serverRendered (boolean) - 응답이 서버 사이드 렌더링되었는지 여부를 나타냅니다.

  • data (object) - useFetch 또는 useAsyncData를 사용하여 API 엔드포인트에서 데이터를 가져올 때, 결과 페이로드는 payload.data에서 접근할 수 있습니다. 이 데이터는 캐시되며 동일한 요청이 여러 번 발생할 경우 동일한 데이터를 다시 가져오는 것을 방지합니다.

    const { data } = await useAsyncData('count', () => $fetch('/api/count'))

    위의 예에서 useAsyncData를 사용하여 count 값을 가져온 후, payload.data에 접근하면 { count: 1 }이 기록된 것을 볼 수 있습니다.

    ssrcontext에서 동일한 payload.data에 접근할 때, 서버 측에서도 동일한 값에 접근할 수 있습니다.

  • state (object) - Nuxt에서 useState 컴포저블을 사용하여 공유 상태를 설정할 때, 이 상태 데이터는 payload.state.[name-of-your-state]를 통해 접근합니다.

    plugins/my-plugin.ts
    export const useColor = () => useState<string>('color', () => 'pink')
    
    export default defineNuxtPlugin((nuxtApp) => {
      if (import.meta.server) {
        const color = useColor()
      }
    })
    

    ref, reactive, shallowRef, shallowReactive, NuxtError와 같은 더 고급 타입을 사용하는 것도 가능합니다.

    Nuxt v3.4 이후로, Nuxt에서 지원하지 않는 타입에 대해 자체 리듀서/리바이버를 정의할 수 있습니다.

    아래 예제에서는 페이로드 플러그인을 사용하여 Luxon DateTime 클래스에 대한 리듀서(또는 직렬화기)와 리바이버(또는 역직렬화기)를 정의합니다.

    plugins/date-time-payload.ts
    /**
     * 이 종류의 플러그인은 Nuxt 라이프사이클에서 매우 초기에 실행되며, 페이로드를 복원하기 전에 실행됩니다.
     * 라우터나 다른 Nuxt 주입 속성에 접근할 수 없습니다.
     *
     * "DateTime" 문자열은 타입 식별자이며 리듀서와 리바이버 모두에서 동일해야 합니다.
     */
    export default definePayloadPlugin((nuxtApp) => {
      definePayloadReducer('DateTime', (value) => {
        return value instanceof DateTime && value.toJSON()
      })
      definePayloadReviver('DateTime', (value) => {
        return DateTime.fromISO(value)
      })
    })
    

isHydrating

클라이언트 측에서 Nuxt 앱이 하이드레이팅 중인지 확인하려면 nuxtApp.isHydrating (boolean)을 사용하세요.

components/nuxt-error-boundary.ts
export default defineComponent({
  setup (_props, { slots, emit }) {
    const nuxtApp = useNuxtApp()
    onErrorCaptured((err) => {
      if (import.meta.client && !nuxtApp.isHydrating) {
        // ...
      }
    })
  }
})

runWithContext

"Nuxt 인스턴스를 사용할 수 없습니다"라는 메시지를 받았기 때문에 여기에 오셨을 가능성이 큽니다. 이 메서드는 신중하게 사용하시고, 문제를 일으키는 예제를 보고하여 궁극적으로 프레임워크 수준에서 해결될 수 있도록 하세요.

runWithContext 메서드는 함수를 호출하고 명시적인 Nuxt 컨텍스트를 제공하는 데 사용됩니다. 일반적으로 Nuxt 컨텍스트는 암시적으로 전달되며 이에 대해 걱정할 필요가 없습니다. 그러나 미들웨어/플러그인에서 복잡한 async/await 시나리오를 다룰 때, 비동기 호출 후 현재 인스턴스가 해제된 경우를 만날 수 있습니다.

middleware/auth.ts
export default defineNuxtRouteMiddleware(async (to, from) => {
  const nuxtApp = useNuxtApp()
  let user
  try {
    user = await fetchUser()
    // try/catch 블록 때문에 Vue/Nuxt 컴파일러가 컨텍스트를 잃습니다.
  } catch (e) {
    user = null
  }
  if (!user) {
    // `navigateTo` 호출에 올바른 Nuxt 컨텍스트를 적용합니다.
    return nuxtApp.runWithContext(() => navigateTo('/auth'))
  }
})

Usage

const result = nuxtApp.runWithContext(() => functionWithContext())
  • functionWithContext: 현재 Nuxt 애플리케이션의 컨텍스트가 필요한 함수입니다. 이 컨텍스트는 자동으로 올바르게 적용됩니다.

runWithContextfunctionWithContext가 반환하는 값을 반환합니다.

A Deeper Explanation of Context

Vue.js Composition API (및 유사한 Nuxt 컴포저블)는 암시적인 컨텍스트에 의존하여 작동합니다. 라이프사이클 동안 Vue는 현재 컴포넌트의 임시 인스턴스(및 Nuxt의 임시 nuxtApp 인스턴스)를 전역 변수에 설정하고 동일한 틱에서 이를 해제합니다. 서버 측에서 렌더링할 때, 여러 사용자의 요청이 동일한 전역 컨텍스트에서 실행되는 nuxtApp과 함께 발생합니다. 이 때문에 Nuxt와 Vue는 두 사용자 또는 컴포넌트 간에 공유 참조가 누출되는 것을 방지하기 위해 이 전역 인스턴스를 즉시 해제합니다.

이것이 의미하는 바는 무엇일까요? Composition API와 Nuxt 컴포저블은 라이프사이클 동안 및 비동기 작업 이전의 동일한 틱에서만 사용 가능합니다:

// --- Vue 내부 ---
const _vueInstance = null
const getCurrentInstance = () => _vueInstance
// ---

// Vue / Nuxt는 setup() 호출 시 _vueInstance에 현재 컴포넌트를 참조하는 전역 변수를 설정합니다.
async function setup() {
  getCurrentInstance() // 작동합니다.
  await someAsyncOperation() // Vue는 비동기 작업 이전의 동일한 틱에서 컨텍스트를 해제합니다!
  getCurrentInstance() // null
}

이 문제에 대한 고전적인 해결책은 첫 번째 호출 시 현재 인스턴스를 로컬 변수에 캐시하는 것입니다. 예를 들어 const instance = getCurrentInstance()와 같이 하고, 다음 컴포저블 호출에서 이를 사용하는 것입니다. 그러나 문제는 이제 모든 중첩된 컴포저블 호출이 명시적으로 인스턴스를 인수로 받아야 하며, composition-api의 암시적 컨텍스트에 의존하지 않아야 한다는 것입니다. 이는 컴포저블의 설계 제한이며, 본질적으로 문제가 아닙니다.

이 제한을 극복하기 위해 Vue는 <script setup>에 대한 각 호출 후 컨텍스트를 복원할 때 애플리케이션 코드를 컴파일할 때 몇 가지 작업을 수행합니다:

const __instance = getCurrentInstance() // Vue 컴파일러에 의해 생성됨
getCurrentInstance() // 작동합니다!
await someAsyncOperation() // Vue는 컨텍스트를 해제합니다.
__restoreInstance(__instance) // Vue 컴파일러에 의해 생성됨
getCurrentInstance() // 여전히 작동합니다!

Vue가 실제로 수행하는 작업에 대한 더 나은 설명은 unjs/unctx#2 (comment)를 참조하세요.

Solution

이것이 runWithContext<script setup>이 작동하는 방식과 유사하게 컨텍스트를 복원하는 데 사용될 수 있는 이유입니다.

Nuxt는 내부적으로 unjs/unctx를 사용하여 플러그인과 미들웨어에 대해 Vue와 유사한 컴포저블을 지원합니다. 이를 통해 navigateTo()와 같은 컴포저블이 nuxtApp을 직접 전달하지 않고도 작동할 수 있으며, Composition API의 DX 및 성능 이점을 Nuxt 프레임워크 전체에 제공합니다.

Nuxt 컴포저블은 Vue Composition API와 동일한 설계를 가지고 있으므로, 이 변환을 마법처럼 수행하기 위해 유사한 솔루션이 필요합니다. unjs/unctx#2 (제안), unjs/unctx#4 (변환 구현), nuxt/framework#3884 (Nuxt에의 통합)를 확인하세요.

Vue는 현재 <script setup>에 대한 비동기/대기 사용을 위한 비동기 컨텍스트 복원만 지원합니다. Nuxt에서는 defineNuxtPlugin()defineNuxtRouteMiddleware()에 대한 변환 지원이 추가되었으며, 이를 사용할 때 Nuxt가 자동으로 컨텍스트 복원과 함께 변환합니다.

Remaining Issues

try/catch 문에 await가 포함된 경우 자동으로 컨텍스트를 복원하는 unjs/unctx 변환이 버그가 있는 것으로 보이며, 궁극적으로 위에서 제안한 해결책의 필요성을 제거하기 위해 해결되어야 합니다.

Native Async Context

새로운 실험적 기능을 사용하여 Node.js AsyncLocalStorage와 새로운 unctx 지원을 사용하여 어떤 중첩된 비동기 컴포저블에도 변환이나 수동 전달/호출 없이 네이티브로 비동기 컨텍스트를 사용할 수 있습니다.

네이티브 비동기 컨텍스트 지원은 현재 Bun과 Node에서 작동합니다.

이것도 참고 guide > going-further > experimental-features#asynccontext

tryUseNuxtApp

이 함수는 useNuxtApp과 동일하게 작동하지만, 컨텍스트가 사용 불가능한 경우 예외를 발생시키는 대신 null을 반환합니다.

nuxtApp이 필요하지 않은 컴포저블이나 예외 없이 컨텍스트가 사용 가능한지 단순히 확인하기 위해 사용할 수 있습니다.

사용 예:

composable.ts
export function useStandType() {
  // 항상 클라이언트에서 작동합니다.
  if (tryUseNuxtApp()) {
    return useRuntimeConfig().public.STAND_TYPE
  } else {
    return process.env.STAND_TYPE
  }
}