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.vue в BaseFooButton.vue.

Если вы хотите автоматически импортировать компоненты только на основе их имени, а не пути, вам необходимо установить для параметра pathPrefix значение false, используя расширенную форму объекта конфигурации:

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

При этом компоненты будут регистрироваться с использованием той же стратегии, что и в Nuxt 2. Например, ~/components/Some/MyComponent.vue будет использоваться как <MyComponent> но не <SomeMyComponent>.

Динамические компоненты

Если вы хотите использовать синтаксис Vue <component :is="someComputedComponent">, вам необходимо использовать помощник resolveComponent, предоставляемый Vue, или импортировать компонент напрямую из #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 для обработки динамических компонентов, убедитесь, что вы не передаете ничего, кроме имени компонента, которое должно быть строкой, а не переменной.
Watch Daniel Roe's short video about resolveComponent.

В качестве альтернативы, хотя это и не рекомендуется, вы можете зарегистрировать все компоненты глобально, что создаст асинхронные чанки для всех ваших компонентов и сделает их доступными во всем приложении.

  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>Горы</h1>
    <LazyMountainsList v-if="show" />
    <button v-if="!show" @click="show = true">Показать список</button>
  </div>
</template>

Прямые импорты

Вы также можете явно импортировать компоненты из #components, если хотите, или если вам необходимо обойти функцию автоматического импорта Nuxt.

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

const show = ref(false)
</script>

<template>
  <div>
    <h1>Горы</h1>
    <LazyMountainsList v-if="show" />
    <button v-if="!show" @click="show = true">Показать список</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' },
// Важно: если у вас есть переопределения, которые вы хотите применить // к поддиректориям `~/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',
}) }, })

Расширения компонентов

По умолчанию, любой файл с расширением, указанным в ключе extensions nuxt.config.ts, рассматривается как компонент. Если вам нужно ограничить расширения файлов, которые должны быть зарегистрированы как компоненты, вы можете использовать расширенную форму объявления директории компонентов и его ключ extensions:

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

Клиентские компоненты

Если компонент предназначен для рендера только на стороне клиента, вы можете добавить суффикс .client к своему компоненту.

Структура директорий
| components/
--| Comments.client.vue
pages/example.vue
<template>
  <div>
    <!-- этот компонент будет отображаться только на стороне клиента -->
    <Comments />
  </div>
</template>
Эта функция работает только с автоимпортами Nuxt и импортами #components. Явный импорт таких компонентов по их реальному пути не преобразует их в клиентские компоненты.
Компоненты .client рендерятся только после монтирования. Чтобы получить доступ к отрисованному шаблону с помощью onMounted(), добавьте await nextTick() в коллбэк хука onMounted().
Аналогичного результата можно добиться и с помощью компонента <ClientOnly>.

Серверные компоненты

Серверные компоненты позволяют серверный рендеринг отдельных компонентов в клиентских приложениях. Серверные компоненты можно использовать в Nuxt, даже если вы создаете статический сайт. Это позволяет создавать сложные сайты, которые смешивают динамические компоненты, HTML, рендеринг которого осуществляется сервером, и даже статические фрагменты разметки.

Серверные компоненты могут использоваться как по отдельности, так и в паре с клиентским компонентом.

Посмотрите видеоролик Learn Vue о серверных компонентах Nuxt.
Прочитайте руководство Дэниела Ро по серверным компонентам Nuxt.

Автономные серверные компоненты

Отдельные серверные компоненты, которые всегда будут отображаться на сервере, также известны как island-компоненты.

Когда их свойства обновляются, это приводит к сетевому запросу, который обновляет отображаемый HTML.

Серверные компоненты в настоящее время являются экспериментальными, и для их использования вам необходимо включить функцию 'component islands' в вашем nuxt.config:

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

Теперь вы можете регистрировать серверные компоненты с суффиксом .server и автоматически использовать их в любом месте вашего приложения.

Структура директорий
-| components/
---| HighlightedMarkdown.server.vue
pages/example.vue
<template>
  <div>
    <!--
      это будет автоматически отрендерено на сервере, то есть ваши библиотеки парсинга и подсветки markdown не будут включены в ваш клиентский бандл.
     -->
    <HighlightedMarkdown markdown="# Headline" />
  </div>
