brand logo

ドキュメント

モジュール作成ガイド

Nuxtアプリケーションを統合、強化、または拡張するためのNuxtモジュールの作成方法を学びます。

Nuxtの設定フックシステムを使用すると、Nuxtのあらゆる側面をカスタマイズし、必要な統合(Vueプラグイン、CMS、サーバールート、コンポーネント、ログ記録など)を追加することが可能です。

Nuxtモジュールは、nuxt devを使用して開発モードでNuxtを開始する際や、nuxt buildでプロジェクトを本番用にビルドする際に順次実行される関数です。モジュールを使用すると、プロジェクトに不要なボイラープレートを追加したり、Nuxt自体に変更を加えることなく、カスタムソリューションをnpmパッケージとしてカプセル化し、適切にテストし、共有することができます。

クイックスタート

Nuxtモジュールを始めるには、スターターテンプレートを使用することをお勧めします:

npm create nuxt -- -t module my-module

これにより、モジュールを開発および公開するために必要なすべてのボイラープレートを備えたmy-moduleプロジェクトが作成されます。

次のステップ:

  1. お好みのIDEでmy-moduleを開く
  2. お気に入りのパッケージマネージャーを使用して依存関係をインストールする
  3. npm run dev:prepareを使用して開発用のローカルファイルを準備する
  4. このドキュメントを参照してNuxtモジュールについてさらに学ぶ

スターターの使用

モジュールスターターを使用して基本的なタスクを実行する方法を学びます。

Nuxtモジュールスターターテンプレートに関するVue Schoolのビデオを視聴してください。

開発方法

モジュールのソースコードは通常srcディレクトリ内にありますが、モジュールを開発するにはNuxtアプリケーションが必要です。それがplaygroundディレクトリの目的です。これは、すでにモジュールと一緒に実行するように設定されたNuxtアプリケーションです。

playgroundを通常のNuxtアプリケーションのように操作できます。

  • npm run devで開発サーバーを起動し、srcディレクトリでモジュールに変更を加えると自動的にリロードされます
  • npm run dev:buildでビルドします

他のすべてのnuxtコマンドはplaygroundディレクトリに対して使用できます(例:nuxt <COMMAND> playground)。便利なようにpackage.json内に追加のdev:*スクリプトを宣言しても構いません。

テスト方法

モジュールスターターには基本的なテストスイートが付属しています:

  • ESLintによるリンター、npm run lintで実行します
  • Vitestによるテストランナー、npm run testまたはnpm run test:watchで実行します

このデフォルトのテスト戦略を必要に応じて拡張しても構いません。

ビルド方法

Nuxtモジュールには、@nuxt/module-builderによって提供される独自のビルダーが付属しています。このビルダーは、あなたの側での設定を必要とせず、TypeScriptをサポートし、他のNuxtアプリケーションに配布するためにアセットが適切にバンドルされることを保証します。

npm run prepackを実行してモジュールをビルドできます。

モジュールをビルドすることが役立つ場合もありますが、ほとんどの場合、自分でビルドする必要はありません:開発中はplaygroundがそれを処理し、公開時にはリリーススクリプトがそれをカバーします。

公開方法

モジュールをnpmに公開する前に、npmjs.comのアカウントを持ち、npm loginでローカルに認証されていることを確認してください。

モジュールのバージョンを上げてnpm publishコマンドを使用してモジュールを公開することもできますが、モジュールスターターには、モジュールの動作するバージョンをnpmに公開することを確認するためのリリーススクリプトが付属しています。

リリーススクリプトを使用するには、まずすべての変更をコミットします(自動バージョンアップと変更ログの更新を利用するためにConventional Commitsに従うことをお勧めします)、次にnpm run releaseでリリーススクリプトを実行します。

