nuxt logo

Tradução da Documentação (Não Oficial)

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:

nuxt.config.ts
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á).

👉 Veja o RFC completo

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/ e public/ 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 procuramos router.options.ts e spa-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

  1. Desempenho - colocar todo o seu código na raiz do seu repositório causa problemas com as pastas .git/ e node_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.
  2. 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 que server/ 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

  1. Crie um novo diretório chamado app/.
  2. Mova suas pastas assets/, components/, composables/, layouts/, middleware/, pages/, plugins/ e utils/ para dentro dele, bem como app.vue, error.vue, app.config.ts. Se você tiver um app/router-options.ts ou app/spa-loading-template.html, esses caminhos permanecem os mesmos.
  3. Certifique-se de que suas pastas nuxt.config.ts, content/, layers/, modules/, public/ e server/ permaneçam fora da pasta app/, na raiz do seu projeto.
  4. 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 ou eslint (se necessário - @nuxtjs/tailwindcss deve configurar automaticamente o tailwindcss 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ê 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:

nuxt.config.ts
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:

  1. Referências compartilhadas para a mesma chave: Todas as chamadas para useAsyncData ou useFetch com a mesma chave agora compartilham as mesmas referências data, error e status. Isso significa que é importante que todas as chamadas com uma chave explícita não tenham opções conflitantes de deep, transform, pick, getCachedData ou default.

  2. Mais controle sobre getCachedData: A função getCachedData agora é chamada toda vez que os dados são buscados, mesmo que isso seja causado por um observador ou chamando refreshNuxtData. (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.

  3. 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).

  4. 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

  1. 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.ts
    export function useUserData(userId: string) {
      return useAsyncData(
        `user-${userId}`,
        () => fetchUser(userId),
        { 
          deep: true,
          transform: (user) => ({ ...user, lastAccessed: new Date() })
        }
      )
    }
    
  2. 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:

nuxt.config.ts
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.

Estrutura de diretórios
├─ 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:

nuxt.config.ts
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'
  }]
})
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:

nuxt.config.ts
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:

nuxt.config.ts
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.

nuxt.config.ts
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:

nuxt.config.ts
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ê.)

app/pages/test/[slug\
// 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:

nuxt.config.ts
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:

nuxt.config.ts
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).

app.vue
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:

nuxt.config.ts
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:

nuxt.config.ts
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:

  1. Você pode optar por reatividade profunda em uma base por composable:
    - const { data } = useFetch('/api/test')
    + const { data } = useFetch('/api/test', { deep: true })
    
  2. 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

Nuxt 2 vs. Nuxt 3+

Na tabela abaixo, há uma comparação rápida entre 3 versões do Nuxt:

Recurso / VersãoNuxt 2Nuxt BridgeNuxt 3+
Vue223
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
webpack445
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 > overview

Nuxt 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