brand logo

ドキュメント

composables

composables/ ディレクトリを使用して、Vue composables をアプリケーションに自動インポートします。

使用法

方法 1: 名前付きエクスポートを使用

composables/useFoo.ts
export const useFoo = () => {
  return useState('foo', () => 'bar')
}

方法 2: デフォルトエクスポートを使用

composables/use-foo.ts or composables/useFoo.ts
// useFoo() として利用可能になります(拡張子を除いたファイル名のキャメルケース)
export default function () {
  return useState('foo', () => 'bar')
}

使用法: 自動インポートされた composable を .js.ts.vue ファイルで使用できます

app.vue
<script setup lang="ts">
const foo = useFoo()
</script>

<template>
  <div>
    {{ foo }}
  </div>
</template>

Nuxt の composables/ ディレクトリは、コードに追加のリアクティビティ機能を提供しません。代わりに、composables 内のリアクティビティは、ref や reactive などの Vue の Composition API メカニズムを使用して実現されます。リアクティブなコードは composables/ ディレクトリの境界に限定されないことに注意してください。アプリケーション内で必要な場所でリアクティビティ機能を自由に使用できます。

こちらも参照 guide > concepts > auto-imports
サンプルコードの編集とプレビューexamples > features > auto-imports

内部では、Nuxt は .nuxt/imports.d.ts ファイルを自動生成して型を宣言します。

Nuxt に型を生成させるためには、nuxt preparenuxt dev、または nuxt build を実行する必要があることに注意してください。

開発サーバーを実行せずに composable を作成すると、TypeScript は Cannot find name 'useBar'. のようなエラーを投げます。

ネストされた Composables

自動インポートを使用して、別の composable 内で composable を使用できます:

composables/test.ts
export const useFoo = () => {
  const nuxtApp = useNuxtApp()
  const bar = useBar()
}

プラグイン注入へのアクセス

composables から プラグイン注入 にアクセスできます:

composables/test.ts
export const useHello = () => {
  const nuxtApp = useNuxtApp()
  return nuxtApp.$hello
}

ファイルのスキャン方法

Nuxt は composables/ ディレクトリ のトップレベルのファイルのみをスキャンします。例:

Directory Structure
-| composables/
---| index.ts     // スキャンされる
---| useFoo.ts    // スキャンされる
---| nested/
-----| utils.ts   // スキャンされない

composables/index.tscomposables/useFoo.ts のみがインポートのために検索されます。

ネストされたモジュールの自動インポートを機能させるには、それらを再エクスポートする(推奨)か、スキャナーを設定してネストされたディレクトリを含めることができます:

例: 必要な composables を composables/index.ts ファイルから再エクスポートする:

composables/index.ts
// このエクスポートの自動インポートを有効にする
export { utils } from './nested/utils.ts'

例: composables/ フォルダ内のネストされたディレクトリをスキャンする:

nuxt.config.ts
export default defineNuxtConfig({
  imports: {
    dirs: [
      // トップレベルの composables をスキャン
      '~/composables',
      // ... または特定の名前とファイル拡張子でネストされた1レベル深い composables をスキャン
      '~/composables/*/index.{ts,js,mjs,mts}',
      // ... または指定されたディレクトリ内のすべての composables をスキャン
      '~/composables/**'
    ]
  }
})

tips

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

はじめに:composablesがもたらすメリットと解決できる課題

Nuxtのcomposablesディレクトリは、VueのComposition APIを活用した関数群(composable)を自動的にインポートし、アプリケーション全体で簡単に再利用できる仕組みを提供します。これにより、状態管理やロジックの共通化が容易になり、コードの重複を減らし、保守性を向上させることが可能です。

特に大規模なプロジェクトや複数人での開発においては、共通の機能をcomposableとして切り出すことで、コードの見通しが良くなり、バグの混入を防ぎやすくなります。また、Nuxtが自動インポートを行うため、import文の記述を省略でき、開発効率も向上します。