リリーススクリプトを実行すると、次のことが行われます:

  • まず、テストスイートを実行します:
    • リンターを実行します(npm run lint
    • 単体テスト、統合テスト、e2eテストを実行します(npm run test
    • モジュールをビルドします(npm run prepack
  • 次に、テストスイートが正常に終了した場合、次の手順でモジュールを公開します:
    • モジュールのバージョンを上げ、Conventional Commitsに基づいて変更ログを生成します
    • モジュールをnpmに公開します(この目的のために、モジュールは再度ビルドされ、公開されたアーティファクトに更新されたバージョン番号が考慮されることを保証します)
    • 新しく公開されたバージョンを表すgitタグをgitリモートオリジンにプッシュします

他のスクリプトと同様に、package.json内のデフォルトのreleaseスクリプトを必要に応じて微調整しても構いません。

モジュールの開発

Nuxtモジュールは、Nuxtアプリケーションをあらゆる方法で変更するための強力なAPIとパターンを備えています。このセクションでは、それらを活用する方法を学びます。

モジュールの構造

Nuxtモジュールには2種類あります:

いずれの場合も、その構造は似ています。

モジュール定義

スターターを使用する場合、モジュール定義はsrc/module.tsにあります。

モジュール定義は、モジュールのエントリーポイントです。これは、Nuxt設定内でモジュールが参照されたときにNuxtによってロードされるものです。

低レベルでは、Nuxtモジュール定義は、インラインユーザーオプションとNuxtと対話するためのnuxtオブジェクトを受け入れる、単純で非同期の可能性がある関数です。

export default function (inlineOptions, nuxt) {
  // ここで好きなことを行うことができます...
  console.log(inlineOptions.token) // `123`
  console.log(nuxt.options.dev) // `true`または`false`
  nuxt.hook('ready', async nuxt => {
    console.log('Nuxt is ready')
  })
}

この関数に対する型ヒントのサポートを得るには、Nuxt Kitによって提供される高レベルのdefineNuxtModuleヘルパーを使用します。

import { defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule((options, nuxt) => {
  nuxt.hook('pages:extend', pages => {
    console.log(`Discovered ${pages.length} pages`)
  })
})

ただし、この低レベルの関数定義を使用することはお勧めしません。代わりに、モジュールを定義するには、特にnpmに公開する場合、モジュールを識別するためのmetaプロパティを持つオブジェクト構文を使用することをお勧めします

このヘルパーは、モジュールに必要な多くの一般的なパターンを実装し、将来の互換性を保証し、モジュール作成者とユーザーの両方にとっての体験を向上させることで、Nuxtモジュールの記述をより簡単にします。

import { defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
  meta: {
    // 通常はモジュールのnpmパッケージ名
    name: '@nuxtjs/example',
    // `nuxt.config`内でモジュールオプションを保持するキー
    configKey: 'sample',
    // 互換性の制約
    compatibility: {
      // サポートされているnuxtバージョンのSemverバージョン
      nuxt: '>=3.0.0'
    }
  },
  // モジュールのデフォルト設定オプション、これらを返す関数であることも可能
  defaults: {},
  // Nuxtフックを登録するためのショートハンドシュガー
  hooks: {},
  // モジュールロジックを保持する関数、非同期であることも可能
  setup(moduleOptions, nuxt) {
    // ...
  }
})

最終的にdefineNuxtModuleは、低レベルの(inlineOptions, nuxt)モジュールシグネチャを持つラッパー関数を返します。このラッパー関数は、setup関数を呼び出す前にデフォルトやその他の必要なステップを適用します:

  • モジュールオプションを自動的にマージするためのdefaultsmeta.configKeyのサポート
  • 型ヒントと自動型推論
  • 基本的なNuxt 2互換性のためのシムを追加
  • meta.nameまたはmeta.configKeyから計算された一意のキーを使用してモジュールが一度だけインストールされることを保証
  • Nuxtフックを自動的に登録
  • モジュールメタに基づいて互換性の問題を自動的にチェック
  • Nuxtの内部使用のためにgetOptionsgetMetaを公開
  • 最新バージョンの@nuxt/kitからdefineNuxtModuleを使用している限り、後方および上方互換性を保証
  • モジュールビルダーツールとの統合

ランタイムディレクトリ

スターターを使用する場合、ランタイムディレクトリはsrc/runtimeにあります。

モジュールは、Nuxt設定内の他のすべてと同様に、アプリケーションのランタイムに含まれません。ただし、モジュールをインストールしたアプリケーションにランタイムコードを提供または注入したい場合があります。それがランタイムディレクトリの役割です。

ランタイムディレクトリ内では、Nuxtアプリに関連するあらゆる種類のアセットを提供できます:

サーバーエンジンNitroには:

  • APIルート
  • ミドルウェア
  • Nitroプラグイン

または、ユーザーのNuxtアプリケーションに注入したい他の種類のアセット:

  • スタイルシート
  • 3Dモデル
  • 画像
  • など

これらのアセットをすべてアプリケーション内に注入することができます。モジュール定義から。

アセットの注入についてはレシピセクションで詳しく学びましょう。

公開されたモジュールは、ランタイムディレクトリ内のアセットに対して自動インポートを利用できません。代わりに、#importsなどから明示的にインポートする必要があります。 :br :br 実際、自動インポートはパフォーマンス上の理由からnode_modules内のファイル(公開されたモジュールが最終的に存在する場所)には有効ではありません。

ツール

モジュールには、その開発を支援するための一連のファーストパーティツールが付属しています。

@nuxt/module-builder

Nuxt Module Builderは、モジュールをビルドして出荷するためのゼロ設定のビルドツールで、すべての重労働を引き受けます。Nuxtアプリケーションとの適切な互換性を確保します。

@nuxt/kit

Nuxt Kitは、モジュールがNuxtアプリケーションと対話するのを助けるためのコンポーザブルユーティリティを提供します。可能な限り手動の代替手段よりもNuxt Kitユーティリティを使用することをお勧めします。これにより、モジュールの互換性とコードの可読性が向上します。

こちらも参照 guide > going-further > kit

@nuxt/test-utils

Nuxt Test Utilsは、モジュールテスト内でNuxtアプリケーションをセットアップして実行するのを助けるユーティリティのコレクションです。

レシピ

ここでは、モジュールを作成する際に使用される一般的なパターンを紹介します。

Nuxt設定の変更

Nuxt設定はモジュールによって読み取られ、変更されることがあります。以下は、実験的な機能を有効にするモジュールの例です。

import { defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    // `experimental`オブジェクトがまだ存在しない場合は作成します
    nuxt.options.experimental ||= {}
    nuxt.options.experimental.componentIslands = true
  }
})

より複雑な設定の変更を処理する必要がある場合は、defuを使用することを検討してください。

Nuxt設定の変更に関するVue Schoolのビデオを視聴してください。

ランタイムへのオプションの公開

モジュールはアプリケーションのランタイムの一部ではないため、そのオプションもランタイムの一部ではありません。ただし、多くの場合、ランタイムコード内でこれらのモジュールオプションの一部にアクセスする必要があります。NuxtのruntimeConfigを使用して必要な設定を公開することをお勧めします。

import { defineNuxtModule } from '@nuxt/kit'
import { defu } from 'defu'

export default defineNuxtModule({
  setup (options, nuxt) {
    nuxt.options.runtimeConfig.public.myModule = defu(nuxt.options.runtimeConfig.public.myModule, {
      foo: options.foo
    })
  }
})

ユーザーが提供するパブリックランタイム設定を上書きするのではなく、defuを使用して拡張していることに注意してください。

その後、プラグイン、コンポーネント、アプリケーション内で他のランタイム設定と同様にモジュールオプションにアクセスできます:

const options = useRuntimeConfig().public.myModule

パブリックランタイム設定に公開する際には、プライベートAPIキーなどの機密性の高いモジュール設定を公開しないように注意してください。これらはパブリックバンドルに含まれることになります。

こちらも参照 guide > going-further > runtime-config

Nuxtモジュールオプションの受け渡しと公開に関するVue Schoolのビデオを視聴してください。

addPluginを使用したプラグインの注入

プラグインは、モジュールがランタイムロジックを追加する一般的な方法です。addPluginユーティリティを使用して、モジュールからプラグインを登録できます。

import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    // 相対パスを解決するためのリゾルバを作成
    const resolver = createResolver(import.meta.url)

    addPlugin(resolver.resolve('./runtime/plugin'))
  }
})
こちらも参照 guide > going-further > kit

