Nuxt Nation カンファレンスが開催されます。11月12日~13日にご参加ください。

components

components/ ディレクトリには、すべての Vue コンポーネントを配置します。

Nuxt は、このディレクトリにあるすべてのコンポーネント(および、使用しているモジュールによって登録されたコンポーネント)を自動的にインポートします。

ディレクトリ構造
-| components/
---| AppHeader.vue
---| AppFooter.vue
app.vue
<template>
  <div>
    <AppHeader />
    <NuxtPage />
    <AppFooter />
  </div>
</template>

コンポーネント名

次のようなネストされたディレクトリにコンポーネントがある場合

ディレクトリ構造
-| components/
---| base/
-----| foo/
-------| Button.vue

... コンポーネントの名前は、重複するセグメントが削除された、自身のパスディレクトリとファイル名に基づいて決定されます。したがって、コンポーネントの名前は次のようになります

<BaseFooButton />
明確にするために、コンポーネントのファイル名がその名前に一致することを推奨します。そのため、上記の例では、Button.vueBaseFooButton.vue に名前を変更できます。

パスではなく名前のみに基づいてコンポーネントを自動インポートする場合は、構成オブジェクトの拡張フォームを使用して pathPrefix オプションを false に設定する必要があります

nuxt.config.ts
export default 
defineNuxtConfig
({
components
: [
{
path
: '~/components',
pathPrefix
: false,
}, ], });

これにより、Nuxt 2 で使用されていたのと同じ戦略を使用してコンポーネントが登録されます。たとえば、~/components/Some/MyComponent.vue<SomeMyComponent> ではなく <MyComponent> として使用できます。

動的コンポーネント

Vue の <component :is="someComputedComponent"> 構文を使用する場合は、Vue が提供する resolveComponent ヘルパーを使用するか、#components からコンポーネントを直接インポートし、それを is プロパティに渡す必要があります。

たとえば

pages/index.vue
<script setup lang="ts">
import { SomeComponent } from '#components'

const MyButton = resolveComponent('MyButton')
</script>

<template>
  <component :is="clickable ? MyButton : 'div'" />
  <component :is="SomeComponent" />
</template>
resolveComponent を使用して動的コンポーネントを処理する場合は、コンポーネントの名前以外のものを挿入しないでください。これは文字列であり、変数であってはなりません。
resolveComponent に関する Daniel Roe の短いビデオをご覧ください。

または、推奨されませんが、すべてのコンポーネントをグローバルに登録することもできます。これにより、すべてのコンポーネントに対して非同期チャンクが作成され、アプリケーション全体で使用できるようになります。

  export default defineNuxtConfig({
    components: {
+     global: true,
+     dirs: ['~/components']
    },
  })

~/components/global ディレクトリに配置するか、ファイル名に .global.vue サフィックスを使用することで、一部のコンポーネントを選択的にグローバルに登録することもできます。上記のように、各グローバルコンポーネントは個別のチャンクでレンダリングされるため、この機能を過度に使用しないように注意してください。

global オプションは、コンポーネントディレクトリごとに設定することもできます。

動的インポート

コンポーネントを動的にインポートする(コンポーネントの遅延読み込みとも呼ばれます)には、コンポーネントの名前に Lazy プレフィックスを追加するだけで済みます。これは、コンポーネントが常に必要ではない場合に特に役立ちます。

Lazy プレフィックスを使用すると、適切なタイミングまでコンポーネントコードの読み込みを遅らせることができ、JavaScriptバンドルサイズの最適化に役立ちます。

pages/index.vue
<script setup lang="ts">
const show = ref(false)
</script>

<template>
  <div>
    <h1>Mountains</h1>
    <LazyMountainsList v-if="show" />
    <button v-if="!show" @click="show = true">Show List</button>
  </div>
</template>

直接インポート

Nuxt の自動インポート機能をバイパスしたい場合や、必要な場合は、#components からコンポーネントを明示的にインポートすることもできます。

pages/index.vue
<script setup lang="ts">
import { NuxtLink, LazyMountainsList } from '#components'

const show = ref(false)
</script>

<template>
  <div>
    <h1>Mountains</h1>
    <LazyMountainsList v-if="show" />
    <button v-if="!show" @click="show = true">Show List</button>
    <NuxtLink to="/">Home</NuxtLink>
  </div>
</template>

カスタムディレクトリ

デフォルトでは、~/components ディレクトリのみがスキャンされます。他のディレクトリを追加したり、このディレクトリのサブフォルダー内でコンポーネントをスキャンする方法を変更したりする場合は、追加のディレクトリを構成に追加できます

