Guia de Atualização
Aprenda como atualizar para a versão mais recente do Nuxt.
Atualizando o Nuxt
Última versão
Para atualizar o Nuxt para a última versão, use o comando nuxt upgrade
.
npx nuxt upgrade
Canal de Lançamento Noturno
Para usar a última build do Nuxt e testar recursos antes do lançamento, leia sobre o guia do canal de lançamento noturno.
O canal de lançamento noturno com a tag latest
está atualmente acompanhando o branch Nuxt v4, o que significa que é particularmente provável que tenha mudanças significativas agora — tenha cuidado! Você pode optar pelo branch 3.x dos lançamentos noturnos com "nuxt": "npm:nuxt-nightly@3x"
.
Testando o Nuxt 4
O Nuxt 4 está programado para lançamento no segundo trimestre de 2025. Ele incluirá todos os recursos atualmente disponíveis através de compatibilityVersion: 4
.
Até o lançamento, é possível testar muitas das mudanças significativas do Nuxt 4 a partir da versão 3.12+ do Nuxt.
Optando pelo Nuxt 4
Primeiro, atualize o Nuxt para a última versão.
Depois, você pode definir sua compatibilityVersion
para corresponder ao comportamento do Nuxt 4:
export default defineNuxtConfig({
future: {
compatibilityVersion: 4,
},
// Para reativar _todo_ o comportamento do Nuxt v3, defina as seguintes opções:
// srcDir: '.',
// dir: {
// app: 'app'
// },
// experimental: {
// scanPageMeta: 'after-resolve',
// sharedPrerenderData: false,
// compileTemplate: true,
// resetAsyncDataToUndefined: true,
// templateUtils: true,
// relativeWatchPaths: true,
// normalizeComponentNames: false,
// spaLoadingTemplateLocation: 'within',
// parseErrorData: false,
// pendingWhenIdle: true,
// alwaysRunFetchOnKeyChange: true,
// defaults: {
// useAsyncData: {
// deep: true
// }
// }
// },
// features: {
// inlineStyles: true
// },
// unhead: {
// renderSSRHeadOptions: {
// omitLineBreaks: false
// }
// }
})
Por enquanto, você precisa definir a versão de compatibilidade em cada camada que opta pelo comportamento do Nuxt 4. Isso não será necessário após o lançamento do Nuxt 4.
Quando você define sua compatibilityVersion
para 4
, os padrões em toda a sua configuração do Nuxt mudarão para optar pelo comportamento do Nuxt v4, mas você pode reativar granularmente o comportamento do Nuxt v3 ao testar, seguindo as linhas comentadas acima. Por favor, registre problemas se houver, para que possamos resolvê-los no Nuxt ou no ecossistema.
Mudanças significativas ou importantes serão anotadas aqui junto com as etapas de migração para compatibilidade retroativa/progressiva.
Esta seção está sujeita a alterações até o lançamento final, então, por favor, verifique aqui regularmente se você está testando o Nuxt 4 usando compatibilityVersion: 4
.
Migrando Usando Codemods
Para facilitar o processo de atualização, colaboramos com a equipe do Codemod para automatizar muitas etapas de migração com alguns codemods de código aberto.
Se você encontrar algum problema, por favor, reporte-os à equipe do Codemod com npx codemod feedback
🙏
Para uma lista completa de codemods do Nuxt 4, informações detalhadas sobre cada um, suas fontes e várias maneiras de executá-los, visite o Registro de Codemods.
Você pode executar todos os codemods mencionados neste guia usando a seguinte receita codemod
:
npx codemod@latest nuxt/4/migration-recipe
Este comando executará todos os codemods em sequência, com a opção de desmarcar qualquer um que você não deseje executar. Cada codemod também está listado abaixo junto com sua respectiva mudança e pode ser executado independentemente.
Nova Estrutura de Diretórios
🚦 Nível de Impacto: Significativo
O Nuxt agora tem como padrão uma nova estrutura de diretórios, com compatibilidade retroativa (então, se o Nuxt detectar que você está usando a estrutura antiga, como com um diretório pages/
no nível superior, essa nova estrutura não se aplicará).
O que Mudou
- o novo
srcDir
padrão do Nuxt éapp/
por padrão, e a maioria das coisas são resolvidas a partir daí. serverDir
agora tem como padrão<rootDir>/server
em vez de<srcDir>/server
layers/
,modules/
epublic/
são resolvidos em relação a<rootDir>
por padrão- se estiver usando Nuxt Content v2.13+,
content/
é resolvido em relação a<rootDir>
- um novo
dir.app
é adicionado, que é o diretório onde procuramosrouter.options.ts
espa-loading-template.html
- isso tem como padrão<srcDir>/
Um exemplo de estrutura de pastas v4.
.output/
.nuxt/
app/
assets/
components/
composables/
layouts/
middleware/
pages/
plugins/
utils/
app.config.ts
app.vue
router.options.ts
content/
layers/
modules/
node_modules/
public/
server/
api/
middleware/
plugins/
routes/
utils/
nuxt.config.ts
👉 Para mais detalhes, veja o PR implementando esta mudança.
Razões para a Mudança
- Desempenho - colocar todo o seu código na raiz do seu repositório causa problemas com as pastas
.git/
enode_modules/
sendo escaneadas/incluídas por observadores de FS, o que pode atrasar significativamente a inicialização em sistemas que não são Mac OS. - Segurança de tipo no IDE -
server/
e o resto do seu aplicativo estão rodando em dois contextos completamente diferentes com diferentes importações globais disponíveis, e garantir queserver/
não esteja dentro da mesma pasta que o resto do seu aplicativo é um grande primeiro passo para garantir que você obtenha boas autocompletes no seu IDE.
Etapas de Migração
- Crie um novo diretório chamado
app/
. - Mova suas pastas
assets/
,components/
,composables/
,layouts/
,middleware/
,pages/
,plugins/
eutils/
para dentro dele, bem comoapp.vue
,error.vue
,app.config.ts
. Se você tiver umapp/router-options.ts
ouapp/spa-loading-template.html
, esses caminhos permanecem os mesmos. - Certifique-se de que suas pastas
nuxt.config.ts
,content/
,layers/
,modules/
,public/
eserver/
permaneçam fora da pastaapp/
, na raiz do seu projeto. - Lembre-se de atualizar quaisquer arquivos de configuração de terceiros para funcionar com a nova estrutura de diretórios, como sua configuração
tailwindcss
oueslint
(se necessário -@nuxtjs/tailwindcss
deve configurar automaticamente otailwindcss
corretamente).
Você pode automatizar esta migração executando npx codemod@latest nuxt/4/file-structure
No entanto, a migração não é necessária. Se você deseja manter sua estrutura de pastas atual, o Nuxt deve detectá-la automaticamente. (Se não detectar, por favor, abra um problema.) A única exceção é se você já tiver um srcDir
personalizado. Nesse caso, você deve estar ciente de que suas pastas modules/
, public/
e server/
serão resolvidas a partir do seu rootDir
em vez do seu srcDir
personalizado. Você pode substituir isso configurando dir.modules
, dir.public
e serverDir
se precisar.
Você também pode forçar uma estrutura de pastas v3 com a seguinte configuração:
export default defineNuxtConfig({
// Isso reverte o novo padrão srcDir de `app` de volta para o seu diretório raiz
srcDir: '.',
// Isso especifica o prefixo do diretório para `app/router.options.ts` e `app/spa-loading-template.html`
dir: {
app: 'app'
}
})
Camada de Busca de Dados Singleton
🚦 Nível de Impacto: Moderado
O que Mudou
O sistema de busca de dados do Nuxt (useAsyncData
e useFetch
) foi significativamente reorganizado para melhor desempenho e consistência:
-
Referências compartilhadas para a mesma chave: Todas as chamadas para
useAsyncData
ouuseFetch
com a mesma chave agora compartilham as mesmas referênciasdata
,error
estatus
. Isso significa que é importante que todas as chamadas com uma chave explícita não tenham opções conflitantes dedeep
,transform
,pick
,getCachedData
oudefault
. -
Mais controle sobre
getCachedData
: A funçãogetCachedData
agora é chamada toda vez que os dados são buscados, mesmo que isso seja causado por um observador ou chamandorefreshNuxtData
. (Anteriormente, novos dados eram sempre buscados e essa função não era chamada nesses casos.) Para permitir mais controle sobre quando usar dados em cache e quando buscar novamente, a função agora recebe um objeto de contexto com a causa da solicitação. -
Suporte a chave reativa: Agora você pode usar referências computadas, referências simples ou funções getter como chaves, o que permite a busca automática de dados (e armazena dados separadamente).
-
Limpeza de dados: Quando o último componente usando dados buscados com
useAsyncData
é desmontado, o Nuxt removerá esses dados para evitar o uso crescente de memória.
Razões para a Mudança
Essas mudanças foram feitas para melhorar o uso de memória e aumentar a consistência com estados de carregamento em chamadas de useAsyncData
.
Etapas de Migração
-
Verifique opções inconsistentes: Revise quaisquer componentes usando a mesma chave com opções ou funções de busca diferentes.
// Isso agora acionará um aviso const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { deep: false }) const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { deep: true })
Pode ser benéfico extrair quaisquer chamadas para
useAsyncData
que compartilhem uma chave explícita (e tenham opções personalizadas) em seu próprio composable:composables/useUserData.tsexport function useUserData(userId: string) { return useAsyncData( `user-${userId}`, () => fetchUser(userId), { deep: true, transform: (user) => ({ ...user, lastAccessed: new Date() }) } ) }
-
Atualize implementações de
getCachedData
:useAsyncData('key', fetchFunction, { - getCachedData: (key, nuxtApp) => { - return cachedData[key] - } + getCachedData: (key, nuxtApp, ctx) => { + // ctx.cause - pode ser 'initial' | 'refresh:hook' | 'refresh:manual' | 'watch' + + // Exemplo: Não use cache em atualização manual + if (ctx.cause === 'refresh:manual') return undefined + + return cachedData[key] + } })
Alternativamente, por enquanto, você pode desativar esse comportamento com:
export default defineNuxtConfig({
experimental: {
granularCachedData: false,
purgeCachedData: false
}
})
Desduplicação de Metadados de Rotas
🚦 Nível de Impacto: Mínimo
O que Mudou
É possível definir alguns metadados de rota usando definePageMeta
, como name
, path
, e assim por diante. Anteriormente, eles estavam disponíveis tanto na rota quanto nos metadados da rota (por exemplo, route.name
e route.meta.name
).
Agora, eles são acessíveis apenas no objeto de rota.
Razões para a Mudança
Isso é resultado de habilitar experimental.scanPageMeta
por padrão, e é uma otimização de desempenho.
Etapas de Migração
A migração deve ser direta:
const route = useRoute()
- console.log(route.meta.name)
+ console.log(route.name)
Nomes de Componentes Normalizados
🚦 Nível de Impacto: Moderado
O Vue agora gerará nomes de componentes que correspondem ao padrão de nomenclatura de componentes do Nuxt.
O que Mudou
Por padrão, se você não definiu manualmente, o Vue atribuirá um nome de componente que corresponde ao nome do arquivo do componente.
├─ components/
├─── SomeFolder/
├───── MyComponent.vue
Neste caso, o nome do componente seria MyComponent
, no que diz respeito ao Vue. Se você quisesse usar <KeepAlive>
com ele, ou identificá-lo no Vue DevTools, você precisaria usar esse nome.
Mas para importá-lo automaticamente, você precisaria usar SomeFolderMyComponent
.
Com esta mudança, esses dois valores corresponderão, e o Vue gerará um nome de componente que corresponde ao padrão de nomenclatura de componentes do Nuxt.
Etapas de Migração
Certifique-se de usar o nome atualizado em quaisquer testes que usem findComponent
de @vue/test-utils
e em qualquer <KeepAlive>
que dependa do nome do seu componente.
Alternativamente, por enquanto, você pode desativar esse comportamento com:
export default defineNuxtConfig({
experimental: {
normalizeComponentNames: false
}
})
Unhead v2
🚦 Nível de Impacto: Mínimo
O que Mudou
Unhead, usado para gerar tags <head>
, foi atualizado para a versão 2. Embora seja em grande parte compatível, inclui várias mudanças significativas para APIs de nível inferior.
- Propriedades removidas:
vmid
,hid
,children
,body
. - Entrada de Promise não é mais suportada.
- As tags agora são ordenadas usando Capo.js por padrão.
Etapas de Migração
As mudanças acima devem ter impacto mínimo no seu aplicativo.
Se você tiver problemas, deve verificar:
- Você não está usando nenhuma das propriedades removidas.
useHead({
meta: [{
name: 'description',
// meta tags não precisam de um vmid, ou uma chave
- vmid: 'description'
- hid: 'description'
}]
})
- Se você estiver usando Template Params ou Alias Tag Sorting, você precisará optar explicitamente por esses recursos agora.
import { TemplateParamsPlugin, AliasSortingPlugin } from '@unhead/vue/plugins'
export default defineNuxtPlugin({
setup() {
const unhead = injectHead()
unhead.use(TemplateParamsPlugin)
unhead.use(AliasSortingPlugin)
}
})
Embora não seja necessário, é recomendável atualizar quaisquer importações de @unhead/vue
para #imports
ou nuxt/app
.
-import { useHead } from '@unhead/vue'
+import { useHead } from '#imports'
Se você ainda tiver problemas, pode reverter para o comportamento da v1 habilitando a configuração head.legacy
.
export default defineNuxtConfig({
unhead: {
legacy: true,
}
})
Nova Localização do DOM para Tela de Carregamento de SPA
🚦 Nível de Impacto: Mínimo
O que Mudou
Ao renderizar uma página apenas para cliente (com ssr: false
), opcionalmente renderizamos uma tela de carregamento (de app/spa-loading-template.html
), dentro da raiz do aplicativo Nuxt:
<div id="__nuxt">
<!-- spa loading template -->
</div>
Agora, por padrão, renderizamos o template ao lado da raiz do aplicativo Nuxt:
<div id="__nuxt"></div>
<!-- spa loading template -->
Razões para a Mudança
Isso permite que o template de carregamento de SPA permaneça no DOM até que o suspense do aplicativo Vue seja resolvido, evitando um flash de branco.
Etapas de Migração
Se você estava direcionando o template de carregamento de SPA com CSS ou document.queryElement
, precisará atualizar seus seletores. Para esse propósito, você pode usar as novas opções de configuração app.spaLoaderTag
e app.spaLoaderAttrs
.
Alternativamente, você pode reverter para o comportamento anterior com:
export default defineNuxtConfig({
experimental: {
spaLoadingTemplateLocation: 'within',
}
})
Dados de Erro Analisados
🚦 Nível de Impacto: Mínimo
Era possível lançar um erro com uma propriedade data
, mas isso não era analisado. Agora, é analisado e disponibilizado no objeto error
. Embora seja uma correção, isso é tecnicamente uma mudança significativa se você estava confiando no comportamento anterior e analisando manualmente.
Etapas de Migração
Atualize seu error.vue
personalizado para remover qualquer análise adicional de error.data
:
<script setup lang="ts">
import type { NuxtError } from '#app'
const props = defineProps({
error: Object as () => NuxtError
})
- const data = JSON.parse(error.data)
+ const data = error.data
</script>
Alternativamente, você pode desativar essa mudança:
export default defineNuxtConfig({
experimental: {
parseErrorData: false
},
})
Estilos Inline Mais Granulares
🚦 Nível de Impacto: Moderado
O Nuxt agora só incluirá estilos inline para componentes Vue, não CSS global.
O que Mudou
Anteriormente, o Nuxt incluía todo o CSS, incluindo estilos globais, e removia elementos <link>
para arquivos CSS separados. Agora, o Nuxt fará isso apenas para componentes Vue (que anteriormente produziam chunks separados de CSS). Acreditamos que isso é um melhor equilíbrio entre reduzir solicitações de rede separadas (assim como antes, não haverá solicitações separadas para arquivos .css
individuais por página ou por componente no carregamento inicial), além de permitir o cache de um único arquivo CSS global e reduzir o tamanho do download do documento da solicitação inicial.
Etapas de Migração
Este recurso é totalmente configurável e você pode reverter para o comportamento anterior definindo inlineStyles: true
para incluir CSS global, bem como CSS por componente.
export default defineNuxtConfig({
features: {
inlineStyles: true
}
})
Escanear Metadados de Página Após Resolução
🚦 Nível de Impacto: Mínimo
O que Mudou
Agora escaneamos metadados de página (definidos em definePageMeta
) após chamar o hook pages:extend
em vez de antes.
Razões para a Mudança
Isso foi para permitir a varredura de metadados para páginas que os usuários queriam adicionar em pages:extend
. Ainda oferecemos uma oportunidade de alterar ou substituir metadados de página em um novo hook pages:resolved
.
Etapas de Migração
Se você quiser substituir metadados de página, faça isso em pages:resolved
em vez de em pages:extend
.
export default defineNuxtConfig({
hooks: {
- 'pages:extend'(pages) {
+ 'pages:resolved'(pages) {
const myPage = pages.find(page => page.path === '/')
myPage.meta ||= {}
myPage.meta.layout = 'overridden-layout'
}
}
})
Alternativamente, você pode reverter para o comportamento anterior com:
export default defineNuxtConfig({
experimental: {
scanPageMeta: true
}
})
Dados de Pré-renderização Compartilhados
🚦 Nível de Impacto: Médio
O que Mudou
Habilitamos um recurso experimental anteriormente para compartilhar dados de chamadas useAsyncData
e useFetch
, entre diferentes páginas. Veja PR original.
Razões para a Mudança
Este recurso compartilha automaticamente dados de payload entre páginas que são pré-renderizadas. Isso pode resultar em uma melhoria significativa de desempenho ao pré-renderizar sites que usam useAsyncData
ou useFetch
e buscam os mesmos dados em diferentes páginas.
Por exemplo, se seu site requer uma chamada useFetch
para cada página (por exemplo, para obter dados de navegação para um menu, ou configurações do site de um CMS), esses dados seriam buscados apenas uma vez ao pré-renderizar a primeira página que os usa, e então armazenados em cache para uso ao pré-renderizar outras páginas.
Etapas de Migração
Certifique-se de que qualquer chave única dos seus dados seja sempre resolvível para os mesmos dados. Por exemplo, se você estiver usando useAsyncData
para buscar dados relacionados a uma página específica, você deve fornecer uma chave que corresponda exclusivamente a esses dados. (useFetch
deve fazer isso automaticamente para você.)
// Isso seria inseguro em uma página dinâmica (por exemplo, `[slug].vue`) porque o slug da rota faz diferença
// para os dados buscados, mas o Nuxt não pode saber disso porque não está refletido na chave.
const route = useRoute()
const { data } = await useAsyncData(async () => {
return await $fetch(`/api/my-page/${route.params.slug}`)
})
// Em vez disso, você deve usar uma chave que identifique exclusivamente os dados buscados.
const { data } = await useAsyncData(route.params.slug, async () => {
return await $fetch(`/api/my-page/${route.params.slug}`)
})
Alternativamente, você pode desativar esse recurso com:
export default defineNuxtConfig({
experimental: {
sharedPrerenderData: false
}
})
Valores Padrão de data
e error
em useAsyncData
e useFetch
🚦 Nível de Impacto: Mínimo
O que Mudou
Os objetos data
e error
retornados de useAsyncData
agora terão como padrão undefined
.
Razões para a Mudança
Anteriormente, data
era inicializado como null
, mas redefinido em clearNuxtData
para undefined
. error
era inicializado como null
. Esta mudança visa trazer maior consistência.
Etapas de Migração
Se você estava verificando se data.value
ou error.value
eram null
, você pode atualizar essas verificações para verificar undefined
em vez disso.
Você pode automatizar esta etapa executando npx codemod@latest nuxt/4/default-data-error-value
Se você encontrar algum problema, pode reverter para o comportamento anterior com:
export default defineNuxtConfig({
experimental: {
defaults: {
useAsyncData: {
value: 'null',
errorValue: 'null'
}
}
}
})
Por favor, registre um problema se você estiver fazendo isso, pois não planejamos manter isso como configurável.
Remoção de valores boolean
obsoletos para a opção dedupe
ao chamar refresh
em useAsyncData
e useFetch
🚦 Nível de Impacto: Mínimo
O que Mudou
Anteriormente, era possível passar dedupe: boolean
para refresh
. Estes eram aliases de cancel
(true
) e defer
(false
).
const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt!' }))
async function refreshData () {
await refresh({ dedupe: true })
}
Razões para a Mudança
Esses aliases foram removidos, para maior clareza.
O problema surgiu ao adicionar dedupe
como uma opção para useAsyncData
, e removemos os valores booleanos, pois acabaram sendo opostos.
refresh({ dedupe: false })
significava não cancelar solicitações existentes em favor desta nova. Mas passar dedupe: true
dentro das opções de useAsyncData
significa não fazer novas solicitações se houver uma solicitação pendente existente. (Veja PR.)
Etapas de Migração
A migração deve ser direta:
const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt 3!' }))
async function refreshData () {
- await refresh({ dedupe: true })
+ await refresh({ dedupe: 'cancel' })
- await refresh({ dedupe: false })
+ await refresh({ dedupe: 'defer' })
}
Você pode automatizar esta etapa executando npx codemod@latest nuxt/4/deprecated-dedupe-value
Respeitar padrões ao limpar data
em useAsyncData
e useFetch
🚦 Nível de Impacto: Mínimo
O que Mudou
Se você fornecer um valor default
personalizado para useAsyncData
, isso agora será usado ao chamar clear
ou clearNuxtData
e será redefinido para seu valor padrão em vez de simplesmente não definido.
Razões para a Mudança
Frequentemente, os usuários definem um valor vazio apropriado, como um array vazio, para evitar a necessidade de verificar null
/undefined
ao iterar sobre ele. Isso deve ser respeitado ao redefinir/limpar os dados.
Etapas de Migração
Se você encontrar algum problema, pode reverter para o comportamento anterior, por enquanto, com:
export default defineNuxtConfig({
experimental: {
resetAsyncDataToUndefined: true,
}
})
Por favor, registre um problema se você estiver fazendo isso, pois não planejamos manter isso como configurável.
Alinhamento do valor pending
em useAsyncData
e useFetch
🚦 Nível de Impacto: Médio
O objeto pending
retornado de useAsyncData
, useFetch
, useLazyAsyncData
e useLazyFetch
agora é uma propriedade computada que é true
apenas quando status
também está pendente.
O que Mudou
Agora, quando immediate: false
é passado, pending
será false
até que a primeira solicitação seja feita. Esta é uma mudança em relação ao comportamento anterior, onde pending
era sempre true
até que a primeira solicitação fosse feita.
Razões para a Mudança
Isso alinha o significado de pending
com a propriedade status
, que também está pending
quando a solicitação está em andamento.
Etapas de Migração
Se você depende da propriedade pending
, certifique-se de que sua lógica leva em conta o novo comportamento onde pending
será true
apenas quando o status também estiver pendente.
<template>
- <div v-if="!pending">
+ <div v-if="status === 'success'">
<p>Data: {{ data }}</p>
</div>
<div v-else>
<p>Loading...</p>
</div>
</template>
<script setup lang="ts">
const { data, pending, execute, status } = await useAsyncData(() => fetch('/api/data'), {
immediate: false
})
onMounted(() => execute())
</script>
Alternativamente, você pode reverter temporariamente para o comportamento anterior com:
export default defineNuxtConfig({
experimental: {
pendingWhenIdle: true
}
})
Comportamento de Mudança de Chave em useAsyncData
e useFetch
🚦 Nível de Impacto: Médio
O que Mudou
Ao usar chaves reativas em useAsyncData
ou useFetch
, o Nuxt busca automaticamente dados quando a chave muda. Quando immediate: false
é definido, useAsyncData
buscará dados apenas quando a chave mudar se os dados já tiverem sido buscados uma vez.
Anteriormente, useFetch
tinha um comportamento ligeiramente diferente. Ele sempre buscava dados quando a chave mudava.
Agora, useFetch
e useAsyncData
se comportam de forma consistente - buscando dados apenas quando a chave muda se os dados já tiverem sido buscados uma vez.
Razões para a Mudança
Isso garante um comportamento consistente entre useAsyncData
e useFetch
, e previne buscas inesperadas. Se você definiu immediate: false
, então você deve chamar refresh
ou execute
ou os dados nunca serão buscados em useFetch
ou useAsyncData
.
Etapas de Migração
Esta mudança deve geralmente melhorar o comportamento esperado, mas se você estava esperando que a mudança de chave ou opções de um useFetch
não imediato, agora você precisará acioná-lo manualmente pela primeira vez.
const id = ref('123')
const { data, execute } = await useFetch('/api/test', {
query: { id },
immediate: false
)
+ watch(id, execute, { once: true })
Para optar por não participar desse comportamento:
// Ou globalmente na sua configuração do Nuxt
export default defineNuxtConfig({
experimental: {
alwaysRunFetchOnKeyChange: true
}
})
Reatividade de Dados Superficial em useAsyncData
e useFetch
🚦 Nível de Impacto: Mínimo
O objeto data
retornado de useAsyncData
, useFetch
, useLazyAsyncData
e useLazyFetch
agora é um shallowRef
em vez de um ref
.
O que Mudou
Quando novos dados são buscados, qualquer coisa que dependa de data
ainda será reativa porque o objeto inteiro é substituído. Mas se seu código mudar uma propriedade dentro dessa estrutura de dados, isso não acionará nenhuma reatividade no seu aplicativo.
Razões para a Mudança
Isso traz uma melhoria significativa de desempenho para objetos e arrays profundamente aninhados porque o Vue não precisa observar cada propriedade/array para modificação. Na maioria dos casos, data
também deve ser imutável.
Etapas de Migração
Na maioria dos casos, nenhuma etapa de migração é necessária, mas se você depende da reatividade do objeto de dados, então você tem duas opções:
- Você pode optar por reatividade profunda em uma base por composable:
- const { data } = useFetch('/api/test') + const { data } = useFetch('/api/test', { deep: true })
- Você pode alterar o comportamento padrão em todo o projeto (não recomendado):
nuxt.config.ts
export default defineNuxtConfig({ experimental: { defaults: { useAsyncData: { deep: true } } } })
Se precisar, você pode automatizar esta etapa executando npx codemod@latest nuxt/4/shallow-function-reactivity
Caminhos de Observação Absolutos em builder:watch
🚦 Nível de Impacto: Mínimo
O que Mudou
O hook builder:watch
do Nuxt agora emite um caminho que é absoluto em vez de relativo ao seu srcDir
do projeto.
Razões para a Mudança
Isso nos permite suportar a observação de caminhos que estão fora do seu srcDir
, e oferece melhor suporte para camadas e outros padrões mais complexos.
Etapas de Migração
Já migramos proativamente os módulos públicos do Nuxt que sabemos que usam esse hook. Veja issue #25339.
No entanto, se você é um autor de módulo usando o hook builder:watch
e deseja permanecer compatível para trás/para frente, você pode usar o seguinte código para garantir que seu código funcione da mesma forma no Nuxt v3 e no Nuxt v4:
+ import { relative, resolve } from 'node:fs'
// ...
nuxt.hook('builder:watch', async (event, path) => {
+ path = relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, path))
// ...
})
Você pode automatizar esta etapa executando npx codemod@latest nuxt/4/absolute-watch-path
Remoção do objeto window.__NUXT__
O que Mudou
Estamos removendo o objeto global window.__NUXT__
após o aplicativo terminar a hidratação.
Razões para a Mudança
Isso abre caminho para padrões de múltiplos aplicativos (#21635) e nos permite focar em uma única maneira de acessar dados do aplicativo Nuxt - useNuxtApp()
.
Etapas de Migração
Os dados ainda estão disponíveis, mas podem ser acessados com useNuxtApp().payload
:
- console.log(window.__NUXT__)
+ console.log(useNuxtApp().payload)
Escaneamento de Índice de Diretório
🚦 Nível de Impacto: Médio
O que Mudou
Pastas filhas na sua pasta middleware/
também são escaneadas para arquivos index
e agora também são registradas como middleware no seu projeto.
Razões para a Mudança
O Nuxt escaneia automaticamente uma série de pastas, incluindo middleware/
e plugins/
.
Pastas filhas na sua pasta plugins/
são escaneadas para arquivos index
e queríamos tornar esse comportamento consistente entre diretórios escaneados.
Etapas de Migração
Provavelmente nenhuma migração é necessária, mas se você quiser reverter para o comportamento anterior, pode adicionar um hook para filtrar esses middlewares:
export default defineNuxtConfig({
hooks: {
'app:resolve'(app) {
app.middleware = app.middleware.filter(mw => !/\/index\.[^/]+$/.test(mw.path))
}
}
})
Mudanças na Compilação de Templates
🚦 Nível de Impacto: Mínimo
O que Mudou
Anteriormente, o Nuxt usava lodash/template
para compilar templates localizados no sistema de arquivos usando o formato/sintaxe de arquivo .ejs
.
Além disso, fornecemos algumas utilidades de template (serialize
, importName
, importSources
) que poderiam ser usadas para geração de código dentro desses templates, que agora estão sendo removidas.
Razões para a Mudança
No Nuxt v3, mudamos para uma sintaxe 'virtual' com uma função getContents()
que é muito mais flexível e performática.
Além disso, lodash/template
teve uma sucessão de problemas de segurança. Estes não se aplicam realmente a projetos Nuxt porque está sendo usado em tempo de build, não em tempo de execução, e por código confiável. No entanto, eles ainda aparecem em auditorias de segurança. Além disso, lodash
é uma dependência pesada e é não utilizada pela maioria dos projetos.
Finalmente, fornecer funções de serialização de código diretamente dentro do Nuxt não é ideal. Em vez disso, mantemos projetos como unjs/knitwork que podem ser dependências do seu projeto, e onde problemas de segurança podem ser relatados/resolvidos diretamente sem exigir uma atualização do próprio Nuxt.
Etapas de Migração
Levantamos PRs para atualizar módulos usando sintaxe EJS, mas se você precisar fazer isso sozinho, você tem três alternativas compatíveis para trás/para frente:
- Mover sua lógica de interpolação de strings diretamente para
getContents()
. - Usar uma função personalizada para lidar com a substituição, como em https://github.com/nuxt-modules/color-mode/pull/240.
- Use
es-toolkit/compat
(um substituto direto para o template lodash), como uma dependência do seu projeto em vez do Nuxt:
+ import { readFileSync } from 'node:fs'
+ import { template } from 'es-toolkit/compat'
// ...
addTemplate({
fileName: 'appinsights-vue.js'
options: { /* algumas opções */ },
- src: resolver.resolve('./runtime/plugin.ejs'),
+ getContents({ options }) {
+ const contents = readFileSync(resolver.resolve('./runtime/plugin.ejs'), 'utf-8')
+ return template(contents)({ options })
+ },
})
Finalmente, se você estiver usando as utilidades de template (serialize
, importName
, importSources
), você pode substituí-las como segue com utilitários de knitwork
:
import { genDynamicImport, genImport, genSafeVariableName } from 'knitwork'
const serialize = (data: any) => JSON.stringify(data, null, 2).replace(/"{(.+)}"(?=,?$)/gm, r => JSON.parse(r).replace(/^{(.*)}$/, '$1'))
const importSources = (sources: string | string[], { lazy = false } = {}) => {
return toArray(sources).map((src) => {
if (lazy) {
return `const ${genSafeVariableName(src)} = ${genDynamicImport(src, { comment: `webpackChunkName: ${JSON.stringify(src)}` })}`
}
return genImport(src, genSafeVariableName(src))
}).join('\n')
}
const importName = genSafeVariableName
Você pode automatizar esta etapa executando npx codemod@latest nuxt/4/template-compilation-changes
Remoção de Recursos Experimentais
🚦 Nível de Impacto: Mínimo
O que Mudou
Quatro recursos experimentais não são mais configuráveis no Nuxt 4:
experimental.treeshakeClientOnly
serátrue
(padrão desde v3.0)experimental.configSchema
serátrue
(padrão desde v3.3)experimental.polyfillVueUseHead
seráfalse
(padrão desde v3.4)experimental.respectNoSSRHeader
seráfalse
(padrão desde v3.4)vite.devBundler
não é mais configurável - usarávite-node
por padrão
Razões para a Mudança
Essas opções foram definidas para seus valores atuais há algum tempo e não temos razão para acreditar que precisam permanecer configuráveis.
Etapas de Migração
-
polyfillVueUseHead
é implementável em user-land com este plugin -
respectNoSSRHeader
é implementável em user-land com middleware de servidor
Nuxt 2 vs. Nuxt 3+
Na tabela abaixo, há uma comparação rápida entre 3 versões do Nuxt:
Recurso / Versão | Nuxt 2 | Nuxt Bridge | Nuxt 3+ |
---|---|---|---|
Vue | 2 | 2 | 3 |
Estabilidade | 😊 Estável | 😊 Estável | 😊 Estável |
Desempenho | 🏎 Rápido | ✈️ Mais Rápido | 🚀 Mais Rápido |
Motor Nitro | ❌ | ✅ | ✅ |
Suporte ESM | 🌙 Parcial | 👍 Melhor | ✅ |
TypeScript | ☑️ Opt-in | 🚧 Parcial | ✅ |
API de Composição | ❌ | 🚧 Parcial | ✅ |
API de Opções | ✅ | ✅ | ✅ |
Importação Automática de Componentes | ✅ | ✅ | ✅ |
Sintaxe <script setup> | ❌ | 🚧 Parcial | ✅ |
Importações Automáticas | ❌ | ✅ | ✅ |
webpack | 4 | 4 | 5 |
Vite | ⚠️ Parcial | 🚧 Parcial | ✅ |
CLI do Nuxt | ❌ Antigo | ✅ nuxt | ✅ nuxt |
Sites Estáticos | ✅ | ✅ | ✅ |
Nuxt 2 para Nuxt 3+
O guia de migração fornece uma comparação passo a passo dos recursos do Nuxt 2 para os recursos do Nuxt 3+ e orientação para adaptar seu aplicativo atual.
Veja também migration > overviewNuxt 2 para Nuxt Bridge
Se você preferir migrar progressivamente seu aplicativo Nuxt 2 para o Nuxt 3, você pode usar o Nuxt Bridge. O Nuxt Bridge é uma camada de compatibilidade que permite usar recursos do Nuxt 3+ no Nuxt 2 com um mecanismo de opt-in.
Veja também bridge > overview※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/getting-started/upgrade