addComponentを使用したVueコンポーネントの注入

モジュールがVueコンポーネントを提供する必要がある場合、addComponentユーティリティを使用して、Nuxtが解決するための自動インポートとして追加できます。

import { defineNuxtModule, addComponent } from '@nuxt/kit'

export default defineNuxtModule({
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    // ランタイムディレクトリから
    addComponent({
      name: 'MySuperComponent', // vueテンプレートで使用されるコンポーネントの名前
      export: 'MySuperComponent', // (オプション)コンポーネントが名前付き(デフォルトではない)エクスポートの場合
      filePath: resolver.resolve('runtime/components/MySuperComponent.vue')
    })

    // ライブラリから
    addComponent({
      name: 'MyAwesomeComponent', // vueテンプレートで使用されるコンポーネントの名前
      export: 'MyAwesomeComponent', // (オプション)コンポーネントが名前付き(デフォルトではない)エクスポートの場合
      filePath: '@vue/awesome-components'
    })
  }
})

または、addComponentsDirを使用してディレクトリ全体を追加することもできます。

import { defineNuxtModule, addComponentsDir } from '@nuxt/kit'

export default defineNuxtModule({
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    addComponentsDir({
      path: resolver.resolve('runtime/components')
    })
  }
})

addImportsaddImportsDirを使用したコンポーザブルの注入

モジュールがコンポーザブルを提供する必要がある場合、addImportsユーティリティを使用して、Nuxtが解決するための自動インポートとして追加できます。

import { defineNuxtModule, addImports, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    addImports({
      name: 'useComposable', // 使用されるコンポーザブルの名前
      as: 'useComposable',
      from: resolver.resolve('runtime/composables/useComposable') // コンポーザブルのパス
    })
  }
})

または、addImportsDirを使用してディレクトリ全体を追加することもできます。

import { defineNuxtModule, addImportsDir, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    addImportsDir(resolver.resolve('runtime/composables'))
  }
})

addServerHandlerを使用したサーバールートの注入

import { defineNuxtModule, addServerHandler, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    addServerHandler({
      route: '/api/hello',
      handler: resolver.resolve('./runtime/server/api/hello/index.get')
    })
  }
})

動的なサーバールートを追加することもできます:

import { defineNuxtModule, addServerHandler, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    addServerHandler({
      route: '/api/hello/:name',
      handler: resolver.resolve('./runtime/server/api/hello/[name].get')
    })
  }
})

他のアセットの注入

モジュールが他の種類のアセットを提供する必要がある場合、それらも注入できます。以下は、Nuxtのcss配列を通じてスタイルシートを注入するシンプルなモジュールの例です。

import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    const resolver = createResolver(import.meta.url)

    nuxt.options.css.push(resolver.resolve('./runtime/style.css'))
  }
})

そして、NitropublicAssetsオプションを通じてアセットのフォルダを公開するより高度な例:

import { defineNuxtModule, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    const resolver = createResolver(import.meta.url)

    nuxt.hook('nitro:config', async (nitroConfig) => {
      nitroConfig.publicAssets ||= []
      nitroConfig.publicAssets.push({
        dir: resolver.resolve('./runtime/public'),
        maxAge: 60 * 60 * 24 * 365 // 1年
      })
    })
  }
})

モジュール内で他のモジュールを使用する

モジュールが他のモジュールに依存している場合、Nuxt KitのinstallModuleユーティリティを使用してそれらを追加できます。たとえば、モジュール内でNuxt Tailwindを使用したい場合、以下のように追加できます:

import { defineNuxtModule, createResolver, installModule } from '@nuxt/kit'

export default defineNuxtModule<ModuleOptions>({
  async setup (options, nuxt) {
    const resolver = createResolver(import.meta.url)

    // Tailwindのディレクティブを含むCSSファイルを注入できます
    nuxt.options.css.push(resolver.resolve('./runtime/assets/styles.css'))

    await installModule('@nuxtjs/tailwindcss', {
      // モジュール設定
      exposeConfig: true,
      config: {
        darkMode: 'class',
        content: {
          files: [
            resolver.resolve('./runtime/components/**/*.{vue,mjs,ts}'),
            resolver.resolve('./runtime/*.{mjs,js,ts}')
          ]
        }
      }
    })
  }
})

フックの使用

ライフサイクルフックを使用すると、Nuxtのほぼすべての側面を拡張できます。モジュールはプログラム的に、または定義内のhooksマップを通じてフックすることができます。

