nuxt logo

Traducción de Documentación (No Oficial)

components

El directorio components/ es donde colocas todos tus componentes de Vue.

Nuxt importa automáticamente cualquier componente en este directorio (junto con los componentes que son registrados por cualquier módulo que puedas estar usando).

Estructura del Directorio
-| components/
---| AppHeader.vue
---| AppFooter.vue
app.vue
<template>
  <div>
    <AppHeader />
    <NuxtPage />
    <AppFooter />
  </div>
</template>

Nombres de Componentes

Si tienes un componente en directorios anidados como:

Estructura del Directorio
-| components/
---| base/
-----| foo/
-------| Button.vue

... entonces el nombre del componente se basará en su propio directorio de ruta y nombre de archivo, eliminando los segmentos duplicados. Por lo tanto, el nombre del componente será:

<BaseFooButton />

Para mayor claridad, recomendamos que el nombre del archivo del componente coincida con su nombre. Así que, en el ejemplo anterior, podrías renombrar Button.vue a BaseFooButton.vue.

Si deseas importar automáticamente componentes basados solo en su nombre, no en la ruta, entonces necesitas establecer la opción pathPrefix a false usando la forma extendida del objeto de configuración:

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

Esto registra los componentes usando la misma estrategia que se usaba en Nuxt 2. Por ejemplo, ~/components/Some/MyComponent.vue será utilizable como <MyComponent> y no <SomeMyComponent>.

Componentes Dinámicos

Si deseas usar la sintaxis de Vue <component :is="someComputedComponent">, necesitas usar el helper resolveComponent proporcionado por Vue o importar el componente directamente desde #components y pasarlo a la prop is.

Por ejemplo:

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>

Si estás usando resolveComponent para manejar componentes dinámicos, asegúrate de no insertar nada más que el nombre del componente, el cual debe ser una cadena literal y no ser o contener una variable. La cadena se analiza estáticamente en el paso de compilación.

Alternativamente, aunque no se recomienda, puedes registrar todos tus componentes globalmente, lo que creará fragmentos asíncronos para todos tus componentes y los hará disponibles en toda tu aplicación.

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

También puedes registrar selectivamente algunos componentes globalmente colocándolos en un directorio ~/components/global, o usando un sufijo .global.vue en el nombre del archivo. Como se señaló anteriormente, cada componente global se renderiza en un fragmento separado, así que ten cuidado de no abusar de esta característica.

La opción global también se puede establecer por directorio de componentes.

Importaciones Dinámicas

Para importar dinámicamente un componente (también conocido como carga diferida de un componente) todo lo que necesitas hacer es agregar el prefijo Lazy al nombre del componente. Esto es particularmente útil si el componente no siempre es necesario.

Al usar el prefijo Lazy puedes retrasar la carga del código del componente hasta el momento adecuado, lo cual puede ser útil para optimizar el tamaño de tu paquete de JavaScript.

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

<template>
  <div>
    <h1>Montañas</h1>
    <LazyMountainsList v-if="show" />
    <button v-if="!show" @click="show = true">Mostrar Lista</button>
  </div>
</template>

Hidratación Diferida (o Lazy)

Los componentes Lazy son excelentes para controlar los tamaños de los fragmentos en tu aplicación, pero no siempre mejoran el rendimiento en tiempo de ejecución, ya que aún se cargan con avidez a menos que se rendericen condicionalmente. En aplicaciones del mundo real, algunas páginas pueden incluir mucho contenido y muchos componentes, y la mayoría de las veces no todos necesitan ser interactivos tan pronto como se carga la página. Tenerlos todos cargados con avidez puede afectar negativamente el rendimiento.

Para optimizar tu aplicación, es posible que desees retrasar la hidratación de algunos componentes hasta que sean visibles, o hasta que el navegador haya terminado con tareas más importantes.

Nuxt admite esto usando hidratación lazy (o diferida), permitiéndote controlar cuándo los componentes se vuelven interactivos.

Estrategias de Hidratación

Nuxt proporciona una gama de estrategias de hidratación integradas. Solo se puede usar una estrategia por componente lazy.

Actualmente, la hidratación lazy integrada de Nuxt solo funciona en componentes de un solo archivo (SFCs), y requiere que definas la prop en el template (en lugar de extender un objeto de props a través de v-bind). Tampoco funciona con importaciones directas desde #components.