</template>

Компоненты, предназначенные только для сервера, используют <NuxtIsland> под капотом, что означает, что свойство lazy и слот #fallback передаются им.

Серверные компоненты (и islands) должны иметь один корневой элемент. (Комментарии HTML также считаются элементами.)
Be careful when nesting islands within other islands as each island adds some extra overhead.
Будьте осторожны при вложении островов в другие острова, поскольку каждый остров добавляет дополнительные затраты.
Большинство функций для серверных компонентов и island-компонентов, таких как слоты и клиентские компоненты, доступны только для однофайловых компонентов.

Клиентские компоненты внутри серверных компонентов

Для работы этой функции в вашей конфигурации должен быть указан experimental.componentIslands.selectiveClient.

Вы можете частично гидратировать компонент, установив атрибут nuxt-client для компонента, который вы хотите загрузить на стороне клиента.

components/ServerWithClient.vue
<template>
  <div>
    <HighlightedMarkdown markdown="# Headline" />
    <!-- Счетчик будет загружен и гидратирован на стороне клиента -->
    <Counter nuxt-client :count="5" />
  </div>
</template>
Это работает только в серверном компоненте. Слоты для клиентских компонентов работают только с experimental.componentIsland.selectiveClient, установленным на 'deep', и поскольку они рендерятся на стороне сервера, они не являются интерактивными на стороне клиента.

Контекст серверного компонента

При рендеринге серверного или island-компонента, <NuxtIsland> делает запрос, который возвращается с NuxtIslandResponse. (Это внутренний запрос, если он рендерится на сервере, или запрос, который вы можете увидеть на вкладке сети, если он рендерится на стороне клиента.)

Это означает, что:

  • Новое приложение Vue будет создано на стороне сервера для создания NuxtIslandResponse.
  • Новый 'island context' будет создан во время рендеринга компонента.
  • Вы не можете получить доступ к 'island context' из остальной части приложения, и не можете получить доступ к контексту остальной части вашего приложения из island-компонента. Другими словами, серверный компонент или island-компонент изолированы от остальной части вашего приложения.
  • Ваши плагины будут запущены снова при рендеринге island-компонента, если только для них не установлен env: { islands: false } (что вы можете сделать в плагине объектного синтаксиса).

Внутри island-компонента вы можете получить доступ к его контексту через nuxtApp.ssrContext.islandContext. Обратите внимание, что пока island-компоненты все еще отмечены как экспериментальные, формат этого контекста может измениться.

Слоты могут быть интерактивными и заключаются в <div> с display: contents;.

В паре с клиентским компонентом

В этом случае компоненты .server + .client представляют собой две «половинки» компонента и могут использоваться в расширенных вариантах использования для отдельных реализаций компонента на стороне сервера и клиента.

Структура директорий
-| components/
---| Comments.client.vue
---| Comments.server.vue
pages/example.vue
<template>
  <div>
    <!-- этот компонент отрендерит Comments.server на сервере, а затем Comments.client после монтирования в браузере -->
    <Comments />
  </div>
</template>

Встроенные компоненты Nuxt

Nuxt предоставляет ряд компонентов, включая <ClientOnly> и <DevOnly>. Подробнее о них можно прочитать в документации API.

Узнать больше Docs > API.

Авторам библиотек

Создание библиотек компонентов Vue с автоматическим treeshaking и регистрацией компонентов — это очень просто. ✨

Вы можете использовать хук 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
)
// Добавьте директорию ./components в список
dirs
.
push
({
path
:
resolve
('./components'),
prefix
: 'awesome'
}) } } })

Вот и все! Теперь в проекте вы можете импортировать библиотеку UI как модуль Nuxt в файл nuxt.config:

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

... и напрямую использовать компоненты модуля (с префиксом awesome-) в нашем pages/index.vue:

<template>
  <div>
    Моя <AwesomeButton>UI кнопка</AwesomeButton>!
    <awesome-alert>Это алерт!</awesome-alert>
  </div>
</template>

Это автоматически импортирует компоненты только в том случае, если они используются, а также поддерживает HMR при обновлении компонентов в node_modules/awesome-ui/components/.

Прочитайте и отредактируйте живой пример в Docs > Examples > Features > Auto Imports.