nuxt logo

ドキュメント翻訳(非公式)

useNuxtApp

Nuxtアプリケーションの共有ランタイムコンテキストにアクセスします。

useNuxtAppは、Nuxtの共有ランタイムコンテキスト(Nuxtコンテキストとも呼ばれる)にアクセスするための組み込みのコンポーザブルです。これはクライアントとサーバーの両方で利用可能ですが、Nitroルート内では利用できません。Vueアプリインスタンス、ランタイムフック、ランタイム設定変数、ssrContextpayloadなどの内部状態にアクセスするのに役立ちます。

app/app.vue
const nuxtApp = useNuxtApp()

もしランタイムコンテキストがスコープ内で利用できない場合、useNuxtAppを呼び出すと例外がスローされます。nuxtAppを必要としないコンポーザブルや、例外なしでコンテキストが利用可能かどうかを単に確認するためには、tryUseNuxtAppを使用できます。

メソッド

provide (name, value)

nuxtAppは、Nuxtプラグインを使用して拡張できるランタイムコンテキストです。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プラグインを作成する際に使用されます。

利用可能なランタイムフックについては、Runtime Hooksを参照してください。

app/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')

プロパティ

useNuxtApp()は、アプリを拡張およびカスタマイズし、状態、データ、変数を共有するために使用できる以下のプロパティを公開します。

vueApp

vueAppは、nuxtAppを通じてアクセスできるグローバルな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]を通じてアクセスされます。

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

    refreactiveshallowRefshallowReactiveNuxtErrorなどのより高度な型を使用することも可能です。

    Nuxt v3.4以降、Nuxtでサポートされていない型に対して独自のリデューサー/リバイバーを定義することが可能になりました。

    以下の例では、ペイロードプラグインを使用してLuxonのDateTimeクラスのリデューサー(またはシリアライザー)とリバイバー(またはデシリアライザー)を定義します。

    app/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)を使用します。

app/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シナリオを扱う際には、非同期呼び出しの後に現在のインスタンスが解除される場合があります。

app/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'))
  }
})

使用法

const result = nuxtApp.runWithContext(() => functionWithContext())
  • functionWithContext: 現在のNuxtアプリケーションのコンテキストを必要とする任意の関数。このコンテキストは自動的に正しく適用されます。

runWithContextは、functionWithContextによって返されるものを返します。

コンテキストのより深い説明

Vue.jsのComposition API(およびNuxtのコンポーザブルも同様に)は、暗黙のコンテキストに依存して動作します。ライフサイクル中、Vueは現在のコンポーネントの一時インスタンス(およびNuxtの一時インスタンスnuxtApp)をグローバル変数に設定し、同じティックでそれを解除します。サーバーサイドでレンダリングする際には、異なるユーザーからの複数のリクエストがあり、nuxtAppが同じグローバルコンテキストで実行されます。このため、NuxtとVueはこのグローバルインスタンスをすぐに解除し、2つのユーザーまたはコンポーネント間で共有参照がリークするのを防ぎます。

これは何を意味するのでしょうか?Composition APIとNuxtコンポーザブルは、ライフサイクル中および非同期操作の前の同じティックでのみ利用可能です。

// --- Vue内部 ---
const _vueInstance = null
const getCurrentInstance = () => _vueInstance
// ---

// Vue / Nuxtはsetup()を呼び出す際に現在のコンポーネントを参照するグローバル変数を_vueInstanceに設定します。
async function setup() {
  getCurrentInstance() // 動作します
  await someAsyncOperation() // Vueは非同期操作の前に同じティックでコンテキストを解除します!
  getCurrentInstance() // null
}

これに対する古典的な解決策は、最初の呼び出しで現在のインスタンスをローカル変数にキャッシュし、次のコンポーザブル呼び出しでそれを使用することです。しかし、問題は、ネストされたコンポーザブル呼び出しが現在のインスタンスを引数として明示的に受け入れ、composition-apiの暗黙のコンテキストに依存しない必要があることです。これはコンポーザブルの設計上の制限であり、問題ではありません。

この制限を克服するために、Vueは<script setup>での各呼び出し後にコンテキストを復元するために、アプリケーションコードをコンパイルする際に裏で作業を行います。

const __instance = getCurrentInstance() // Vueコンパイラによって生成されます
getCurrentInstance() // 動作します!
await someAsyncOperation() // Vueはコンテキストを解除します
__restoreInstance(__instance) // Vueコンパイラによって生成されます
getCurrentInstance() // まだ動作します!

Vueが実際に何をしているのかについてのより良い説明は、unjs/unctx#2 (comment)を参照してください。

解決策

ここで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は現在、非同期/awaitの使用に対して<script setup>の非同期コンテキスト復元のみをサポートしています。Nuxtでは、defineNuxtPlugin()defineNuxtRouteMiddleware()の変換サポートが追加されており、それらを使用する際にNuxtが自動的にコンテキスト復元で変換します。

残りの問題

try/catchステートメントを含むawaitでコンテキストを自動的に復元するunjs/unctxの変換はバグがあるようで、最終的には上記の回避策の要件を取り除くために解決される必要があります。

ネイティブ非同期コンテキスト

新しい実験的な機能を使用すると、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
  }
}