components
Nuxt は、このディレクトリにあるすべてのコンポーネント(および、使用しているモジュールによって登録されたコンポーネント)を自動的にインポートします。
-| components/
---| AppHeader.vue
---| AppFooter.vue
<template>
<div>
<AppHeader />
<NuxtPage />
<AppFooter />
</div>
</template>
コンポーネント名
次のようなネストされたディレクトリにコンポーネントがある場合
-| components/
---| base/
-----| foo/
-------| Button.vue
... コンポーネントの名前は、重複するセグメントが削除された、自身のパスディレクトリとファイル名に基づいて決定されます。したがって、コンポーネントの名前は次のようになります
<BaseFooButton />
Button.vue
を BaseFooButton.vue
に名前を変更できます。パスではなく名前のみに基づいてコンポーネントを自動インポートする場合は、構成オブジェクトの拡張フォームを使用して pathPrefix
オプションを false
に設定する必要があります
export default defineNuxtConfig({
components: [
{
path: '~/components',
pathPrefix: false, },
],
});
これにより、Nuxt 2 で使用されていたのと同じ戦略を使用してコンポーネントが登録されます。たとえば、~/components/Some/MyComponent.vue
は <SomeMyComponent>
ではなく <MyComponent>
として使用できます。
動的コンポーネント
Vue の <component :is="someComputedComponent">
構文を使用する場合は、Vue が提供する resolveComponent
ヘルパーを使用するか、#components
からコンポーネントを直接インポートし、それを is
プロパティに渡す必要があります。
たとえば
<script setup lang="ts">
import { SomeComponent } from '#components'
const MyButton = resolveComponent('MyButton')
</script>
<template>
<component :is="clickable ? MyButton : 'div'" />
<component :is="SomeComponent" />
</template>
resolveComponent
を使用して動的コンポーネントを処理する場合は、コンポーネントの名前以外のものを挿入しないでください。これは文字列であり、変数であってはなりません。または、推奨されませんが、すべてのコンポーネントをグローバルに登録することもできます。これにより、すべてのコンポーネントに対して非同期チャンクが作成され、アプリケーション全体で使用できるようになります。
export default defineNuxtConfig({
components: {
+ global: true,
+ dirs: ['~/components']
},
})
~/components/global
ディレクトリに配置するか、ファイル名に .global.vue
サフィックスを使用することで、一部のコンポーネントを選択的にグローバルに登録することもできます。上記のように、各グローバルコンポーネントは個別のチャンクでレンダリングされるため、この機能を過度に使用しないように注意してください。
global
オプションは、コンポーネントディレクトリごとに設定することもできます。動的インポート
コンポーネントを動的にインポートする(コンポーネントの遅延読み込みとも呼ばれます)には、コンポーネントの名前に Lazy
プレフィックスを追加するだけで済みます。これは、コンポーネントが常に必要ではない場合に特に役立ちます。
Lazy
プレフィックスを使用すると、適切なタイミングまでコンポーネントコードの読み込みを遅らせることができ、JavaScriptバンドルサイズの最適化に役立ちます。
<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
からコンポーネントを明示的にインポートすることもできます。
<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
ディレクトリのみがスキャンされます。他のディレクトリを追加したり、このディレクトリのサブフォルダー内でコンポーネントをスキャンする方法を変更したりする場合は、追加のディレクトリを構成に追加できます
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
キーの拡張形式を使用できます
export default defineNuxtConfig({
components: [
{
path: '~/components',
extensions: ['.vue'], }
]
})
クライアントコンポーネント
コンポーネントがクライアント側でのみレンダリングされることを意図している場合は、コンポーネントに .client
サフィックスを追加できます。
| components/
--| Comments.client.vue
<template>
<div>
<!-- this component will only be rendered on client side -->
<Comments />
</div>
</template>
#components
インポートでのみ機能します。これらのコンポーネントを実際のパスから明示的にインポートしても、クライアントのみのコンポーネントには変換されません。.client
コンポーネントは、マウントされた後にのみレンダリングされます。onMounted()
を使用してレンダリングされたテンプレートにアクセスするには、onMounted()
フックのコールバックに await nextTick()
を追加します。サーバーコンポーネント
サーバーコンポーネントを使用すると、クライアント側アプリ内で個々のコンポーネントをサーバーレンダリングできます。静的サイトを生成している場合でも、Nuxt 内でサーバーコンポーネントを使用できます。これにより、動的コンポーネント、サーバーレンダリングされたHTML、さらには静的なマークアップのチャンクを組み合わせた複雑なサイトを構築できます。
サーバーコンポーネントは、単独で使用することも、クライアントコンポーネントと組み合わせて使用することもできます。
スタンドアロンサーバーコンポーネント
スタンドアロンサーバーコンポーネントは、常にサーバー上でレンダリングされます。これはアイランドコンポーネントとも呼ばれます。
プロパティが更新されると、これによりネットワークリクエストが発生し、レンダリングされたHTMLがインプレースで更新されます。
サーバーコンポーネントは現在実験段階であり、使用するには、nuxt.config で「コンポーネントアイランド」機能を有効にする必要があります
export default defineNuxtConfig({
experimental: {
componentIslands: true
}
})
これで、.server
サフィックスを使用してサーバー専用コンポーネントを登録し、アプリケーション内の任意の場所で自動的に使用できるようになります。
-| components/
---| HighlightedMarkdown.server.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
スロットの両方が渡されます。
サーバーコンポーネント内のクライアントコンポーネント
experimental.componentIslands.selectiveClient
を true にする必要があります。nuxt-client
属性をクライアントサイドでロードしたいコンポーネントに設定することで、コンポーネントを部分的にハイドレーションできます。
<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
<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ドキュメントを参照してください。
ライブラリ作成者向け
自動ツリーシェイキングとコンポーネント登録を備えた 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 ライブラリをインポートできます。
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 もサポートされます。