Релиз·  

Nuxt 4.5

Nuxt 4.5 — один из крупнейших релизов за последнее время. Vite 8, Rspack 2 на базе Rsbuild, экспериментальный SSR streaming, стабильная система кодов ошибок, новый composable useLayout, именованные views и подготовка к Nuxt 5.
Daniel Roe

Daniel Roe

@danielroe.dev

Nuxt 4.5 — крупный релиз. В нём три апгрейда сборщика (Vite 8, Rspack 2 и новый pipeline на Rsbuild для Rspack builder), экспериментальный SSR streaming, стабильная система кодов ошибок, несколько новых composables и соглашений, плюс работа, которая приближает Nuxt 5.

Много изменений — самое время заварить кофе. ☕️

📣 Новости

Подготовка к Nuxt 5

Заметная часть релиза — (надеемся) невидимая инфраструктура для Nuxt 5. Мы перешли на последние major-версии ряда ключевых зависимостей (unhead v3, unctx v3 и Vite 8), перевели сборку самого фреймворка на tsdown и ввели стабильный контракт выходной сборки nuxt/* с dev-экспортами, чтобы type-checking в monorepo Nuxt работал без шага сборки (#35463, #35605).

Большая часть работы сужает внутренний разрыв между v4 и v5, чтобы миграция была максимально скучной(?).

Чтобы проверить breaking changes Nuxt v4, включите future.compatibilityVersion: 5. Следите за Upgrade Guide — там появятся детали.

С выходом Nuxt v4.5 команда сосредоточится на стабилизации Nuxt v5 и утилитах совместимости для плавного апгрейда.

Конец поддержки Nuxt 3

Nuxt 3 выходит из поддержки 31 июля 2026 — это один из последних релизов линейки 3.x. Если вы всё ещё на v3, самое время переехать. Большинство назвали переход с v3 на v4 гладким, а upgrade guide мы держим актуальным.

Вместе с v4.5.0 выходит патч для линейки 3.x (v3.21.9) с совместимыми исправлениями и мелкими улучшениями из этого релиза. Ключевые пункты (Vite 8, Rspack 2, unhead v3, unctx v3) — крупные апгрейды и остаются только в v4, поэтому 3.x сохраняет стабильность до конца поддержки.

⚡️ Vite 8

Nuxt теперь работает на Vite 8 (#34256). Холодный старт быстрее, внутренности на Rolldown свежее, плюс апстрим-улучшения от команды Vite.

Для большинства приложений апгрейд прозрачен. Если у вас кастомные Vite-плагины или конфиг, загляните в Vite migration guide — вдруг что-то затронет вас.

Vite 8 — major-версия. Если вы напрямую зависите от Vite (кастомные плагины, правки vite.config или экосистемные плагины с фиксированной версией Vite), проверьте совместимость до продакшена.

🦀 Rspack 2 и Rsbuild

Если вы используете Rspack builder, этот релиз — существенный апгрейд. Мы перешли на Rspack 2 (#34929): быстрее, легче, и builder пересобран поверх @rsbuild/core (#35489).

Публичный API тот же. Подключение — builder: 'rspack', хуки rspack:* работают как раньше:

nuxt.config.ts
export default defineNuxtConfig({
  builder: 'rspack',
})

Под капотом многое улучшилось:

  • Dev-сервер теперь в middleware mode через Rsbuild вместо webpack-dev-middleware и webpack-hot-middleware (#35575).
  • Для SSR scoped-style ids и строгого ESM resolution используется Rspack-специфичный Vue loader (#35566).
Это основа для полноценной поддержки Rsbuild. Builder пока называется rspack, чтобы ничего не сломать, но внутри всё построено на Rsbuild.

🌊 Экспериментальный SSR Streaming

Это одна из фич, которая меня радует больше всего. Можно включить SSR streaming и сильно улучшить Time to First Byte (#34411). Вместо буферизации всей страницы Nuxt сразу отдаёт HTML-оболочку (<head>, стили, preload hints, entry scripts), а body стримит по мере рендера Vue.

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

Streaming автоматически отключается для ботов и краулеров, чтобы поисковики получали полностью отрендеренный HTML. Можно настроить user agents, считающиеся краулерами, и отключить streaming для отдельных маршрутов:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    ssrStreaming: {
      botRegex: /googlebot|bingbot|my-internal-crawler/i,
    },
  },
  routeRules: {
    '/no-stream/**': { streaming: false },
  },
})

Перед включением стоит понять одну вещь. Streaming фиксирует HTTP-статус и заголовки с первым байтом, поэтому всё, что меняет ответ после начала рендера (setResponseStatus() в <script setup>, запись cookie в middleware и т.д.), до клиента не дойдёт. Nuxt закрывает типичные случаи: маршруты с правилами redirect, cache, isr, swr, noScripts или ssr: false автоматически откатываются на buffered renderer, а в dev мы логируем предупреждение о пропущенных мутациях, чтобы ничего не терялось молча.

SSR streaming экспериментален и выключен по умолчанию. Подходит для контентных маршрутов, где важен TTFB, но проверьте логику мутаций ответа (статус, заголовки, cookies) до широкого выката. Experimental features docs описывают fallback и оговорки подробно.
Узнать больше Docs > Guide > Going Further > Experimental Features#ssrstreaming.

🩺 Стабильные коды ошибок

Меня это особенно радует. В Nuxt появилась стабильная система кодов ошибок (#35429) на nostics. Предупреждения и ошибки при сборке и в runtime теперь несут стабильный код (например NUXT_E1001 или NUXT_B5001), короткое объяснение почему это случилось, и конкретный fix.

Каждый код можно grep'ить и bookmark'ить; сложные случаи ведут на отдельную страницу доков. Классическая «composable вызвана вне Nuxt context» теперь — NUXT_E1001 с why/fix inline и docs page про правила context и runWithContext().

В продакшене verbose why/fix убирается, остаётся только стабильный код.

Это основа для гораздо лучших сообщений об ошибках; в следующих релизах будем переносить на неё существующие warnings и errors. 🔥

🎨 Composable useLayout

Новый composable useLayout читает layout, выбранный для текущего маршрута (#35623). Раньше не было чистого реактивного способа спросить из компонента «какой layout у этой страницы?».

app/components/LayoutBadge.vue
<script setup lang="ts">
const layout = useLayout()
</script>

<template>
  <span>Current layout: {{ layout }}</span>
</template>

Возвращает read-only computed ref: значение синхронизируется при навигации и когда route rules или definePageMeta меняют resolved layout.

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

🪟 Именованные views

Nuxt поддерживает named views через соглашение об именах файлов (#35123). Если родительская страница рендерит больше одного <NuxtPage>, каждому outlet можно дать имя и положить sibling-файл по соглашению name@view.vue:

Directory Structure
-| pages/
---| parent/
-----| child.vue
-----| child@sidebar.vue
---| parent.vue
pages/parent.vue
<template>
  <div>
    <NuxtPage />
    <aside>
      <NuxtPage name="sidebar" />
    </aside>
  </div>
</template>

При переходе на /parent/child child.vue попадает в default outlet, а child@sidebar.vue — в sidebar. В Vue Router это было давно; в этом релизе мы связали это с file-based routing Nuxt.

definePageMeta читается только из default route file, per-view rendering modes не поддерживаются (режим родительской страницы применяется к default view).
Узнать больше Docs > Guide > Directory Structure > App > Pages#named Views V45.

🚦 Опция enabled для useFetch и useAsyncData

Теперь можно блокировать fetch реактивной опцией enabled (#33260). Пока enabled равен false, каждый запуск блокируется (начальный fetch, execute/refresh, watch triggers). Если переключить с true на false во время запроса, in-flight request отменяется без очистки существующих data.

app/pages/search.vue
<script setup lang="ts">
const query = ref('')

const { data } = await useFetch('/api/search', {
  query: { q: query },
  // Only fetch once the user has typed something
  enabled: () => query.value.length > 2,
})
</script>

Удобно для зависимых или условных запросов, когда request не должен уходить, пока не выполнено условие. Работает с getter или ref и остаётся реактивным.

Узнать больше Docs > API > Composables > Use Async Data.

Если вы используете <NuxtLink> с prop custom, Nuxt больше не вешает prefetch handlers сам: он не знает, как устроена ваша разметка. Slot теперь отдаёт всё нужное для ручного prefetch (#34539):

<template>
  <NuxtLink
    v-slot="{ href, navigate, prefetch, prefetched, shouldPrefetch }"
    to="/about"
    custom
  >
    <a
      :href="href"
      :class="{ 'is-prefetched': prefetched }"
      @click="navigate"
      @pointerenter="shouldPrefetch('interaction') && prefetch()"
      @focus="shouldPrefetch('interaction') && prefetch()"
    >
      About page
    </a>
  </NuxtLink>
</template>

prefetch запускает prefetch, prefetched показывает, что он уже был (удобно для класса prefetched), shouldPrefetch учитывает соединение пользователя и конфиг.

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

⚡️ Forwarded Preload Hints при Prefetch

Попробуйте и эту опцию. При prefetch ссылки на маршрут с payload extraction Nuxt уже подгружает data и chunks назначения. С opt-in experimental.prefetchPreloadTags (#35144) он также пробрасывает <link rel="preload"> и modulepreload hints назначения (что страница задаёт через useHead или модули вроде <NuxtImg preload> из @nuxt/image) в текущий document, понижая до rel="prefetch", чтобы они не конкурировали с ресурсами текущей страницы.

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

На практике тяжёлые above-the-fold ресурсы следующей страницы (hero image, critical script) начинают качаться, пока пользователь ещё на текущей, и навигация ощущается мгновенной. По умолчанию выключено, пока собираем feedback — попробуйте и расскажите, как ведёт себя в вашем приложении.

🌐 import.meta.envName

Resolved Nuxt environment name теперь доступен в runtime как import.meta.envName для Vite и webpack/Rspack builds (#34844). Это значение из --envName (или resolved default), по нему можно ветвиться в коде приложения:

if (import.meta.envName === 'staging') {
  // enable staging-only behaviour
}
Узнать больше Docs > API > Advanced > Import Meta.

🔭 Tracing channels для SSR-событий

Nuxt публикует diagnostics-channel traces для server-side подсистем (#35191). Мы не навязываем стек: эмитим каналы nuxt.render, nuxt.island, nuxt.data и nuxt.plugin по соглашению untracing, поверх можно строить OpenTelemetry или что угодно ещё. Работает в Node, Deno, Bun и Cloudflare Workers.

nuxt.config.ts
export default defineNuxtConfig({
  // Turn on Nuxt's own channels
  tracingChannel: true,
})

Можно включать точечно. В Nuxt v5 появятся дополнительные Nitro-level channels:

nuxt.config.ts
export default defineNuxtConfig({
  tracingChannel: {
    nuxt: true,
  },
})
Имена каналов, формы payload и ключи опций могут ещё меняться, пока untracing registry не стабилизируется.

📦 Обновления зависимостей

unhead v3

Head management в Nuxt теперь на unhead v3 (#34793). Меньше размер, синхронный engine внутри, лучше type-safety для useHead из коробки. Это также разблокирует SSR streaming.

unhead v3 сужает типы для useHeadbreaking type change, если вы опирались на более мягкие типы v2. Runtime для подавляющего большинства приложений совместим; promise input (deprecated в v2) больше не поддерживается. Ошибки типов после апгрейда почти всегда означают реальное ужесточение, а не регрессию.

unctx v3

Мы перешли на unctx v3 (#35541), что закрывает класс давних async context issues (#33644). Это часть работы над надёжностью composable context, которая продолжится в v5.

И ещё

Обновили magic-string до v1, Babel до v8 и подтянули последний Rolldown повсюду. nuxt upgrade --dedupe (см. ниже) — самый простой способ аккуратно подтянуть всё это.

🛠️ Nuxt CLI

В релизе улучшения из @nuxt/cli v3.36 и v3.37:

  • nuxt module remove удаляет модуль и чистит его конфиг (nuxt/cli#1306), пара к nuxt module add.
  • Non-interactive nuxt init для скриптов и CI (nuxt/cli#1341); больше не спрашивает package manager, берёт его из шаблона (nuxt/cli#1330).
  • Онбординг type-check: nuxt typecheck предложит установить vue-tsc и typescript, если их нет (nuxt/cli#1316).
  • Поддержка Golar для type-checking: nuxt typecheck может использовать Golar вместо vue-tsc (nuxt/cli#1362). Подхватывается автоматически, если Golar установлен (или есть golar.config.*); checker можно задать явно: --checker=vue-tsc или --checker=golar:
    nuxt typecheck --checker=golar
    
  • Dev server с учётом layers: dev server перезагружается при изменениях nuxt.config в локальных layers (nuxt/cli#1345).

🧩 TypeScript Plugin и Named Layout Slots

Экспериментальный TypeScript plugin Nuxt работает на @dxup/nuxt, в релизе — более новая версия. Если не пробовали: experimental.typescriptPlugin даёт удобства в редакторе — переименование auto-imported component обновляет все использования, плюс go-to-definition для glob imports, Nitro routes, definePageMeta, runtimeConfig и typed route names.

В bundled версии появилась opt-in runtime фича: named layout slots (KazariEX/dxup#20). Можно написать top-level named-slot template на странице, и он попадёт в matching named slot активного layout. Страница сможет вставлять контент в slots layout — file-based layouts иначе этого не дают.

Включите вместе с plugin:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    typescriptPlugin: true,
  },
  dxup: {
    features: {
      namedLayoutSlots: true,
    },
  },
})

Layout может объявить named slots:

layouts/center.vue
<template>
  <slot />
  <slot name="side" one="one" />
</template>

Любая страница с этим layout заполняет их:

pages/about.vue
<script setup lang="ts">
definePageMeta({ layout: 'center' })
</script>

<template>
  <template #side="{ one }">
    This "{{ one }}" comes from the layout slot.
  </template>
  <div>About page</div>
</template>
Узнать больше Docs > Guide > Going Further > Experimental Features#typescriptplugin.

🔥 Производительность и надёжность

Как всегда, много работы ушло в скорость и стабильность.

Одна опция, которую можно включить уже сейчас: shared file watcher (#35143). Vite уже крутит chokidar-based watcher, и Nuxt может использовать его вместо второго — меньше памяти, меньше file handles. С compatibilityVersion: 5 это станет default, но включить можно сейчас:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    watcher: 'builder',
  },
})

Есть и улучшения без opt-in:

  • Быстрее старт dev-сервера – dev-only Nitro и pages work отложены и упрощены (#35381, #35383).
  • Легче production-сборки – island-renderer chunk не попадает в сборку без islands (#35456), plugin handling вырезается из prod builds (#35278).
  • Улучшенный island hashing – стабильнее island и key hashing; getIslandHash и hashKey теперь exposed (#35583).
  • Выигрыш по concurrency и I/O в Kit path resolution и Nitro inline styles (#35511, #35514).

Ещё пара quality-of-life fixes:

  • $fetch auto-imported в user code — закрывает edge cases с top-level $fetch.create под Rolldown output format (#35581).
  • Nuxt учитывает системные HTTP_PROXY / HTTPS_PROXY в builder environment (#35183).
  • HMR работает для defineNuxtComponent в JSX (#35620).

⚠️ На что обратить внимание перед апгрейдом

Как выше, в релизе три major dependency bumps. Для большинства приложений они прозрачны, но стоит проверить:

  • Vite 8 – сверьте кастомные Vite plugins и конфиг с Vite migration guide.
  • Rspack 2 – при builder: 'rspack' внутренности теперь на Rsbuild; кастомный Rspack config может потребовать правок.
  • unhead v3 – возможные breaking type changes из-за более строгой типизации useHead.

⬆️ Обновление

Рекомендуем апгрейд так:

npx nuxt upgrade --dedupe

# or, if you are staying on the 3.x line
npx nuxt@latest upgrade --dedupe --channel=v3

Команда deduplicate lockfile и подтягивает обновления зависимостей Nuxt, особенно в unjs ecosystem (в этом релизе это важнее обычного из-за major bumps).

При апгрейде со старой версии загляните в upgrade guide.

👉 Полные release notes

Полные release notes Nuxt v4.5.0.
Полные release notes Nuxt v3.21.9.

Спасибо всем, кто внёс вклад в этот релиз. Он получился большим, и без вас его бы не было. 💚

← Вернуться в блог
Nuxt в LinkedInNuxt в BlueskyNuxt в X