import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  // `hooks`マップを通じて`app:error`フックにフック
  hooks: {
    'app:error': (err) => {
      console.info(`This error happened: ${err}`);
    }
  },
  setup (options, nuxt) {
    // プログラム的に`pages:extend`フックにフック
    nuxt.hook('pages:extend', (pages) => {
      console.info(`Discovered ${pages.length} pages`);
    })
  }
})
こちらも参照 api > advanced > hooks

モジュール内でNuxtライフサイクルフックを使用する方法に関するVue Schoolのビデオを視聴してください。

モジュールのクリーンアップ :br :br モジュールがウォッチャーを開いたり、処理したり、開始したりする場合、Nuxtライフサイクルが終了したときにそれを閉じる必要があります。このためにcloseフックが利用可能です。

import { defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    nuxt.hook('close', async nuxt => {
      // カスタムコードをここに
    })
  }
})

テンプレート/仮想ファイルの追加

ユーザーのアプリにインポートできる仮想ファイルを追加する必要がある場合、addTemplateユーティリティを使用できます。

import { defineNuxtModule, addTemplate } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    // ファイルはNuxtの内部仮想ファイルシステムに追加され、'#build/my-module-feature.mjs'からインポートできます
    addTemplate({
      filename: 'my-module-feature.mjs',
      getContents: () => 'export const myModuleFeature = () => "hello world !"'
    })
  }
})

サーバー用には、代わりにaddServerTemplateユーティリティを使用する必要があります。

import { defineNuxtModule, addServerTemplate } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    // ファイルはNitroの仮想ファイルシステムに追加され、サーバーコードから'my-server-module.mjs'としてインポートできます
    addServerTemplate({
      filename: 'my-server-module.mjs',
      getContents: () => 'export const myServerModule = () => "hello world !"'
    })
  }
})

型宣言の追加

ユーザーのプロジェクトに型宣言を追加したい場合(例えば、Nuxtインターフェースを拡張したり、独自のグローバル型を提供したりする場合)、NuxtはaddTypeTemplateユーティリティを提供しており、これによりテンプレートをディスクに書き込み、生成されたnuxt.d.tsファイルに参照を追加します。

モジュールがNuxtによって処理される型を拡張する必要がある場合、addTypeTemplateを使用してこの操作を実行できます:

import { defineNuxtModule, addTemplate, addTypeTemplate } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    addTypeTemplate({
      filename: 'types/my-module.d.ts',
      getContents: () => `// Generated by my-module
        interface MyModuleNitroRules {
          myModule?: { foo: 'bar' }
        }
        declare module 'nitropack' {
          interface NitroRouteRules extends MyModuleNitroRules {}
          interface NitroRouteConfig extends MyModuleNitroRules {}
        }
        export {}`
    })
  }
})

より細かい制御が必要な場合は、prepare:typesフックを使用して、型を注入するコールバックを登録できます。

const template = addTemplate({ /* template options */ })
nuxt.hook('prepare:types', ({ references }) => {
  references.push({ path: template.dst })
})
テンプレートの更新

テンプレート/仮想ファイルを更新する必要がある場合、updateTemplatesユーティリティを次のように活用できます:

nuxt.hook('builder:watch', async (event, path) => {
  if (path.includes('my-module-feature.config')) {
    // 登録したテンプレートをリロードします
    updateTemplates({ filter: t => t.filename === 'my-module-feature.mjs' })
  }
})

テスト

テストは、さまざまなセットアップでモジュールが期待通りに動作することを確認するのに役立ちます。このセクションでは、モジュールに対してさまざまな種類のテストを実行する方法を紹介します。

単体テストと統合テスト

Nuxtモジュールの単体テストと統合テストを簡単にする方法をまだ議論し、探求しています。 :br :br このRFCをチェックして会話に参加してください

エンドツーエンド

Nuxt Test Utilsは、モジュールをエンドツーエンドでテストするためのライブラリです。以下はそれを使用するためのワークフローです:

  1. test/fixtures/*内に"フィクスチャ"として使用するNuxtアプリケーションを作成します
  2. テストファイル内でこのフィクスチャを使用してNuxtをセットアップします
  3. @nuxt/test-utilsからのユーティリティを使用してフィクスチャと対話します(例:ページをフェッチする)
  4. このフィクスチャに関連するチェックを実行します(例:"HTMLに...が含まれている")
  5. 繰り返します

実際のフィクスチャ:

test/fixtures/ssr/nuxt.config.ts
// 1. フィクスチャとして使用するNuxtアプリケーションを作成
import MyModule from '../../../src/module'

export default defineNuxtConfig({
  ssr: true,
  modules: [
    MyModule
  ]
})

そしてそのテスト:

test/rendering.ts
import { describe, it, expect } from 'vitest'
import { fileURLToPath } from 'node:url'
import { setup, $fetch } from '@nuxt/test-utils/e2e'

describe('ssr', async () => {
  // 2. テストファイル内でこのフィクスチャを使用してNuxtをセットアップ
  await setup({
    rootDir: fileURLToPath(new URL('./fixtures/ssr', import.meta.url)),
  })

  it('renders the index page', async () => {
    // 3. `@nuxt/test-utils`からのユーティリティを使用してフィクスチャと対話
    const html = await $fetch('/')

    // 4. このフィクスチャに関連するチェックを実行
    expect(html).toContain('<div>ssr</div>')
  })
})

// 5. 繰り返します
describe('csr', async () => { /* ... */ })

このようなワークフローの例は、モジュールスターターで利用可能です。