nuxt.config.ts
export default 
defineNuxtConfig
({
components
: [
// ~/calendar-module/components/event/Update.vue => <EventUpdate /> {
path
: '~/calendar-module/components' },
// ~/user-module/components/account/UserDeleteDialog.vue => <UserDeleteDialog /> {
path
: '~/user-module/components',
pathPrefix
: false },
// ~/components/special-components/Btn.vue => <SpecialBtn /> {
path
: '~/components/special-components',
prefix
: 'Special' },
// It's important that this comes last if you have overrides you wish to apply // to sub-directories of `~/components`. // // ~/components/Btn.vue => <Btn /> // ~/components/base/Btn.vue => <BaseBtn /> '~/components' ] })

npm パッケージ

npm パッケージからコンポーネントを自動インポートする場合は、addComponentローカルモジュール で使用して登録できます。

import { 
addComponent
,
defineNuxtModule
} from '@nuxt/kit'
export default
defineNuxtModule
({
setup
() {
// import { MyComponent as MyAutoImportedComponent } from 'my-npm-package'
addComponent
({
name
: 'MyAutoImportedComponent',
export
: 'MyComponent',
filePath
: 'my-npm-package',
}) }, })
ネストされたディレクトリは、スキャンされる順序どおりに最初に追加する必要があります。

コンポーネント拡張機能

デフォルトでは、nuxt.config.ts の extensions キー で指定された拡張子を持つすべてのファイルは、コンポーネントとして扱われます。コンポーネントとして登録する必要があるファイル拡張子を制限する必要がある場合は、コンポーネントディレクトリ宣言とその extensions キーの拡張形式を使用できます

nuxt.config.ts
export default 
defineNuxtConfig
({
components
: [
{
path
: '~/components',
extensions
: ['.vue'],
} ] })

クライアントコンポーネント

コンポーネントがクライアント側でのみレンダリングされることを意図している場合は、コンポーネントに .client サフィックスを追加できます。

ディレクトリ構造
| components/
--| Comments.client.vue
pages/example.vue
<template>
  <div>
    <!-- this component will only be rendered on client side -->
    <Comments />
  </div>
</template>
この機能は、Nuxt の自動インポートと #components インポートでのみ機能します。これらのコンポーネントを実際のパスから明示的にインポートしても、クライアントのみのコンポーネントには変換されません。
.client コンポーネントは、マウントされた後にのみレンダリングされます。onMounted() を使用してレンダリングされたテンプレートにアクセスするには、onMounted() フックのコールバックに await nextTick() を追加します。
<ClientOnly> コンポーネントを使用しても、同様の結果を得ることができます。

サーバーコンポーネント

サーバーコンポーネントを使用すると、クライアント側アプリ内で個々のコンポーネントをサーバーレンダリングできます。静的サイトを生成している場合でも、Nuxt 内でサーバーコンポーネントを使用できます。これにより、動的コンポーネント、サーバーレンダリングされたHTML、さらには静的なマークアップのチャンクを組み合わせた複雑なサイトを構築できます。

サーバーコンポーネントは、単独で使用することも、クライアントコンポーネントと組み合わせて使用することもできます。

Nuxt サーバーコンポーネントに関する Learn Vue のビデオをご覧ください。
Nuxt サーバーコンポーネントに関する Daniel Roe のガイドをご覧ください。

スタンドアロンサーバーコンポーネント

スタンドアロンサーバーコンポーネントは、常にサーバー上でレンダリングされます。これはアイランドコンポーネントとも呼ばれます。

プロパティが更新されると、これによりネットワークリクエストが発生し、レンダリングされたHTMLがインプレースで更新されます。

サーバーコンポーネントは現在実験段階であり、使用するには、nuxt.config で「コンポーネントアイランド」機能を有効にする必要があります

nuxt.config.ts
export default 
defineNuxtConfig
({
experimental
: {
componentIslands
: true
} })

これで、.server サフィックスを使用してサーバー専用コンポーネントを登録し、アプリケーション内の任意の場所で自動的に使用できるようになります。

ディレクトリ構造
-| components/
---| HighlightedMarkdown.server.vue
pages/example.vue
<template>
  <div>
    <!--
      this will automatically be rendered on the server, meaning your markdown parsing + highlighting
      libraries are not included in your client bundle.
     -->
    <HighlightedMarkdown markdown="# Headline" />
  </div>
</template>

サーバー専用コンポーネントは、内部的に <NuxtIsland> を使用します。つまり、lazy プロパティと #fallback スロットの両方が渡されます。

サーバーコンポーネント(およびアイランド)は、単一のルート要素を持つ必要があります。(HTMLコメントも要素と見なされます。)
各アイランドは追加のオーバーヘッドを追加するため、アイランドを別のアイランド内にネストする場合は注意してください。
スロットやクライアントコンポーネントなど、サーバー専用コンポーネントおよびアイランドコンポーネントのほとんどの機能は、単一ファイルコンポーネントでのみ使用できます。

