components
O diretório components/ é onde você coloca todos os seus componentes Vue.
O Nuxt importa automaticamente quaisquer componentes neste diretório (junto com componentes que são registrados por quaisquer módulos que você possa estar usando).
-| components/
---| AppHeader.vue
---| AppFooter.vue
<template>
<div>
<AppHeader />
<NuxtPage />
<AppFooter />
</div>
</template>
Nomes de Componentes
Se você tiver um componente em diretórios aninhados como:
-| components/
---| base/
-----| foo/
-------| Button.vue
... então o nome do componente será baseado no caminho do diretório e no nome do arquivo, com segmentos duplicados sendo removidos. Portanto, o nome do componente será:
<BaseFooButton />
Para clareza, recomendamos que o nome do arquivo do componente corresponda ao seu nome. Então, no exemplo acima, você poderia renomear Button.vue
para BaseFooButton.vue
.
Se você quiser importar automaticamente componentes com base apenas no nome, não no caminho, então você precisa definir a opção pathPrefix
como false
usando a forma estendida do objeto de configuração:
export default defineNuxtConfig({
components: [
{
path: '~/components',
pathPrefix: false, // [!code ++]
},
],
});
Isso registra os componentes usando a mesma estratégia usada no Nuxt 2. Por exemplo, ~/components/Some/MyComponent.vue
será utilizável como <MyComponent>
e não <SomeMyComponent>
.
Componentes Dinâmicos
Se você quiser usar a sintaxe Vue <component :is="someComputedComponent">
, você precisa usar o helper resolveComponent
fornecido pelo Vue ou importar o componente diretamente de #components
e passá-lo para a prop is
.
Por exemplo:
<script setup lang="ts">
import { SomeComponent } from '#components'
const MyButton = resolveComponent('MyButton')
</script>
<template>
<component :is="clickable ? MyButton : 'div'" />
<component :is="SomeComponent" />
</template>
Se você estiver usando resolveComponent
para lidar com componentes dinâmicos, certifique-se de não inserir nada além do nome do componente, que deve ser uma string literal e não ser ou conter uma variável. A string é analisada estaticamente na etapa de compilação.
Alternativamente, embora não recomendado, você pode registrar todos os seus componentes globalmente, o que criará chunks assíncronos para todos os seus componentes e os tornará disponíveis em toda a sua aplicação.
export default defineNuxtConfig({
components: {
+ global: true,
+ dirs: ['~/components']
},
})
Você também pode registrar seletivamente alguns componentes globalmente colocando-os em um diretório ~/components/global
, ou usando um sufixo .global.vue
no nome do arquivo. Como mencionado acima, cada componente global é renderizado em um chunk separado, então tenha cuidado para não abusar desse recurso.
A opção global
também pode ser definida por diretório de componentes.
Importações Dinâmicas
Para importar dinamicamente um componente (também conhecido como carregamento preguiçoso de um componente), tudo o que você precisa fazer é adicionar o prefixo Lazy
ao nome do componente. Isso é particularmente útil se o componente nem sempre for necessário.
Ao usar o prefixo Lazy
, você pode atrasar o carregamento do código do componente até o momento certo, o que pode ser útil para otimizar o tamanho do seu bundle JavaScript.
<script setup lang="ts">
const show = ref(false)
</script>
<template>
<div>
<h1>Montanhas</h1>
<LazyMountainsList v-if="show" />
<button v-if="!show" @click="show = true">Mostrar Lista</button>
</div>
</template>
Hidratação Atrasada (ou Preguiçosa)
Componentes preguiçosos são ótimos para controlar os tamanhos dos chunks em seu aplicativo, mas nem sempre melhoram o desempenho em tempo de execução, pois ainda são carregados ansiosamente, a menos que sejam renderizados condicionalmente. Em aplicações do mundo real, algumas páginas podem incluir muito conteúdo e muitos componentes, e na maioria das vezes nem todos precisam ser interativos assim que a página é carregada. Tê-los todos carregados ansiosamente pode impactar negativamente o desempenho.
Para otimizar seu aplicativo, você pode querer atrasar a hidratação de alguns componentes até que eles estejam visíveis, ou até que o navegador tenha concluído tarefas mais importantes.
O Nuxt suporta isso usando hidratação preguiçosa (ou atrasada), permitindo que você controle quando os componentes se tornam interativos.
Estratégias de Hidratação
O Nuxt fornece uma gama de estratégias de hidratação embutidas. Apenas uma estratégia pode ser usada por componente preguiçoso.
Atualmente, a hidratação preguiçosa embutida do Nuxt só funciona em componentes de arquivo único (SFCs) e requer que você defina a prop no template (em vez de espalhar um objeto de props via v-bind
). Também não funciona com importações diretas de #components
.
hydrate-on-visible
Hidrata o componente quando ele se torna visível na viewport.
<template>
<div>
<LazyMyComponent hydrate-on-visible />
</div>
</template>
Por baixo dos panos, isso usa a estratégia embutida hydrateOnVisible
do Vue.
hydrate-on-idle
Hidrata o componente quando o navegador está ocioso. Isso é adequado se você precisar que o componente carregue o mais rápido possível, mas não bloqueie o caminho de renderização crítico.
Você também pode passar um número que serve como um tempo limite máximo.
<template>
<div>
<LazyMyComponent hydrate-on-idle />
</div>
</template>
Por baixo dos panos, isso usa a estratégia embutida hydrateOnIdle
do Vue.
hydrate-on-interaction
Hidrata o componente após uma interação especificada (por exemplo, clique, mouseover).
<template>
<div>
<LazyMyComponent hydrate-on-interaction="mouseover" />
</div>
</template>
Se você não passar um evento ou lista de eventos, ele padrão para hidratar em pointerenter
e focus
.
Por baixo dos panos, isso usa a estratégia embutida hydrateOnInteraction
do Vue.
hydrate-on-media-query
Hidrata o componente quando a janela corresponde a uma consulta de mídia.
<template>
<div>
<LazyMyComponent hydrate-on-media-query="(max-width: 768px)" />
</div>
</template>
Por baixo dos panos, isso usa a estratégia embutida hydrateOnMediaQuery
do Vue.
hydrate-after
Hidrata o componente após um atraso especificado (em milissegundos).
<template>
<div>
<LazyMyComponent :hydrate-after="2000" />
</div>
</template>
hydrate-when
Hidrata o componente com base em uma condição booleana.
<template>
<div>
<LazyMyComponent :hydrate-when="isReady" />
</div>
</template>
<script setup lang="ts">
const isReady = ref(false)
function myFunction() {
// aciona estratégia de hidratação personalizada...
isReady.value = true
}
</script>
hydrate-never
Nunca hidrata o componente.
<template>
<div>
<LazyMyComponent hydrate-never />
</div>
</template>
Ouvindo Eventos de Hidratação
Todos os componentes de hidratação atrasada emitem um evento @hydrated
quando são hidratados.
<template>
<div>
<LazyMyComponent hydrate-on-visible @hydrated="onHydrate" />
</div>
</template>
<script setup lang="ts">
function onHydrate() {
console.log("Componente foi hidratado!")
}
</script>
Advertências e Melhores Práticas
A hidratação atrasada pode oferecer benefícios de desempenho, mas é essencial usá-la corretamente:
-
Priorize Conteúdo no Viewport: Evite a hidratação atrasada para conteúdo crítico, acima da dobra. É mais adequado para conteúdo que não é imediatamente necessário.
-
Renderização Condicional: Ao usar
v-if="false"
em um componente preguiçoso, você pode não precisar de hidratação atrasada. Você pode simplesmente usar um componente preguiçoso normal. -
Estado Compartilhado: Esteja atento ao estado compartilhado (
v-model
) entre vários componentes. Atualizar o modelo em um componente pode acionar a hidratação em todos os componentes vinculados a esse modelo. -
Use Cada Estratégia para o Caso de Uso Pretendido: Cada estratégia é otimizada para um propósito específico.
hydrate-when
é melhor para componentes que podem não precisar ser hidratados sempre.hydrate-after
é para componentes que podem esperar um tempo específico.hydrate-on-idle
é para componentes que podem ser hidratados quando o navegador está ocioso.
-
Evite
hydrate-never
em componentes interativos: Se um componente requer interação do usuário, ele não deve ser configurado para nunca hidratar.
Importações Diretas
Você também pode importar explicitamente componentes de #components
se quiser ou precisar contornar a funcionalidade de importação automática do Nuxt.
<script setup lang="ts">
import { NuxtLink, LazyMountainsList } from '#components'
const show = ref(false)
</script>
<template>
<div>
<h1>Montanhas</h1>
<LazyMountainsList v-if="show" />
<button v-if="!show" @click="show = true">Mostrar Lista</button>
<NuxtLink to="/">Início</NuxtLink>
</div>
</template>
Diretórios Personalizados
Por padrão, apenas o diretório ~/components
é escaneado. Se você quiser adicionar outros diretórios, ou mudar como os componentes são escaneados dentro de uma subpasta deste diretório, você pode adicionar diretórios adicionais à configuração:
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' },
// É importante que isso venha por último se você tiver substituições que deseja aplicar
// a subdiretórios de `~/components`.
//
// ~/components/Btn.vue => <Btn />
// ~/components/base/Btn.vue => <BaseBtn />
'~/components'
]
})
Quaisquer diretórios aninhados precisam ser adicionados primeiro, pois são escaneados em ordem.
Pacotes npm
Se você quiser importar automaticamente componentes de um pacote npm, você pode usar addComponent
em um módulo local para registrá-los.
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',
})
},
})
Extensões de Componentes
Por padrão, qualquer arquivo com uma extensão especificada na chave extensions de nuxt.config.ts
é tratado como um componente.
Se você precisar restringir as extensões de arquivo que devem ser registradas como componentes, você pode usar a forma estendida da declaração do diretório de componentes e sua chave extensions
:
export default defineNuxtConfig({
components: [
{
path: '~/components',
extensions: ['.vue'], // [!code ++]
}
]
})
Componentes do Cliente
Se um componente deve ser renderizado apenas no lado do cliente, você pode adicionar o sufixo .client
ao seu componente.
| components/
--| Comments.client.vue
<template>
<div>
<!-- este componente será renderizado apenas no lado do cliente -->
<Comments />
</div>
</template>
Este recurso só funciona com importações automáticas do Nuxt e importações de #components
. Importar explicitamente esses componentes de seus caminhos reais não os converte em componentes apenas do cliente.
Componentes .client
são renderizados apenas após serem montados. Para acessar o template renderizado usando onMounted()
, adicione await nextTick()
no callback do hook onMounted()
.
Componentes do Servidor
Componentes do servidor permitem a renderização no servidor de componentes individuais dentro de seus aplicativos do lado do cliente. É possível usar componentes do servidor dentro do Nuxt, mesmo se você estiver gerando um site estático. Isso torna possível construir sites complexos que misturam componentes dinâmicos, HTML renderizado no servidor e até mesmo fragmentos estáticos de marcação.
Componentes do servidor podem ser usados sozinhos ou emparelhados com um componente do cliente.
Leia o guia de Daniel Roe sobre Componentes do Servidor Nuxt.
Componentes do servidor autônomos
Componentes do servidor autônomos sempre serão renderizados no servidor, também conhecidos como componentes Islands.
Quando suas props são atualizadas, isso resultará em uma solicitação de rede que atualizará o HTML renderizado no local.
Componentes do servidor são atualmente experimentais e, para usá-los, você precisa habilitar o recurso 'component islands' em seu nuxt.config:
export default defineNuxtConfig({
experimental: {
componentIslands: true
}
})
Agora você pode registrar componentes apenas do servidor com o sufixo .server
e usá-los em qualquer lugar da sua aplicação automaticamente.
-| components/
---| HighlightedMarkdown.server.vue
<template>
<div>
<!--
isso será automaticamente renderizado no servidor, o que significa que suas bibliotecas de análise + destaque de markdown
não estão incluídas no seu bundle do cliente.
-->
<HighlightedMarkdown markdown="# Headline" />
</div>
</template>
Componentes apenas do servidor usam <NuxtIsland>
por baixo dos panos, o que significa que a prop lazy
e o slot #fallback
são ambos passados para ele.
Componentes do servidor (e islands) devem ter um único elemento raiz. (Comentários HTML são considerados elementos também.)
Props são passadas para componentes do servidor via parâmetros de consulta de URL, e são, portanto, limitadas pelo comprimento possível de um URL, então tenha cuidado para não passar quantidades enormes de dados para componentes do servidor via props.
Tenha cuidado ao aninhar islands dentro de outras islands, pois cada island adiciona algum overhead extra.
A maioria dos recursos para componentes apenas do servidor e componentes island, como slots e componentes do cliente, estão disponíveis apenas para componentes de arquivo único.
Componentes do cliente dentro de componentes do servidor
Este recurso precisa de experimental.componentIslands.selectiveClient
dentro da sua configuração para ser verdadeiro.
Você pode hidratar parcialmente um componente definindo um atributo nuxt-client
no componente que deseja carregar no lado do cliente.
<template>
<div>
<HighlightedMarkdown markdown="# Headline" />
<!-- Counter será carregado e hidratado no lado do cliente -->
<Counter nuxt-client :count="5" />
</div>
</template>
Isso só funciona dentro de um componente do servidor. Slots para componentes do cliente funcionam apenas com experimental.componentIsland.selectiveClient
definido como 'deep'
e, como são renderizados no lado do servidor, não são interativos uma vez no lado do cliente.
Contexto do Componente do Servidor
Ao renderizar um componente apenas do servidor ou island, <NuxtIsland>
faz uma solicitação fetch que retorna com um NuxtIslandResponse
. (Esta é uma solicitação interna se renderizada no servidor, ou uma solicitação que você pode ver na aba de rede se estiver renderizando na navegação do lado do cliente.)
Isso significa:
- Um novo aplicativo Vue será criado no lado do servidor para criar o
NuxtIslandResponse
. - Um novo 'contexto de island' será criado enquanto o componente é renderizado.
- Você não pode acessar o 'contexto de island' do resto do seu aplicativo e não pode acessar o contexto do resto do seu aplicativo do componente island. Em outras palavras, o componente do servidor ou island é isolado do resto do seu aplicativo.
- Seus plugins serão executados novamente ao renderizar o island, a menos que tenham
env: { islands: false }
definido (o que você pode fazer em um plugin de sintaxe de objeto).
Dentro de um componente island, você pode acessar seu contexto de island através de nuxtApp.ssrContext.islandContext
. Note que enquanto os componentes island ainda são marcados como experimentais, o formato deste contexto pode mudar.
Slots podem ser interativos e são envoltos dentro de um <div>
com display: contents;
Emparelhado com um Componente do Cliente
Neste caso, os componentes .server
+ .client
são duas 'metades' de um componente e podem ser usados em casos de uso avançados para implementações separadas de um componente no lado do servidor e do cliente.
-| components/
---| Comments.client.vue
---| Comments.server.vue
<template>
<div>
<!-- este componente renderizará Comments.server no servidor e depois Comments.client uma vez montado no navegador -->
<Comments />
</div>
</template>
Componentes Embutidos do Nuxt
Existem vários componentes que o Nuxt fornece, incluindo <ClientOnly>
e <DevOnly>
. Você pode ler mais sobre eles na documentação da API.
Autores de Bibliotecas
Fazer bibliotecas de componentes Vue com tree-shaking automático e registro de componentes é super fácil. ✨
Você pode usar o método addComponentsDir
fornecido pelo @nuxt/kit
para registrar seu diretório de componentes em seu módulo Nuxt.
Imagine uma estrutura de diretório como esta:
-| node_modules/
---| awesome-ui/
-----| components/
-------| Alert.vue
-------| Button.vue
-----| nuxt.ts
-| pages/
---| index.vue
-| nuxt.config.ts
Então, em awesome-ui/nuxt.ts
, você pode usar o hook addComponentsDir
:
import { createResolver, defineNuxtModule, addComponentsDir } from '@nuxt/kit'
export default defineNuxtModule({
setup() {
const resolver = createResolver(import.meta.url)
// Adicione o diretório ./components à lista
addComponentsDir({
path: resolver.resolve('./components'),
prefix: 'awesome',
})
},
})
É isso! Agora, em seu projeto, você pode importar sua biblioteca de UI como um módulo Nuxt em seu arquivo nuxt.config
:
export default defineNuxtConfig({
modules: ['awesome-ui/nuxt']
})
... e usar diretamente os componentes do módulo (prefixados com awesome-
) em nosso pages/index.vue
:
<template>
<div>
Meu <AwesomeButton>botão de UI</AwesomeButton>!
<awesome-alert>Aqui está um alerta!</awesome-alert>
</div>
</template>
Ele importará automaticamente os componentes apenas se usados e também suportará HMR ao atualizar seus componentes em node_modules/awesome-ui/components/
.
※Esta página é uma tradução não oficial da documentação oficial do Nuxt.js.
A página correspondente na documentação oficial está aqui:
https://nuxt.com/docs/3.x/guide/directory-structure/components