Playgroundと外部での手動QA

モジュールを開発する際にテストするためのPlayground Nuxtアプリケーションを持つことは非常に便利です。モジュールスターターにはその目的のために統合されています

モジュールを他のNuxtアプリケーション(モジュールリポジトリの一部ではないアプリケーション)でローカルにテストすることができます。これを行うには、npm packコマンド、またはパッケージマネージャーの同等のコマンドを使用して、モジュールからtarballを作成します。その後、テストプロジェクトで、package.jsonのパッケージとしてモジュールを次のように追加できます:"my-module": "file:/path/to/tarball.tgz"

その後、通常のプロジェクトのようにmy-moduleを参照できるはずです。

ベストプラクティス

大きな力には大きな責任が伴います。モジュールは強力ですが、アプリケーションのパフォーマンスを維持し、開発者の体験を向上させるために、モジュールを作成する際に心に留めておくべきベストプラクティスを以下に示します。

非同期モジュール

見てきたように、Nuxtモジュールは非同期であることができます。たとえば、APIをフェッチしたり、非同期関数を呼び出す必要があるモジュールを開発したい場合があります。

ただし、非同期の動作には注意が必要です。Nuxtは、次のモジュールに進んで開発サーバーの開始やビルドプロセスを開始する前に、モジュールのセットアップを待ちます。時間のかかるロジックはNuxtフックに遅延させることをお勧めします。

モジュールのセットアップに1秒以上かかる場合、Nuxtは警告を発します。

露出するインターフェースには常にプレフィックスを付ける

Nuxtモジュールは、他のモジュールや内部と競合しないように、露出する設定、プラグイン、API、コンポーザブル、またはコンポーネントに明示的なプレフィックスを提供する必要があります。

理想的には、モジュールの名前でプレフィックスを付けるべきです(例:モジュールがnuxt-fooと呼ばれる場合、<FooButton>useFooBar()を公開し、<Button>useBar()を公開しない)。

TypeScriptに優しい

Nuxtは、最高の開発者体験のためにTypeScriptを第一級で統合しています。

型を公開し、TypeScriptを使用してモジュールを開発することは、直接TypeScriptを使用していない場合でもユーザーに利益をもたらします。

CommonJS構文を避ける

NuxtはネイティブESMに依存しています。詳細についてはネイティブESモジュールをお読みください。

モジュールの使用法を文書化する

モジュールの使用法をreadmeファイルに文書化することを検討してください:

  • なぜこのモジュールを使用するのか?
  • このモジュールをどのように使用するのか?
  • このモジュールは何をするのか?

統合ウェブサイトとドキュメントへのリンクを追加することは常に良いアイデアです。

StackBlitzデモまたはボイラープレートを提供する

モジュールとStackBlitzを使用した最小限の再現を作成し、モジュールのreadmeに追加することは良いプラクティスです。

これは、モジュールの潜在的なユーザーにモジュールを簡単に試す方法を提供するだけでなく、問題が発生したときに最小限の再現を作成して送信する簡単な方法も提供します。

特定のNuxtバージョンで宣伝しない

Nuxt、Nuxt Kit、および他の新しいツールは、前方および後方互換性を念頭に置いて作られています。

エコシステムの断片化を避けるために、「Nuxt用のX」を使用し、「Nuxt 3用のX」を使用しないでください。また、Nuxtバージョンの制約を設定するためにmeta.compatibilityを使用することをお勧めします。

スターターデフォルトに従う

モジュールスターターには、デフォルトのツールと設定(例:ESLint設定)が付属しています。モジュールをオープンソース化する予定がある場合、これらのデフォルトに従うことで、他のコミュニティモジュールと一貫したコーディングスタイルを共有し、他の人が貢献しやすくなります。

エコシステム

Nuxtモジュールエコシステムは、月間1500万以上のNPMダウンロードを誇り、さまざまなツールとの拡張機能と統合を提供しています。あなたもこのエコシステムの一部になることができます!

Nuxtモジュールの種類に関するVue Schoolのビデオを視聴してください。

モジュールの種類

公式モジュールは、@nuxt/(例:@nuxt/content)でプレフィックス(スコープ)されたモジュールです。これらはNuxtチームによって作成され、積極的にメンテナンスされています。フレームワークと同様に、コミュニティからの貢献は大歓迎で、より良いものにするために役立ちます!

コミュニティモジュールは、@nuxtjs/(例:@nuxtjs/tailwindcss)でプレフィックス(スコープ)されたモジュールです。これらは、コミュニティメンバーによって作成され、メンテナンスされている実績のあるモジュールです。ここでも、誰からの貢献も歓迎されます。

サードパーティおよびその他のコミュニティモジュールは、(多くの場合)nuxt-でプレフィックスされたモジュールです。誰でもこれらを作成でき、このプレフィックスを使用することで、これらのモジュールはnpmで発見可能になります。アイデアをドラフトし、試すための最良の出発点です!

プライベートまたは個人用モジュールは、独自のユースケースや会社のために作成されたモジュールです。これらはNuxtと連携するために特定の命名規則に従う必要はなく、npm組織(例:@my-company/nuxt-auth)の下にスコープされることがよくあります。

コミュニティモジュールのリスト化

コミュニティモジュールはすべてモジュールリストにリストされることを歓迎します。リストされるには、nuxt/modulesリポジトリでissueを開いてください。Nuxtチームはリスト化前にベストプラクティスを適用するのを手伝います。

nuxt-modules@nuxtjs/への参加

モジュールをnuxt-modulesに移動することで、常に誰かが助けてくれるようになり、この方法で完璧なソリューションを作るために力を合わせることができます。