hydrate-on-visible

Hidrata el componente cuando se vuelve visible en el viewport.

pages/index.vue
<template>
  <div>
    <LazyMyComponent hydrate-on-visible />
  </div>
</template>
Ver también Opciones de IntersectionObserver

Internamente, esto usa la estrategia integrada de Vue hydrateOnVisible.

hydrate-on-idle

Hidrata el componente cuando el navegador está inactivo. Esto es adecuado si necesitas que el componente se cargue lo antes posible, pero no bloquee la ruta de renderizado crítica.

También puedes pasar un número que sirva como tiempo máximo de espera.

pages/index.vue
<template>
  <div>
    <LazyMyComponent hydrate-on-idle />
  </div>
</template>

Internamente, esto usa la estrategia integrada de Vue hydrateOnIdle.

hydrate-on-interaction

Hidrata el componente después de una interacción especificada (por ejemplo, clic, mouseover).

pages/index.vue
<template>
  <div>
    <LazyMyComponent hydrate-on-interaction="mouseover" />
  </div>
</template>

Si no pasas un evento o lista de eventos, por defecto hidrata en pointerenter y focus.

Internamente, esto usa la estrategia integrada de Vue hydrateOnInteraction.

hydrate-on-media-query

Hidrata el componente cuando la ventana coincide con una consulta de medios.

pages/index.vue
<template>
  <div>
    <LazyMyComponent hydrate-on-media-query="(max-width: 768px)" />
  </div>
</template>

Internamente, esto usa la estrategia integrada de Vue hydrateOnMediaQuery.

hydrate-after

Hidrata el componente después de un retraso especificado (en milisegundos).

pages/index.vue
<template>
  <div>
    <LazyMyComponent :hydrate-after="2000" />
  </div>
</template>

hydrate-when

Hidrata el componente basado en una condición booleana.

pages/index.vue
<template>
  <div>
    <LazyMyComponent :hydrate-when="isReady" />
  </div>
</template>
<script setup lang="ts">
const isReady = ref(false)
function myFunction() {
  // activar estrategia de hidratación personalizada...
  isReady.value = true
}
</script>

hydrate-never

Nunca hidrata el componente.

pages/index.vue
<template>
  <div>
    <LazyMyComponent hydrate-never />
  </div>
</template>

Escuchar Eventos de Hidratación

Todos los componentes de hidratación diferida emiten un evento @hydrated cuando son hidratados.

pages/index.vue
<template>
  <div>
    <LazyMyComponent hydrate-on-visible @hydrated="onHydrate" />
  </div>
</template>

<script setup lang="ts">
function onHydrate() {
  console.log("¡El componente ha sido hidratado!")
}
</script>

Advertencias y Mejores Prácticas

La hidratación diferida puede ofrecer beneficios de rendimiento, pero es esencial usarla correctamente:

  1. Prioriza el Contenido en el Viewport: Evita la hidratación diferida para contenido crítico, por encima del pliegue. Es más adecuada para contenido que no se necesita inmediatamente.

  2. Renderizado Condicional: Al usar v-if="false" en un componente lazy, es posible que no necesites hidratación diferida. Puedes simplemente usar un componente lazy normal.

  3. Estado Compartido: Ten en cuenta el estado compartido (v-model) entre múltiples componentes. Actualizar el modelo en un componente puede activar la hidratación en todos los componentes vinculados a ese modelo.

  4. Usa Cada Estrategia para su Caso de Uso Previsto: Cada estrategia está optimizada para un propósito específico.

    • hydrate-when es mejor para componentes que podrían no necesitar ser hidratados siempre.
    • hydrate-after es para componentes que pueden esperar un tiempo específico.
    • hydrate-on-idle es para componentes que pueden ser hidratados cuando el navegador está inactivo.
  5. Evita hydrate-never en componentes interactivos: Si un componente requiere interacción del usuario, no debe configurarse para nunca hidratarse.

Importaciones Directas

También puedes importar explícitamente componentes desde #components si deseas o necesitas omitir la funcionalidad de auto-importación de Nuxt.

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

const show = ref(false)
</script>

