brand logo

ドキュメント

Nuxt はどのように動作するのか?

Nuxt はウェブアプリケーションを構築するための、最小限でありながら高度にカスタマイズ可能なフレームワークです。

このガイドは、Nuxt の内部をよりよく理解し、Nuxt 上で新しいソリューションやモジュール統合を開発するのに役立ちます。

Nuxt インターフェース

nuxt dev で開発モードで Nuxt を開始するか、nuxt build で本番アプリケーションをビルドすると、nuxt として内部で参照される共通のコンテキストが作成されます。これは、nuxt.config ファイルとマージされた正規化されたオプション、いくつかの内部状態、および unjs/hookable によって強化された強力なフックシステムを保持し、異なるコンポーネントが互いに通信できるようにします。これを Builder Core と考えることができます。

このコンテキストは、Nuxt Kit のコンポーザブルで使用するためにグローバルに利用可能です。そのため、プロセスごとに Nuxt のインスタンスは一つだけ許可されます。

Nuxt インターフェースを拡張し、ビルドプロセスの異なる段階にフックするためには、Nuxt Modules を使用できます。

詳細については、ソースコードをチェックしてください。

NuxtApp インターフェース

ブラウザまたはサーバーでページをレンダリングする際に、nuxtApp として参照される共有コンテキストが作成されます。このコンテキストは、Vue インスタンス、ランタイムフック、ssrContext やハイドレーション用のペイロードなどの内部状態を保持します。これを Runtime Core と考えることができます。

このコンテキストは、Nuxt プラグインや <script>、Vue のコンポーザブル内で useNuxtApp() コンポーザブルを使用してアクセスできます。グローバルな使用はブラウザでは可能ですが、サーバーではユーザー間でコンテキストを共有しないようにするためにできません。

useNuxtApp はコンテキストが現在利用できない場合に例外を投げるため、コンポーザブルが常に nuxtApp を必要としない場合は、例外を投げる代わりに null を返す tryUseNuxtApp を使用できます。

nuxtApp インターフェースを拡張し、異なる段階にフックしたりコンテキストにアクセスするためには、Nuxt Plugins を使用できます。

このインターフェースについての詳細は、Nuxt App を参照してください。

nuxtApp には以下のプロパティがあります:

const nuxtApp = {
  vueApp, // グローバルな Vue アプリケーション: https://vuejs.org/api/application.html#application-api

  versions, // Nuxt と Vue のバージョンを含むオブジェクト

  // これらはランタイム NuxtApp フックを呼び出したり追加したりするためのものです
  // https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts#L18
  hooks,
  hook,
  callHook,

  // サーバーサイドでのみアクセス可能
  ssrContext: {
    url,
    req,
    res,
    runtimeConfig,
    noSSR,
  },

  // これは文字列化され、サーバーからクライアントに渡されます
  payload: {
    serverRendered: true,
    data: {},
    state: {}
  }

  provide: (name: string, value: any) => void
}

詳細については、ソースコードをチェックしてください。

ランタイムコンテキスト vs. ビルドコンテキスト

Nuxt は Node.js を使用してプロジェクトをビルドおよびバンドルしますが、ランタイム側も持っています。

両方の領域を拡張することができますが、そのランタイムコンテキストはビルド時から分離されています。そのため、ランタイム設定以外の状態、コード、コンテキストを共有することは想定されていません!

nuxt.configNuxt Modules はビルドコンテキストを拡張するために使用でき、Nuxt Plugins はランタイムを拡張するために使用できます。

本番用のアプリケーションをビルドする際、nuxt build.output ディレクトリにスタンドアロンのビルドを生成し、nuxt.configNuxt modules から独立しています。

tips

このセクションは公式ドキュメントの翻訳ではなく、本サイト独自の補足記事です。

はじめに:Nuxt のコンテキスト理解がもたらすメリット

Nuxt は強力で柔軟なフレームワークですが、その内部には「ビルドコンテキスト」と「ランタイムコンテキスト」という2つの異なる環境が存在します。これらを正しく理解し使い分けることは、Nuxt アプリケーションの開発効率や保守性を大きく向上させます。

例えば、ビルド時にしか利用できない設定やモジュールの拡張と、実際のユーザーがアクセスするランタイムでの状態管理やプラグインの挙動は別物です。混同すると、意図しない動作やパフォーマンス低下、さらにはセキュリティリスクを招くこともあります。

本記事では、Nuxt の2つのコンテキストの違いをわかりやすく解説し、実務での活用例や注意点を交えて丁寧に説明します。