すでに公開され、動作しているモジュールを持っていて、それをnuxt-modulesに移行したい場合、nuxt/modulesでissueを開いてください

nuxt-modulesに参加することで、コミュニティモジュールを@nuxtjs/スコープの下にリネームし、そのドキュメントのためにサブドメイン(例:my-module.nuxtjs.org)を提供できます。

tips

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

Nuxtモジュール作成の補足解説

Nuxtのモジュール機能は、アプリケーションの拡張やカスタマイズを強力にサポートします。公式ドキュメントでは基本的な作成方法やスターターの使い方が紹介されていますが、本記事では実務での活用を念頭に置き、より具体的な使いどころや注意点、よくある落とし穴について詳しく解説します。


1. イントロ:Nuxtモジュールで何が嬉しいのか?

Nuxtモジュールを使う最大のメリットは、プロジェクトの拡張性と再利用性が飛躍的に向上することです。例えば、CMS連携や認証機能、カスタムAPIルートの追加など、複雑な機能をボイラープレートなしで簡単に組み込めます。

  • コードの分離と管理が容易になる
    モジュールとして機能を切り出すことで、メンテナンスやテストがしやすくなります。

  • 複数プロジェクト間での共有が可能
    npmパッケージとして公開すれば、社内外の他プロジェクトでも同じ機能を簡単に導入できます。

  • Nuxtの設定やフックを活用した柔軟な拡張
    Nuxtの設定やライフサイクルフックを利用して、アプリケーションのあらゆる段階で処理を差し込めます。


2. まず結論:Nuxtモジュール作成の要点

  • モジュールはNuxtの設定やフックを通じて機能を拡張する関数として実装する
  • 開発には公式のスターターテンプレートを使うと効率的
  • playgroundディレクトリで動作確認しながら開発できる
  • テスト(ESLint、Vitest)を組み込み、品質を保つことが重要
  • ビルドは@nuxt/module-builderが自動で対応、公開時にnpm publishで配布可能
  • リリースはConventional Commitsに準拠すると自動化がスムーズ

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

使うべきケース

  • 複数のNuxtプロジェクトで共通の機能を使いたいとき
  • Nuxtの設定やビルドプロセスに介入してカスタマイズしたいとき
  • 大規模な機能を分離して保守性を高めたいとき
  • 外部サービスやAPIとの統合をパッケージ化したいとき

避けたほうがよいケース

  • 単一プロジェクト内でしか使わない小さな機能(単純なプラグインやミックスインで十分な場合)
  • モジュール化のコストが機能の複雑さに見合わない場合
  • 既存の公式モジュールやコミュニティモジュールで十分な場合

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

ユースケース1:CMS連携モジュールの作成

複数プロジェクトで同じCMSを使う場合、APIクライアントの設定や認証処理をモジュールにまとめると便利です。

export default function MyCmsModule() {
  this.nuxt.hook('ready', async () => {
    // CMSクライアントの初期化
    const cmsClient = createCmsClient(this.options.cms)
    this.nuxt.provide('cms', cmsClient)
  })

  this.extendBuild((config) => {
    // CMS関連のビルド設定を追加
  })
}

ユースケース2:カスタムAPIルートの追加

サーバーサイドで独自のAPIエンドポイントを追加したい場合、モジュールでサーバールートを登録できます。

export default function CustomApiModule() {
  this.addServerHandler({
    route: '/api/custom',
    handler: '~/server/api/custom.ts'
  })
}

ユースケース3:Vueプラグインの自動登録

共通のVueプラグインを複数プロジェクトで使う場合、モジュールでプラグイン登録を自動化します。

export default function VuePluginModule() {
  this.addPlugin({
    src: resolve(__dirname, 'plugins/my-plugin.js'),
    mode: 'client'
  })
}

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

SSRとCSRの違いに注意

モジュールで追加したコードがサーバーサイドレンダリング(SSR)とクライアントサイドレンダリング(CSR)のどちらで実行されるかを意識しましょう。例えば、ブラウザAPIを使うコードはSSRでエラーになるため、mode: 'client'指定や実行環境の判定が必要です。

Hydrationエラーの原因に

モジュールで動的にコンポーネントやプラグインを追加すると、SSRとCSRで差異が生じてHydrationエラーが発生することがあります。状態管理や非同期処理の扱いに注意してください。

パフォーマンスへの影響

モジュールが大量の依存や重い処理を追加すると、ビルド時間や初期ロードに影響します。必要な機能だけを絞り込み、遅延ロードや条件付き登録を検討しましょう。

テストの重要性

モジュールはNuxtのコアに影響を与えるため、Lintやユニットテスト、統合テストを必ず実施し、品質を担保してください。


6. まとめ

Nuxtモジュールは、アプリケーションの拡張性と再利用性を高める強力な仕組みです。公式スターターを活用しつつ、実務でのユースケースや注意点を理解して開発すれば、保守性の高いモジュールを効率的に作成できます。SSR/CSRの違いやパフォーマンス面の配慮も忘れずに、テストを充実させることが成功の鍵です。


モジュール開発は最初は難しく感じるかもしれませんが、Nuxtの設定やフックの仕組みを理解し、公式スターターを活用することでスムーズに進められます。まずは小さな機能から試してみましょう。


title: 'Nuxtモジュール開発の実務的ガイド:基礎から応用まで' description: 'Nuxtモジュール開発の基本的な構造から実務での活用例、注意点までを丁寧に解説。初〜中級者が理解しやすいように、具体的なユースケースやパフォーマンス面の考慮も含めて紹介します。'