<template>
  <div>
    <h1>Montañas</h1>
    <LazyMountainsList v-if="show" />
    <button v-if="!show" @click="show = true">Mostrar Lista</button>
    <NuxtLink to="/">Inicio</NuxtLink>
  </div>
</template>

Directorios Personalizados

Por defecto, solo se escanea el directorio ~/components. Si deseas agregar otros directorios, o cambiar cómo se escanean los componentes dentro de una subcarpeta de este directorio, puedes agregar directorios adicionales a la configuración:

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' },

    // Es importante que esto venga al final si tienes sobrescrituras que deseas aplicar
    // a subdirectorios de `~/components`.
    //
    // ~/components/Btn.vue => <Btn />
    // ~/components/base/Btn.vue => <BaseBtn />
    '~/components'
  ]
})

Cualquier directorio anidado necesita ser agregado primero ya que se escanean en orden.

Paquetes npm

Si deseas auto-importar componentes desde un paquete npm, puedes usar addComponent en un módulo local para registrarlos.

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',
    })
  },
})

Extensiones de Componentes

Por defecto, cualquier archivo con una extensión especificada en la clave extensions de nuxt.config.ts se trata como un componente. Si necesitas restringir las extensiones de archivo que deben registrarse como componentes, puedes usar la forma extendida de la declaración del directorio de componentes y su clave extensions:

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

Componentes del Cliente

Si un componente está destinado a ser renderizado solo del lado del cliente, puedes agregar el sufijo .client a tu componente.

Estructura del Directorio
| components/
--| Comments.client.vue
pages/example.vue
<template>
  <div>
    <!-- este componente solo se renderizará del lado del cliente -->
    <Comments />
  </div>
</template>

Esta característica solo funciona con auto-importaciones de Nuxt e importaciones de #components. Importar explícitamente estos componentes desde sus rutas reales no los convierte en componentes solo del cliente.

Los componentes .client se renderizan solo después de ser montados. Para acceder al template renderizado usando onMounted(), agrega await nextTick() en el callback del hook onMounted().

Ver también api > components > client-only

Componentes del Servidor

Los componentes del servidor permiten renderizar en el servidor componentes individuales dentro de tus aplicaciones del lado del cliente. Es posible usar componentes del servidor dentro de Nuxt, incluso si estás generando un sitio estático. Eso hace posible construir sitios complejos que mezclan componentes dinámicos, HTML renderizado en el servidor e incluso fragmentos estáticos de marcado.

Los componentes del servidor pueden usarse por sí solos o emparejados con un componente del cliente.

Lee la guía de Daniel Roe sobre Componentes del Servidor de Nuxt.

Componentes del servidor independientes

Los componentes del servidor independientes siempre se renderizarán en el servidor, también conocidos como componentes de Islas.

Cuando sus props se actualizan, esto resultará en una solicitud de red que actualizará el HTML renderizado en su lugar.

Los componentes del servidor son actualmente experimentales y para usarlos, necesitas habilitar la característica 'component islands' en tu nuxt.config:

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

Ahora puedes registrar componentes solo del servidor con el sufijo .server y usarlos en cualquier lugar de tu aplicación automáticamente.

Estructura del Directorio
-| components/
---| HighlightedMarkdown.server.vue
pages/example.vue
<template>
  <div>
    <!--
      esto se renderizará automáticamente en el servidor, lo que significa que tus bibliotecas de análisis y resaltado de markdown
      no se incluyen en tu paquete del cliente.
     -->
    <HighlightedMarkdown markdown="# Headline" />
  </div>
</template>

Los componentes solo del servidor usan <NuxtIsland> internamente, lo que significa que la prop lazy y el slot #fallback se pasan a él.

Los componentes del servidor (e islas) deben tener un solo elemento raíz. (Los comentarios HTML se consideran elementos también.)

Las props se pasan a los componentes del servidor a través de parámetros de consulta de URL, y por lo tanto están limitadas por la posible longitud de una URL, así que ten cuidado de no pasar enormes cantidades de datos a los componentes del servidor a través de props.

Ten cuidado al anidar islas dentro de otras islas ya que cada isla agrega un poco de sobrecarga adicional.

La mayoría de las características para componentes solo del servidor y componentes de islas, como slots y componentes del cliente, solo están disponibles para componentes de un solo archivo.