サーバーコンポーネント内のクライアントコンポーネント

この機能を使用するには、設定内で experimental.componentIslands.selectiveClient を true にする必要があります。

nuxt-client 属性をクライアントサイドでロードしたいコンポーネントに設定することで、コンポーネントを部分的にハイドレーションできます。

components/ServerWithClient.vue
<template>
  <div>
    <HighlightedMarkdown markdown="# Headline" />
    <!-- Counter will be loaded and hydrated client-side -->
    <Counter nuxt-client :count="5" />
  </div>
</template>
これはサーバーコンポーネント内でのみ機能します。クライアントコンポーネントのスロットは、experimental.componentIsland.selectiveClient'deep' に設定されている場合にのみ機能し、サーバーサイドでレンダリングされるため、クライアントサイドになった後もインタラクティブにはなりません。

サーバーコンポーネントのコンテキスト

サーバー専用またはアイランドコンポーネントをレンダリングすると、<NuxtIsland>NuxtIslandResponse を返す fetch リクエストを行います。(これは、サーバー上でレンダリングされる場合は内部リクエストであり、クライアントサイドナビゲーションでレンダリングされる場合は、ネットワークタブで確認できるリクエストです。)

これは次のことを意味します。

  • NuxtIslandResponse を作成するために、新しい Vue アプリがサーバーサイドで作成されます。
  • コンポーネントをレンダリング中に、新しい「アイランドコンテキスト」が作成されます。
  • アプリの他の部分から「アイランドコンテキスト」にアクセスすることはできず、アイランドコンポーネントからアプリの他の部分のコンテキストにアクセスすることはできません。言い換えれば、サーバーコンポーネントまたはアイランドは、アプリの他の部分から分離されています。
  • env: { islands: false } が設定されている場合(オブジェクト構文のプラグインで設定できます)を除き、プラグインはアイランドをレンダリングする際に再び実行されます。

アイランドコンポーネント内では、nuxtApp.ssrContext.islandContext を通してそのアイランドコンテキストにアクセスできます。アイランドコンポーネントはまだ実験的な機能としてマークされているため、このコンテキストの形式は変更される可能性があることに注意してください。

スロットはインタラクティブにすることができ、display: contents; を持つ <div> でラップされます。

クライアントコンポーネントとの組み合わせ

この場合、.server + .client コンポーネントは、コンポーネントの2つの「半分」であり、サーバー側とクライアント側でコンポーネントの別々の実装を行う高度なユースケースで使用できます。

ディレクトリ構造
-| components/
---| Comments.client.vue
---| Comments.server.vue
pages/example.vue
<template>
  <div>
    <!-- this component will render Comments.server on the server then Comments.client once mounted in the browser -->
    <Comments />
  </div>
</template>

Nuxt組み込みコンポーネント

<ClientOnly><DevOnly> など、Nuxtが提供するコンポーネントがいくつかあります。詳細については、APIドキュメントを参照してください。

ドキュメント > API で詳細をご覧ください。

ライブラリ作成者向け

自動ツリーシェイキングとコンポーネント登録を備えた Vue コンポーネントライブラリの作成は非常に簡単です。✨

components:dirs フックを使用すると、Nuxt モジュールでユーザー設定を必要とせずに、ディレクトリリストを拡張できます。

次のようなディレクトリ構造を想像してください。

ディレクトリ構造
-| node_modules/
---| awesome-ui/
-----| components/
-------| Alert.vue
-------| Button.vue
-----| nuxt.js
-| pages/
---| index.vue
-| nuxt.config.js

次に、awesome-ui/nuxt.js で、components:dirs フックを使用できます。

import { 
defineNuxtModule
,
createResolver
} from '@nuxt/kit'
export default
defineNuxtModule
({
hooks
: {
'components:dirs': (
dirs
) => {
const {
resolve
} =
createResolver
(import.meta.
url
)
// Add ./components dir to the list
dirs
.
push
({
path
:
resolve
('./components'),
prefix
: 'awesome'
}) } } })

それだけです!これで、プロジェクトで、nuxt.config ファイルに Nuxt モジュールとして UI ライブラリをインポートできます。

nuxt.config.ts
export default 
defineNuxtConfig
({
modules
: ['awesome-ui/nuxt']
})

... そして、pages/index.vue でモジュールコンポーネント(awesome- というプレフィックス付き)を直接使用できます。

<template>
  <div>
    My <AwesomeButton>UI button</AwesomeButton>!
    <awesome-alert>Here's an alert!</awesome-alert>
  </div>
</template>

コンポーネントが使用されている場合にのみ自動的にインポートされ、node_modules/awesome-ui/components/ でコンポーネントを更新する際の HMR もサポートされます。

ドキュメント > 例 > 機能 > 自動インポート でライブ例を読んで編集してください。