Nuxtモジュール開発の実務的ガイド:基礎から応用まで

Nuxtはモジュールシステムを通じて、アプリケーションの機能拡張やカスタマイズを強力にサポートしています。モジュールを活用することで、共通機能の再利用や設定の一元管理が可能になり、開発効率や保守性が大幅に向上します。

本記事では、Nuxtモジュール開発の基本的な構造や使いどころ、実務でよくあるユースケースを具体的に解説し、さらに開発時に注意すべきポイントや落とし穴についても触れます。Nuxt公式ドキュメントの内容を補完し、より実践的な視点で理解を深めていただける内容です。


まず結論:Nuxtモジュール開発の要点

  • モジュールはNuxtアプリの拡張機能で、npm配布やローカル定義が可能
  • defineNuxtModuleヘルパーを使うことで型安全かつ互換性の高いモジュールを簡単に作成できる
  • ランタイムディレクトリを活用して、Vueコンポーネントやプラグイン、APIルートなどを注入可能
  • addPluginaddComponentなどのユーティリティで、Nuxtの設定やアセットを柔軟に拡張できる
  • モジュールオプションはruntimeConfigを通じてランタイムに安全に公開するのがベストプラクティス
  • 非同期処理はモジュールセットアップの遅延に注意し、重い処理はフックに遅延させるべき
  • モジュールの公開インターフェースには必ずプレフィックスを付けて名前衝突を防ぐ

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

使うべきケース

  • 複数のプロジェクトで共通利用したい機能や設定をまとめたいとき
  • Nuxtの設定やビルドプロセスをプログラム的に拡張したいとき
  • ランタイムにVueコンポーネントやプラグイン、APIエンドポイントを注入したいとき
  • 他のモジュールに依存しつつ機能を組み合わせて提供したいとき
  • チームやコミュニティで再利用可能なパッケージとして機能を切り出したいとき

使わない方がよいケース

  • 単一プロジェクト内だけで完結する簡単な機能拡張(プラグインやミドルウェアで十分な場合)
  • モジュールのセットアップに1秒以上かかる重い処理を同期的に行う場合(パフォーマンスに悪影響)
  • 機密情報をランタイム設定に誤って公開してしまうリスクがある場合(APIキーなど)

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

1. Nuxt設定の動的変更

モジュールからNuxtの設定を動的に変更し、実験的機能を有効化する例です。

import { defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    nuxt.options.experimental ||= {}
    nuxt.options.experimental.componentIslands = true
  }
})

このように、モジュール内でnuxt.optionsを直接操作することで、ビルドやランタイムの挙動を柔軟に制御できます。


2. ランタイム設定の公開と利用

モジュールのオプションをruntimeConfigのパブリック側に安全に公開し、アプリケーション内で利用する例です。

import { defineNuxtModule } from '@nuxt/kit'
import { defu } from 'defu'

export default defineNuxtModule({
  setup (options, nuxt) {
    nuxt.options.runtimeConfig.public.myModule = defu(nuxt.options.runtimeConfig.public.myModule, {
      foo: options.foo
    })
  }
})

アプリケーション側では以下のようにアクセス可能です。

const config = useRuntimeConfig().public.myModule
console.log(config.foo)

プライベートなAPIキーなどの機密情報は絶対にpublic側に公開しないでください。ブラウザにバンドルされてしまいます。


3. プラグインやコンポーネントの注入

モジュールからVueコンポーネントやプラグインをNuxtに登録する例です。

import { defineNuxtModule, addPlugin, addComponent, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    // プラグインの追加
    addPlugin(resolver.resolve('./runtime/plugin'))

    // コンポーネントの追加
    addComponent({
      name: 'MyWidget',
      filePath: resolver.resolve('./runtime/components/MyWidget.vue')
    })
  }
})

これにより、ユーザーはモジュールを導入するだけで自動的に機能が組み込まれます。


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

SSR/CSRやHydrationの問題

  • モジュールで注入したコンポーネントやプラグインがサーバーサイドレンダリング(SSR)に対応していない場合、Hydrationエラーが発生することがあります。
  • クライアント専用の処理は、runtimeConfigやプラグイン内で適切に条件分岐し、サーバー側で実行されないように注意してください。

パフォーマンスへの影響

  • モジュールのセットアップ処理が重いと、Nuxtの起動やビルドが遅延します。
  • 1秒以上かかる処理は非同期にし、可能ならNuxtのフック(例:ready)に遅延させるのが望ましいです。

名前衝突の防止

  • モジュールが公開するコンポーネント名やコンポーザブル名は必ずプレフィックスを付けて、他のモジュールやユーザーコードと衝突しないようにしましょう。
  • 例:モジュール名がnuxt-fooなら、<FooButton>useFooBar()のように命名する。

自動インポートの制限

  • 公開されたnpmモジュール内のランタイムディレクトリは自動インポートが効かないため、明示的にインポートする必要があります。
  • ローカルモジュールやプロジェクト内のモジュールでは自動インポートが利用可能です。

まとめ

Nuxtモジュールは、アプリケーションの拡張性を高める強力な仕組みです。defineNuxtModuleを活用し、ランタイムディレクトリや各種ユーティリティを駆使することで、設定変更からコンポーネント注入、APIルート追加まで幅広い機能を実装できます。

ただし、非同期処理の遅延や名前衝突、SSR対応などの注意点を押さえ、パフォーマンスと安全性を意識した設計が重要です。この記事の内容を参考に、実務で役立つモジュール開発をぜひ進めてみてください。