Componentes del cliente dentro de componentes del servidor

Esta característica necesita que experimental.componentIslands.selectiveClient dentro de tu configuración sea verdadero.

Puedes hidratar parcialmente un componente estableciendo un atributo nuxt-client en el componente que deseas que se cargue del lado del cliente.

components/ServerWithClient.vue
<template>
  <div>
    <HighlightedMarkdown markdown="# Headline" />
    <!-- Counter se cargará e hidratará del lado del cliente -->
    <Counter nuxt-client :count="5" />
  </div>
</template>

Esto solo funciona dentro de un componente del servidor. Los slots para componentes del cliente solo funcionan con experimental.componentIsland.selectiveClient configurado como 'deep' y dado que se renderizan del lado del servidor, no son interactivos una vez del lado del cliente.

Contexto del Componente del Servidor

Al renderizar un componente solo del servidor o de isla, <NuxtIsland> realiza una solicitud de fetch que regresa con un NuxtIslandResponse. (Esta es una solicitud interna si se renderiza en el servidor, o una solicitud que puedes ver en la pestaña de red si se está renderizando en la navegación del lado del cliente.)

Esto significa:

  • Se creará una nueva aplicación Vue del lado del servidor para crear el NuxtIslandResponse.
  • Se creará un nuevo 'contexto de isla' mientras se renderiza el componente.
  • No puedes acceder al 'contexto de isla' desde el resto de tu aplicación y no puedes acceder al contexto del resto de tu aplicación desde el componente de isla. En otras palabras, el componente del servidor o isla está aislado del resto de tu aplicación.
  • Tus plugins se ejecutarán nuevamente al renderizar la isla, a menos que tengan env: { islands: false } establecido (lo cual puedes hacer en un plugin de sintaxis de objeto).

Dentro de un componente de isla, puedes acceder a su contexto de isla a través de nuxtApp.ssrContext.islandContext. Ten en cuenta que mientras los componentes de isla aún están marcados como experimentales, el formato de este contexto puede cambiar.

Los slots pueden ser interactivos y están envueltos dentro de un <div> con display: contents;

Emparejado con un Componente del Cliente

En este caso, los componentes .server + .client son dos 'mitades' de un componente y pueden usarse en casos de uso avanzados para implementaciones separadas de un componente en el lado del servidor y del cliente.

Estructura del Directorio
-| components/
---| Comments.client.vue
---| Comments.server.vue
pages/example.vue
<template>
  <div>
    <!-- este componente renderizará Comments.server en el servidor y luego Comments.client una vez montado en el navegador -->
    <Comments />
  </div>
</template>

Componentes Integrados de Nuxt

Hay una serie de componentes que Nuxt proporciona, incluyendo <ClientOnly> y <DevOnly>. Puedes leer más sobre ellos en la documentación de la API.

Ver también api

Autores de Librerías

Hacer bibliotecas de componentes de Vue con tree-shaking automático y registro de componentes es muy fácil. ✨

Puedes usar el método addComponentsDir proporcionado por @nuxt/kit para registrar tu directorio de componentes en tu módulo de Nuxt.

Imagina una estructura de directorio como esta:

Estructura del Directorio
-| node_modules/
---| awesome-ui/
-----| components/
-------| Alert.vue
-------| Button.vue
-----| nuxt.ts
-| pages/
---| index.vue
-| nuxt.config.ts

Luego en awesome-ui/nuxt.ts puedes usar el hook addComponentsDir:

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

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

    // Agregar el directorio ./components a la lista
    addComponentsDir({
      path: resolver.resolve('./components'),
      prefix: 'awesome',
    })
  },
})

¡Eso es todo! Ahora en tu proyecto, puedes importar tu librería de UI como un módulo de Nuxt en tu archivo nuxt.config:

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

... y usar directamente los componentes del módulo (prefijados con awesome-) en nuestro pages/index.vue:

<template>
  <div>
    ¡Mi <AwesomeButton>botón de UI</AwesomeButton>!
    <awesome-alert>¡Aquí hay una alerta!</awesome-alert>
  </div>
</template>

Importará automáticamente los componentes solo si se usan y también soportará HMR al actualizar tus componentes en node_modules/awesome-ui/components/.

Editar y previsualizar el código de ejemploexamples > features > auto-imports