まず結論:Nuxt のコンテキストのポイント

  • ビルドコンテキストnuxt.config や Nuxt Modules によって拡張され、ビルド時にのみ利用可能。
  • ランタイムコンテキストはブラウザやサーバーでのページレンダリング時に生成され、nuxtApp としてアクセス可能。
  • ビルドコンテキストとランタイムコンテキストは分離されており、状態やコードの共有は基本的にできない。
  • ビルドコンテキストはアプリの構成やビルドプロセスの制御に使い、ランタイムコンテキストは実際のユーザー体験や動的処理に使う。
  • それぞれのコンテキストを誤用すると、SSR や Hydration の問題、パフォーマンス低下、セキュリティリスクが発生する可能性がある。

いつ使うべきか?使わない方がよいケース

ビルドコンテキストを使うべきケース

  • アプリの設定や環境変数の定義(nuxt.config
  • ビルド時にコードを変換・最適化するモジュールの追加
  • 静的ファイルの生成やルーティングの設定
  • ビルドプロセスに影響を与える処理全般

ランタイムコンテキストを使うべきケース

  • ユーザーのリクエストに応じた動的データの取得や状態管理
  • Vue コンポーネント内でのプラグイン利用やフックの呼び出し
  • クライアントサイドでのインタラクションや API 通信
  • SSR 時のリクエスト固有の情報アクセス(例:ssrContext

使わない方がよいケース

  • ビルドコンテキストでランタイム固有の状態を扱う(例:ユーザーセッション情報)
  • ランタイムコンテキストでビルド時にしか存在しない設定を参照する
  • 両者の境界を曖昧にして状態を共有しようとする

実務でよくあるユースケースとサンプルコード

1. ビルド時に環境変数を設定し、ランタイムで利用する

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      apiBase: process.env.API_BASE_URL || 'https://api.example.com'
    }
  }
})
// composables/useApi.ts
export const useApi = () => {
  const nuxtApp = useNuxtApp()
  const apiBase = nuxtApp.$config.public.apiBase
  const fetchData = async () => {
    const res = await fetch(`${apiBase}/data`)
    return res.json()
  }
  return { fetchData }
}

ビルドコンテキストで環境変数を設定し、ランタイムで安全に参照しています。


2. Nuxt モジュールでビルド時にルーティングを拡張

// modules/custom-routes.ts
export default function CustomRoutesModule() {
  this.nuxt.hook('pages:extend', (pages) => {
    pages.push({
      name: 'custom',
      path: '/custom',
      file: '~/pages/custom.vue'
    })
  })
}

モジュールはビルドコンテキストで動作し、ページのルーティングを追加しています。


3. ランタイムプラグインでユーザー固有の情報を注入

// plugins/user.ts
export default defineNuxtPlugin((nuxtApp) => {
  const user = useUserStore()
  nuxtApp.provide('user', user)
})
const { $user } = useNuxtApp()
console.log($user.name)

ランタイムコンテキストでユーザー情報を管理し、Vue コンポーネントで利用しています。


よくある落とし穴・注意点

1. SSR と Hydration の不整合

ランタイムコンテキストの状態がサーバーとクライアントで異なると、Hydration エラーが発生します。例えば、サーバー側でのみ存在する値をクライアントで参照すると問題になります。ssrContext はサーバー専用なので、クライアント側での使用は避けましょう。

2. ビルドコンテキストのコードをランタイムで実行しようとする

ビルド時にしか存在しないモジュールや設定をランタイムで参照すると、実行時エラーになります。例えば、nuxt.config の内容を直接ランタイムで操作することはできません。

3. パフォーマンスへの影響

ビルドコンテキストで重い処理を行うとビルド時間が長くなり、ランタイムコンテキストで不要な処理を行うとユーザー体験が悪化します。処理の役割を明確に分けることが重要です。

4. セキュリティリスク

ビルドコンテキストでのみ扱うべき秘密情報をランタイムに漏らすと、クライアントに機密情報が露出します。runtimeConfig.privateruntimeConfig.public の使い分けを厳密に行いましょう。


まとめ

Nuxt のビルドコンテキストとランタイムコンテキストは、それぞれ役割と利用タイミングが異なる重要な概念です。これらを正しく理解し使い分けることで、安定した SSR、効率的な開発、そして安全なアプリケーション運用が可能になります。

  • ビルドコンテキストは設定やビルド処理に特化
  • ランタイムコンテキストはユーザー体験や動的処理に特化
  • 境界を守り、状態やコードの混在を避けることが重要

Nuxt をより深く理解し、実務でのトラブルを減らすために、ぜひ本記事のポイントを参考にしてください。

Nuxt の公式ドキュメントやソースコードも定期的にチェックし、最新の仕様やベストプラクティスを追いかけることをおすすめします。