Nuxtモジュール開発の理解を深めるには、公式ドキュメントのNuxt Kitモジュールスターターも合わせて参照すると良いでしょう。


title: 'Nuxtモジュールエコシステムの活用と実務でのポイント解説' description: 'Nuxtのモジュールエコシステムは多彩な拡張機能を提供し、開発効率を大幅に向上させます。本記事ではモジュールの種類や使い分け、実務での活用例、注意点を詳しく解説します。'

Nuxtモジュールエコシステムの活用と実務でのポイント解説

Nuxtは豊富なモジュールエコシステムを持ち、これにより開発者は多様な機能を簡単にプロジェクトに組み込めます。モジュールを活用することで、手間のかかる設定や実装を省略し、より迅速に高品質なアプリケーションを構築可能です。

本記事では、Nuxtのモジュールエコシステムの概要から、実務での具体的な使い方、注意すべきポイントまでを丁寧に解説します。初〜中級者の方がモジュールを効果的に使いこなせるよう、実践的な視点を交えて説明します。


まず結論:Nuxtモジュールエコシステムの要点

  • 多様なモジュールが存在し、公式・コミュニティ・サードパーティ・プライベートに分類される
  • 公式モジュールはNuxtチームが管理し、安定性と信頼性が高い
  • コミュニティモジュールは活発にメンテナンスされており、最新技術を取り入れやすい
  • サードパーティモジュールは自由度が高く、実験的な機能も多いが品質は様々
  • プライベートモジュールは企業や個人の特定ニーズに対応可能
  • モジュールの選定はプロジェクトの要件やメンテナンス状況を考慮して行うべき
  • 実務では認証、スタイリング、コンテンツ管理などでモジュールがよく使われる
  • SSRやHydrationの挙動に注意し、パフォーマンス影響を把握することが重要

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

使うべきケース

  • 共通機能の導入を効率化したいとき
    例:認証、SEO対策、PWA対応、スタイリングフレームワークの統合など、よく使われる機能を素早く導入可能。

  • 複雑な設定や連携を簡単にしたいとき
    モジュールは設定の抽象化や依存関係の管理を自動化し、開発負荷を軽減。

  • コミュニティや公式の信頼できるソリューションを利用したいとき
    安定したメンテナンスとサポートが期待できる。

使わない方がよいケース

  • プロジェクト固有の特殊な要件がある場合
    汎用モジュールが合わず、カスタム実装が必要なことも。

  • モジュールのメンテナンスが停止している場合
    セキュリティリスクや将来的な互換性問題が発生する可能性がある。

  • パフォーマンスに厳しい要件があり、不要な機能を含むモジュールを避けたい場合
    モジュールの導入でバンドルサイズや初期ロードが増加することもあるため注意。


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

1. 認証機能の導入

認証は多くのアプリで必須機能ですが、実装は複雑です。@nuxtjs/auth-nextのような公式コミュニティモジュールを使うと、OAuthやJWT認証を簡単に統合できます。

// nuxt.config.js
export default {
  modules: ['@nuxtjs/auth-next'],
  auth: {
    strategies: {
      local: {
        token: {
          property: 'token',
          global: true,
        },
        user: {
          property: 'user',
        },
        endpoints: {
          login: { url: '/api/login', method: 'post' },
          user: { url: '/api/user', method: 'get' },
          logout: { url: '/api/logout', method: 'post' },
        },
      },
    },
  },
}

2. Tailwind CSSの統合

スタイリングフレームワークの導入もモジュールで簡単に。@nuxtjs/tailwindcssを使うと、設定不要でTailwind CSSが使えます。

// nuxt.config.js
export default {
  modules: ['@nuxtjs/tailwindcss'],
}

3. コンテンツ管理

@nuxt/contentモジュールを使うと、MarkdownやJSONなどのファイルを簡単にコンテンツとして扱え、ブログやドキュメントサイトの構築がスムーズです。

// nuxt.config.js
export default {
  modules: ['@nuxt/content'],
}

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

SSRとCSRの違いによる挙動の違い

モジュールによってはサーバーサイドレンダリング(SSR)とクライアントサイドレンダリング(CSR)で動作が異なる場合があります。例えば、ブラウザAPIを使うモジュールはSSR時にエラーになることがあるため、利用時は動作環境を確認しましょう。

Hydrationエラーの原因に注意

モジュールが生成するHTMLとクライアントでのレンダリング結果が異なるとHydrationエラーが発生します。特に動的に変わるデータを扱うモジュールは、SSRとCSRの差異を意識して実装する必要があります。

パフォーマンスへの影響

モジュールは便利ですが、不要な機能まで含むことがあり、バンドルサイズ増加や初期ロード時間の延長につながることがあります。導入前に依存関係や影響範囲を調査し、必要最低限のモジュールを選ぶことが重要です。

メンテナンス状況の確認

コミュニティやサードパーティのモジュールはメンテナンスが不十分な場合もあります。セキュリティや互換性の観点から、導入前にGitHubの更新頻度やIssueの対応状況をチェックしましょう。


まとめ

Nuxtのモジュールエコシステムは、開発効率を大幅に向上させる強力な武器です。公式やコミュニティの信頼できるモジュールを活用しつつ、プロジェクトの要件に合わせて適切に選択・運用することが成功の鍵となります。SSRやHydrationの挙動、パフォーマンスへの影響にも注意しながら、実務での活用を進めてください。


モジュールは便利ですが、依存しすぎず、必要に応じて自作やカスタマイズも検討しましょう。
また、公式ドキュメントやコミュニティの最新情報を常にチェックすることが重要です。