まず結論:composablesのポイントまとめ

  • 自動インポートにより、composables/内の関数をどこでも名前だけで呼び出せる
  • VueのComposition APIを活用し、状態管理やロジックの再利用が容易
  • トップレベルのファイルのみスキャンされるため、ネストしたファイルは再エクスポートや設定が必要
  • プラグイン注入へのアクセスも可能で、Nuxtアプリの拡張性を高められる
  • リアクティビティはVueの仕組みを利用し、Nuxt独自のリアクティブ機能はない
  • 型定義は自動生成されるが、開発サーバー起動が必須でないとTypeScriptエラーが出ることがある

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

使うべきケース

  • 複数のコンポーネントやページで共通の状態やロジックを使いたいとき
  • VueのComposition APIを活用してコードの再利用性を高めたいとき
  • Nuxtの自動インポート機能を活かしてimport文を減らし、コードをシンプルにしたいとき
  • プラグインや外部ライブラリの機能をcomposable経由でラップし、使いやすくしたいとき

使わない方がよいケース

  • 単一のコンポーネント内だけで完結するロジックの場合(わざわざcomposable化する必要はない)
  • 非同期処理や副作用が複雑で、状態管理が難しい場合は、VuexやPiniaなどの状態管理ライブラリを検討したほうが良い
  • ネストしたディレクトリ構造を多用し、設定を複雑にしたくない場合(トップレベルのファイルにまとめるか、再エクスポートを活用すること)

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

1. 状態管理の共通化

複数のコンポーネントで共有する状態をcomposableに切り出す例です。

// composables/useCounter.ts
import { ref } from 'vue'

export const useCounter = () => {
  const count = ref(0)
  const increment = () => {
    count.value++
  }
  return { count, increment }
}
<script setup lang="ts">
const { count, increment } = useCounter()
</script>

<template>
  <button @click="increment">Count: {{ count }}</button>
</template>

2. API呼び出しの共通処理

API通信のロジックをcomposableにまとめて再利用します。

// composables/useFetchUser.ts
import { ref } from 'vue'

export const useFetchUser = () => {
  const user = ref(null)
  const error = ref(null)

  const fetchUser = async (id: string) => {
    try {
      const res = await fetch(`/api/users/${id}`)
      user.value = await res.json()
    } catch (e) {
      error.value = e
    }
  }

  return { user, error, fetchUser }
}

3. プラグイン注入の活用

Nuxtプラグインで提供される機能をcomposableから利用する例です。

// composables/useHello.ts
export const useHello = () => {
  const nuxtApp = useNuxtApp()
  return nuxtApp.$hello
}

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

1. ネストしたcomposablesは自動インポートされない

composables/nested/utils.tsのようにサブディレクトリに置いたファイルは自動的にスキャンされません。
この場合はトップレベルのcomposables/index.tsで再エクスポートするか、nuxt.config.tsimports.dirs設定で明示的にスキャン対象に含める必要があります。

2. SSRとHydrationの影響

composable内でブラウザ固有のAPI(windowdocumentなど)を直接使うと、SSR時にエラーになる可能性があります。
そのため、process.clientonMountedなどのフックを使ってクライアント側でのみ実行する工夫が必要です。

3. パフォーマンスへの配慮

composableは状態やロジックを共有するため便利ですが、過剰に状態をグローバル化するとパフォーマンス低下や不要な再レンダリングの原因になります。
必要な範囲で状態を限定し、適切に分割することが重要です。

4. TypeScriptの型エラー

開発サーバーを起動せずにcomposableを作成すると、TypeScriptが自動生成された型定義を認識できず、Cannot find name 'useFoo'のようなエラーが発生します。
必ずnuxt devnuxt buildを実行して型定義を生成してください。


まとめ

Nuxtのcomposables機能は、VueのComposition APIを活用したロジックの再利用を強力にサポートします。自動インポートによりimport文の記述を省略でき、開発効率が向上する一方で、ネストしたファイルの扱いやSSR対応など注意すべきポイントもあります。実務では状態管理やAPI呼び出しの共通化、プラグイン機能のラップなどに活用し、コードの保守性と拡張性を高めましょう。

適切に使いこなすことで、Nuxtアプリケーションの開発がよりスムーズで堅牢になります。ぜひ本記事のポイントを参考に、composablesを効果的に活用してください。