Экспериментальные возможности

Включение экспериментальных возможностей Nuxt для доступа к новому функционалу.

В Nuxt часть возможностей помечена как экспериментальные; их можно включить в конфигурации.

Описание этих возможностей задаётся в @nuxt/schema. Полный список и параметры — в API-документации и исходном коде.

Экспериментальные возможности могут быть изменены или удалены в будущих версиях.

alwaysRunFetchOnKeyChange

Запускать ли useFetch при изменении ключа, даже если задано immediate: false и запрос ещё не выполнялся.

useFetch и useAsyncData всегда перезапускаются при смене ключа, если immediate: true или запрос уже был выполнен.

По умолчанию флаг выключен; при необходимости включите:

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

appManifest

Использовать app manifest, чтобы на клиенте учитывались route rules.

По умолчанию включено; при необходимости отключите:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    appManifest: false,
  },
})

asyncContext

Включить нативный async context для вложенных композаблов в Nuxt и Nitro — возможность вызывать композаблы внутри асинхронных и снизить ошибки «Nuxt instance is unavailable».

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    asyncContext: true,
  },
})
Подробнее в pull-request на GitHub.

asyncEntry

Включает генерацию асинхронной точки входа для Vue-бандла, что помогает при использовании module federation.

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

extractAsyncDataHandlers

Выносит функции-обработчики из вызовов useAsyncData и useLazyAsyncData в отдельные чанки для улучшения code splitting и кэширования.

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

Обработчики, заданные inline, превращаются в динамически подгружаемые чанки:

<!-- До -->
<script setup>
const { data } = await useAsyncData('user', async () => {
  return await $fetch('/api/user')
})
</script>
<!-- После преобразования -->
<script setup>
const { data } = await useAsyncData('user', () =>
  import('/generated-chunk.js').then(r => r.default()),
)
</script>

Так логика загрузки данных выносится в отдельные чанки, но при необходимости код по-прежнему подгружается.

Рекомендуется только для статической сборки с извлечением payload, когда данные не нужно подгружать заново в рантайме.

emitRouteChunkError

Вызывает хук app:chunkError при ошибке загрузки чанков vite/webpack. По умолчанию при переходе на новый маршрут при сбое загрузки чанка выполняется перезагрузка нового маршрута.

По умолчанию Nuxt перезагружает новый маршрут при сбое загрузки чанка при навигации (automatic).

Значение automatic-immediate заставляет Nuxt перезагружать текущий маршрут сразу при сбое загрузки чанка (не дожидаясь навигации). Это полезно для ошибок чанков, не связанных с навигацией, например когда не удаётся загрузить ленивый компонент. Минус — возможные лишние перезагрузки, если приложению не нужен чанк, из-за которого произошла ошибка.

Автоматическую обработку можно отключить, задав false, или обрабатывать ошибки чанков вручную, задав manual.

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    emitRouteChunkError: 'automatic', // или 'automatic-immediate', 'manual' или false
  },
})

enforceModuleCompatibility

Нужно ли выбрасывать ошибку (и не загружать приложение), если модуль Nuxt несовместим.

По умолчанию отключено.

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

restoreState

Позволяет восстанавливать состояние приложения Nuxt из sessionStorage при перезагрузке страницы после ошибки чанка или вызова reloadNuxtApp().

Чтобы избежать ошибок гидрации, состояние применяется только после монтирования Vue-приложения, из-за чего при первой загрузке возможна краткая «вспышка».

Включайте с осторожностью: возможны неожиданные эффекты. Рекомендуется задавать явные ключи в useState, так как автогенерируемые ключи могут не совпадать между сборками.
nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    restoreState: true,
  },
})

inlineRouteRules

Задаёт правила маршрутов на уровне страницы через defineRouteRules.

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

Правила создаются по path страницы.

Подробнее в утилите defineRouteRules.
Узнать больше Docs > 4 X > Guide > Concepts > Rendering#hybrid Rendering.

noVueServer

Отключает эндпоинт Vue server renderer в Nitro.

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

parseErrorData

Нужно ли разбирать error.data при рендере страницы серверной ошибки.

По умолчанию включено; при необходимости можно отключить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    parseErrorData: false,
  },
})

payloadExtraction

Управляет тем, как передаются данные payload для пререндеренных и кэшируемых (ISR/SWR) страниц.

  • 'client' — payload встраивается в HTML при первом серверном рендере и выносится в файлы _payload.json для клиентской навигации. Нет отдельного сетевого запроса при первой загрузке и сохраняется эффективная клиентская навигация.
  • true — payload выносится в отдельный _payload.json и для первого рендера, и для клиентской навигации.
  • false — извлечение payload отключено. Payload всегда в HTML, файлы _payload.json не создаются.

По умолчанию true, при compatibilityVersion: 5'client'.

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    // Payload в HTML, в файлы — только для клиентской навигации
    payloadExtraction: 'client',
  },
})

Извлечение payload работает и для маршрутов с кэшированием ISR (Incremental Static Regeneration) или SWR (Stale-While-Revalidate). CDN могут кэшировать файлы payload вместе с HTML и ускорять клиентскую навигацию по кэшированным маршрутам.

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    payloadExtraction: 'client',
  },
  routeRules: {
    // Для этих маршрутов будут создаваться файлы payload
    '/products/**': { isr: 3600 },
    '/blog/**': { swr: true },
  },
})

clientNodePlaceholder

Вместо элементов <div> в SSR для client-only компонентов используются узлы-комментарии (<!--placeholder-->).

При включении .client.vue и обёртки createClientOnly() на сервере рендерят HTML-комментарий вместо пустого <div>. Это устраняет проблему гидратации Vue: scoped-стили могут не применяться, когда placeholder-<div> и корень компонента имеют одинаковый тег.

При включении атрибуты (class, style и т.д.), переданные в .client.vue, не попадут в SSR HTML. Если нужны стилизованные placeholder'ы против layout shift, используйте <ClientOnly> со слотом #fallback.

Флаг включается при future.compatibilityVersion 5 и выше, но его можно включить явно:

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

clientFallback

Включает экспериментальный компонент <NuxtClientFallback> для рендера контента на клиенте при ошибке SSR.

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

crossOriginPrefetch

Включает cross-origin prefetch через Speculation Rules API.

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    crossOriginPrefetch: true,
  },
})
Подробнее о Speculation Rules API.

viewTransition

Включает интеграцию View Transition API с клиентским роутером.

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

Можно передать объект для настройки типов view transition — разных CSS-анимаций в зависимости от типа навигации:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    viewTransition: {
      enabled: true,
      types: ['slide'],
    },
  },
})
Прочитайте и отредактируйте живой пример в https://stackblitz.com/edit/nuxt-view-transitions?file=app.vue.
Подробнее о View Transition API.
Подробнее о View Transition API.

writeEarlyHints

Включает отправку early hints при использовании node-сервера.

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

componentIslands

Включает экспериментальную поддержку component islands с <NuxtIsland> и файлами .island.vue.

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    componentIslands: true, // false или 'local+remote'
  },
})
Узнать больше Docs > 4 X > Directory Structure > App > Components#server Components.
Дорожная карта server components на GitHub.

localLayerAliases

Разрешать алиасы ~, ~~, @ и @@ внутри слоёв относительно исходной и корневой директорий слоя.

По умолчанию включено; при необходимости можно отключить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    localLayerAliases: false,
  },
})

typedPages

Включает новый экспериментальный типизированный роутер.

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

По умолчанию даёт типизированное использование navigateTo, <NuxtLink>, router.push() и др.

Типизированные параметры в странице: const route = useRoute('route-name').

watcher

Задаёт альтернативный watcher для отслеживания файлов в Nuxt.

По умолчанию используется chokidar-granular, который игнорирует корневые каталоги (например node_modules и .git).

Значение parcel подключает @parcel/watcher и может улучшить производительность в больших проектах и на Windows.

Значение chokidar включает отслеживание всех файлов в исходной директории.

Значение 'builder' переиспользует собственный file watcher активного сборщика (например, server.watcher у Vite) вместо запуска второго. Это уменьшает число watcher'ов в режиме разработки и станет значением по умолчанию при future.compatibilityVersion: 5. Если у сборщика нет своего watcher'а (сейчас webpack и rspack), Nuxt выводит предупреждение и возвращается к выбору по умолчанию.

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    watcher: 'chokidar-granular', // также возможны 'chokidar', 'parcel' или 'builder'
  },
})

sharedPrerenderData

Nuxt автоматически делится данными payload между пререндеренными страницами. Это может заметно ускорить пререндер сайтов с useAsyncData или useFetch, когда одни и те же данные запрашиваются на разных страницах.

При необходимости функцию можно отключить.

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    sharedPrerenderData: false,
  },
})

Важно: при включении опции ключ данных должен однозначно соответствовать этим данным. Например, при запросе данных страницы через useAsyncData задавайте ключ, однозначно идентифицирующий данные. (useFetch делает это автоматически.)

// Так делать небезопасно на динамической странице (напр. `[slug].vue`): slug влияет на данные,
// но Nuxt этого не видит, так как ключ от него не зависит.
const route = useRoute()
const { data } = await useAsyncData(async (_nuxtApp, { signal }) => {
  return await $fetch(`/api/my-page/${route.params.slug}`, { signal })
})
// Используйте ключ, однозначно идентифицирующий запрашиваемые данные.
const { data } = await useAsyncData(route.params.slug, async (_nuxtApp, { signal }) => {
  return await $fetch(`/api/my-page/${route.params.slug}`, { signal })
})

clientNodeCompat

При включении Nuxt полифиллит импорты Node.js в клиентской сборке с помощью unenv.

Чтобы глобалы вроде Buffer работали в браузере, их нужно подключать вручную.
import { Buffer } from 'node:buffer'

globalThis.Buffer ||= Buffer

scanPageMeta

Nuxt передаёт модулям на этапе сборки часть метаданных маршрута из definePageMeta (alias, name, path, redirect, props, middleware).

Работает только со статическими значениями или строками/массивами, не с переменными и условными присваиваниями. Подробнее: исходный issue.

По умолчанию метаданные страниц сканируются после регистрации всех маршрутов в pages:extend, затем вызывается хук pages:resolved.

При проблемах в проекте опцию можно отключить.

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    scanPageMeta: false,
  },
})

cookieStore

Включает поддержку CookieStore для отслеживания изменений cookies (если браузер поддерживает) и обновления ref из useCookie.

По умолчанию опция включена; при необходимости её можно отключить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    cookieStore: false,
  },
})
Подробнее о CookieStore.

buildCache

Кэширует артефакты сборки Nuxt по хешу конфигурации и исходных файлов.

Учитываются только исходные файлы в srcDir и serverDir (части Vue и Nitro приложения).

По умолчанию отключено; при необходимости можно включить:

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

При включении полная пересборка выполняется при изменении следующих файлов:

Directory structure
.nuxtrc
.npmrc
package.json
package-lock.json
yarn.lock
pnpm-lock.yaml
tsconfig.json
bun.lock
bun.lockb

Кроме того, любые изменения файлов в srcDir приводят к пересборке клиентского и серверного бандла Vue. Nitro пересобирается всегда (ведётся работа над тем, чтобы Nitro мог объявлять кэшируемые артефакты и их хеши).

Хранится не более 10 кэш-архивов.

checkOutdatedBuildInterval

Интервал (в мс) проверки наличия новых сборок. Не действует, если experimental.appManifest отключён.

Значение false отключает проверку.

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    checkOutdatedBuildInterval: 3600000, // 1 hour, or false to disable
  },
})

extraPageMetaExtractionKeys

Макрос definePageMeta() позволяет собирать метаданные страниц на этапе сборки. Nuxt предоставляет фиксированный набор поддерживаемых ключей для внутренних возможностей: редиректы, алиасы страниц, кастомные пути.

Эта опция задаёт дополнительные ключи для извлечения из метаданных страницы при использовании scanPageMeta.

<script lang="ts" setup>
definePageMeta({
  foo: 'bar',
})
</script>
export default defineNuxtConfig({
  experimental: {
    extraPageMetaExtractionKeys: ['foo'],
  },
  hooks: {
    'pages:resolved' (ctx) {
      // ✅ foo is available
    },
  },
})

Модули могут получать из метаданных страницы дополнительные ключи в контексте сборки. При использовании в модуле рекомендуется также дополнить типы NuxtPage своими ключами.

Перед навигацией ожидается один кадр анимации, чтобы браузер успел перерисовать экран и зафиксировать действие пользователя.

Может снижать INP при навигации по предрендеренным маршрутам.

По умолчанию включено; при необходимости можно отключить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    navigationRepaint: false,
  },
})

normalizeComponentNames

Nuxt приводит автоматически сгенерированные имена компонентов Vue к полному имени, которое используется при автоимпорте.

При возникновении проблем опцию можно отключить.

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    normalizeComponentNames: false,
  },
})

По умолчанию Vue назначает компоненту имя по имени файла, если имя не задано вручную.

Directory structure
├─ components/
├─── SomeFolder/
├───── MyComponent.vue

В этом случае имя компонента в Vue будет MyComponent. Для использования с <KeepAlive> или отображения в Vue DevTools нужно использовать это имя.

Для автоимпорта при этом потребуется имя SomeFolderMyComponent.

При включении experimental.normalizeComponentNames оба имени совпадают: Vue генерирует имя компонента по правилам именования Nuxt.

normalizePageNames

Имена компонентов страниц приводятся в соответствие с именами маршрутов. На компоненты страниц устанавливается свойство __name, чтобы Vue мог корректно различать их в <KeepAlive> по имени.

По умолчанию Vue назначает компонентам имена по имени файла: например, у pages/foo/index.vue и pages/bar/index.vue будет имя index. Из-за этого фильтрация <KeepAlive> по имени ненадёжна — несколько страниц имеют одно имя.

При включённом normalizePageNames компоненты страниц получают имена по маршруту (например, foo и bar), поэтому можно использовать <KeepAlive> с include/exclude без ручного добавления defineOptions({ name: '...' }) на каждой странице.

Опция включается при future.compatibilityVersion: 5 и выше; при необходимости её можно отключить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    normalizePageNames: false,
  },
})
app.vue
<template>
  <NuxtPage :keepalive="{ include: ['foo'] }" />
</template>

spaLoadingTemplateLocation

При рендере страницы только для клиента (ssr: false) при необходимости показывается экран загрузки из ~/spa-loading-template.html.

Значение within встраивает шаблон так:

<div id="__nuxt">
  <!-- spa loading template -->
</div>

Либо шаблон можно вывести рядом с корнем приложения Nuxt, задав значение body:

<div id="__nuxt"></div>
<!-- spa loading template -->

Это уменьшает белую вспышку при гидрации страницы только для клиента.

browserDevtoolsTiming

Включает маркеры производительности для хуков Nuxt в инструментах разработчика. Их можно смотреть во вкладке Performance в браузерах на Chromium — удобно для отладки и оптимизации.

По умолчанию включено в режиме разработки; при необходимости можно отключить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    browserDevtoolsTiming: false,
  },
})
Детали реализации в PR #29922.
Подробнее о Chrome DevTools Performance API.

debugModuleMutation

Записывает изменения nuxt.options в контексте модулей — помогает отлаживать правки конфигурации при инициализации Nuxt.

По умолчанию включено при включённом режиме debug; при необходимости можно отключить.

Чтобы включить явно:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    debugModuleMutation: true,
  },
})
Детали реализации в PR #30555.

lazyHydration

Включает стратегии гидрации для компонентов <Lazy>: гидрация откладывается до момента необходимости, что улучшает производительность.

По умолчанию включено; при необходимости можно отключить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    lazyHydration: false,
  },
})
Подробнее о ленивой гидрации.

templateImportResolution

Отключает разрешение импортов в шаблонах Nuxt относительно пути модуля, добавившего шаблон.

По умолчанию Nuxt разрешает импорты в шаблонах относительно модуля, который их добавил. Значение false отключает это поведение — может пригодиться при конфликтах разрешения в некоторых средах.

По умолчанию включено; при необходимости можно отключить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    templateImportResolution: false,
  },
})
Детали реализации в PR #31175.

templateRouteInjection

По умолчанию объект маршрута из автоимпортируемого композабла useRoute() синхронизирован с текущей страницей в <NuxtPage>. Для экспортируемого vue-router'ом useRoute и для объекта $route в шаблонах Vue это не так.

При включении этой опции подмешивается миксин, который синхронизирует объект $route в шаблоне с управляемым Nuxt useRoute().

По умолчанию включено; при необходимости можно отключить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    templateRouteInjection: false,
  },
})

decorators

Включает синтаксис декораторов во всём приложении Nuxt/Nitro.

При сборщике Vite (по умолчанию) декораторы обрабатываются через Babel и @babel/plugin-proposal-decorators. При webpack или rspack — через esbuild.

В TypeScript давно есть поддержка декораторов через compilerOptions.experimentalDecorators — это реализация до стандартизации TC39. Сейчас декораторы — предложение Stage 3, в TS 5.0+ поддерживаются без отдельной настройки (см. https://github.com/microsoft/TypeScript/pull/52582 и https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#decorators).

Включение experimental.decorators даёт поддержку предложения TC39, а не старой реализации TypeScript compilerOptions.experimentalDecorators.

До финального включения в стандарт JS возможны изменения.

Использование

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

При использовании сборщика Vite или серверной сборки Nitro потребуются дополнительные пакеты Babel в dev-зависимостях:

npm install -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
Nuxt предложит установить их автоматически, если они ещё не установлены.
app/app.vue
function something (_method: () => unknown) {
  return () => 'decorated'
}

class SomeClass {
  @something
  public someMethod () {
    return 'initial'
  }
}

const value = new SomeClass().someMethod()
// this will return 'decorated'

defaults

Задаёт опции по умолчанию для основных компонентов и композаблов Nuxt.

В будущем эти опции, вероятно, перенесут (например, в app.config или в каталог app/).

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    defaults: {
      nuxtLink: {
        componentName: 'NuxtLink',
        prefetch: true,
        prefetchOn: {
          visibility: true,
        },
      },
      useAsyncData: {
        deep: true,
      },
      useState: {
        resetOnClear: true,
      },
    },
  },
})

Опция useState.resetOnClear задаёт, сбрасывает ли clearNuxtState состояние в начальное значение (из функции init в useState) вместо undefined. По умолчанию true при compatibilityVersion: 5.

purgeCachedData

Очищать ли кэши Nuxt (static и asyncData) при навигации по маршрутам.

Nuxt автоматически очищает кэш из useAsyncData и nuxtApp.static.data. Это снижает утечки памяти и даёт актуальные данные при необходимости, но поведение можно отключить.

По умолчанию включено; при необходимости можно отключить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    purgeCachedData: false,
  },
})
Детали реализации в PR #31379.

prefetchPreloadTags

Если <NuxtLink> префетчится и у целевого маршрута включено извлечение payload (по умолчанию для пререндеренных и кэшируемых маршрутов), подсказки <link rel="preload">, которые целевая страница задала через useHead (или модули вроде <NuxtImg preload> из @nuxt/image), переносятся в текущий документ.

Перенесённые ссылки понижаются с rel="preload" до rel="prefetch", чтобы не конкурировать с критичными ресурсами текущей страницы. Переносятся только пользовательские теги head; preload чанков JS/CSS на этапе сборки уже обрабатываются отдельно в пайплайне префетча.

Флаг по умолчанию выключен: вместе с prefetchOn: 'visibility' (значение по умолчанию у <NuxtLink>) это может запустить много кросс-маршрутных префетчей сразу. Включайте его, когда уверены, что preload на целевых страницах стоит переносить для ссылок, с которыми обычно взаимодействуют пользователи.

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    prefetchPreloadTags: true,
  },
})
Мотивация описана в issue #34953.

granularCachedData

Вызывать ли и использовать ли результат getCachedData при обновлении данных для useAsyncData и useFetch (через watch, refreshNuxtData() или ручной вызов refresh()).

По умолчанию включено; при необходимости можно отключить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    granularCachedData: false,
  },
})
Детали реализации в PR #31373.

headNext

Оптимизации для работы с head:

  • Подключается плагин capo.js для более эффективного рендера тегов в <head>.
  • Используется плагин hash hydration для снижения нагрузки при начальной гидрации.

По умолчанию включено; при необходимости можно отключить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    headNext: false,
  },
})

pendingWhenIdle

Для useAsyncData и useFetch: должно ли pending быть true, пока загрузка данных ещё не начата.

По умолчанию отключено; при необходимости можно включить:

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

entryImportMap

По умолчанию Nuxt повышает стабильность чанков, разрешая entry-чанк бандла через import map.

В начало тега <head> добавляется import map:

<script type="importmap">{"imports":{"#entry":"/_nuxt/DC5HVSK5.js"}}</script>

В чанках скриптов, выдаваемых Vite, импорты идут из #entry. Изменения entry-файла не инвалидируют остальные неизменённые чанки.

Nuxt автоматически отключает эту возможность, если в vite.build.target указан браузер без поддержки import maps или если vite.build.rolldownOptions.output.entryFileNames задан без [hash].

Отключить эту возможность можно так:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    entryImportMap: false,
  },
  // или лучше задать нужный target в vite — Nuxt его учтёт
  vite: {
    build: {
      target: 'safari13',
    },
  },
})

typescriptPlugin

Включает улучшенный опыт разработки с TypeScript через модуль @dxup/nuxt.

Экспериментальный плагин даёт лучшую интеграцию TypeScript и инструменты для удобной работы с TypeScript в Nuxt.

По умолчанию отключено; при необходимости можно включить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    typescriptPlugin: true,
  },
})
Для использования нужно:
  • Иметь typescript в зависимостях
  • Настроить VS Code на использование TypeScript из workspace (см. документацию VS Code)
Подробнее о @dxup/nuxt.

ssrStreaming

Включает SSR-стриминг для улучшения Time to First Byte (TTFB). Сервер сразу отправляет HTML-оболочку (<head>, стили, preload-подсказки и entry-скрипты), затем постепенно стримит тело через renderToWebStream Vue.

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

Стриминг автоматически отключается для ботов и краулеров (Googlebot, Bingbot и т.д.), чтобы поисковики получали полностью отрендеренный HTML. Паттерн по умолчанию ловит только индексирующих краулеров; Lighthouse и другие аудит-инструменты в него не входят, чтобы синтетические замеры отражали тот же streamed-ответ, что и у пользователей. Regex детекции ботов можно переопределить:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    ssrStreaming: {
      botRegex: /googlebot|bingbot|my-internal-crawler/i,
    },
  },
})

Стриминг можно управлять по маршрутам через routeRules:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    ssrStreaming: true,
  },
  routeRules: {
    '/no-stream/**': { streaming: false },
  },
})
Автоматический fallback на буферизованный рендер. Стриминг фиксирует статус и заголовки ответа при flush оболочки, поэтому несовместим с изменениями ответа после рендера. Запросы с любым из условий ниже не стримятся: используется буферизованный рендер или редирект/ошибка:
  • routeRules с noScripts, cache, isr, swr, redirect или streaming: false для маршрута
  • маршруты с ssr: false (уже SPA)
  • user agent бота/краулера (через botRegex)
  • пререндеренные маршруты (nuxi generate)
  • серверные редиректы navigateTo() из плагинов, middleware или setup страницы
  • фатальные ошибки до flush оболочки
Статус и заголовки ответа нужно задать до flush оболочки. Стриминг фиксирует HTTP-статус и заголовки с первым байтом; всё, что меняет ответ после этого, до клиента не дойдёт. Это свойство стриминга, а не баг Nuxt.Граница — flush оболочки:
  • Доходит до клиента: мутации из плагинов Nuxt и Nitro, которые выполняются до начала рендера.
  • Теряется: setResponseStatus(), useResponseHeader(), запись useCookie() и вызовы h3 setHeader()/appendResponseHeader() во время рендера компонентов (в том числе после await в route middleware или <script setup>), потому что оболочка уже ушла в сеть.
Чтобы сохранить мутацию ответа, перенесите её в плагин или отключите стриминг для маршрута:
  • routeRules: { '/path': { streaming: false } }: статически, по маршруту.
  • хук render:route с ctx.prefersStream = false: в рантайме, по запросу (например, для условного 404).
В dev streaming handler пишет предупреждение с именем отброшенных мутаций и маршрутом.
Если ошибка случилась после фиксации HTTP-статуса, выставляется payload.error, а закрывающие теги всё равно отправляются как валидный документ — клиент подхватит ошибку при гидратации и покажет error page. Ошибки до flush оболочки обрабатывает буферизованный error renderer с корректным статусом.
Стили маршрута стримятся, JS-подсказки только для entry. Оболочка уходит до рендера маршрута, поэтому её <head> содержит только стили и подсказки entry-чанка. После регистрации модулей страницы и layout их CSS стримится сразу после оболочки (inline как <style> при inlineStyles, иначе как <link>), так что стили страницы, layout и top-level async-компонентов приходят до отрисовки body (вложенные async-компоненты — отдельный FOUC-кейс ниже). Route-specific JS-чанки из оболочки не прелоадятся; браузер находит их после парсинга entry-скрипта. Стриминг улучшает TTFB на любом маршруте; выигрыш по LCP максимален там, где JS маршрута пересекается с entry-чанком.
Component islands совместимы со стримингом. Контент слотов island и selective-client (nuxt-client) компоненты обычно вшиваются в HTML в post-render проходе, что невозможно после того, как body прошёл мимо якорей island. Вместо этого рендерер выводит каждый island teleport как inert <template> в конце документа и переносит его на место inline-скриптом до гидратации. Для app-кода это прозрачно. Исключение — сборки с features.noScripts и island-компонентами: fallback на буферизованный рендер, потому что relocation-скрипт не выполнится.

Хуки модулей

Модули участвуют в streamed-ответе через существующий хук render:html (теперь с флагом streaming: true во втором аргументе), хук решения по запросу и два хука только для стриминга:

  • render:route срабатывает один раз на запрос до рендера, для любого режима. Читайте ctx.canStream, чтобы понять, доступен ли стриминг для маршрута, и ставьте ctx.prefersStream = false, чтобы принудительно включить буферизацию (cookie, auth, A/B). Рендерер стримит только при canStream && prefersStream. Это runtime-escape для статического routeRules / botRegex.
  • render:html срабатывает один раз до flush оболочки с streaming: true во втором аргументе. Мутации htmlAttrs, head, bodyAttrs и bodyPrepend доходят до клиента. Мутации body/bodyAppend теряются, потому что body вот-вот начнёт стримиться (в dev будет предупреждение). Модули, которые меняют только head (CSP, OG, analytics meta), работают без изменений кода.
  • render:html:chunk срабатывает на каждый чанк рендерера до постановки в очередь. Меняйте ctx.chunk: Uint8Array (nonce injection); по ctx.index отличайте первый чанк от следующих.
  • render:html:close после завершения body stream, до закрывающих тегов. Меняйте ctx.bodyAppend: string[] для финальной разметки (analytics в конце body, debug-виджеты и т.д.).
// modules/streaming-csp/src/runtime/server-plugin.ts
import { defineNitroPlugin } from '#imports'

export default defineNitroPlugin((nitro) => {
  nitro.hooks.hook('render:html', (ctx, { event }) => {
    const nonce = event.context.cspNonce
    if (!nonce) { return }
    // Работает и для streaming (pre-shell), и для buffered (post-render).
    for (let i = 0; i < ctx.head.length; i++) {
      ctx.head[i] = ctx.head[i].replace(/<script(?![^>]*\snonce=)/g, `<script nonce="${nonce}"`)
    }
  })
})
CSP nonce. Streaming renderer выводит несколько inline-скриптов и стилей в обход unhead: bootstrap queue, IIFE, suspense head pushes, island-teleport relocation и route <style>. Если у head-скриптов есть nonce, renderer переиспользует его для всех — strict script-src/style-src 'nonce-…' не блокирует стриминг. Модулю достаточно проставить nonce на head-скриптах (как выше); хук render:html:chunk остаётся для скриптов, которые компоненты рендерят в body.
FOUC в dev для SFC-стилей: в development Vite отдаёт <style> из SFC как JS-модули, которые инжектят стили на клиенте после evaluate, без <link> в оболочке. При стриминге браузер начинает рисовать DOM до выполнения этих модулей — SFC-стили на миг без оформления.Обход: критичные для первой отрисовки стили положите в глобальный CSS через css: ['~/assets/main.css']. Глобальные файлы попадают в <link rel="stylesheet"> в <head> оболочки и применяются до стрима body. SFC <style> подходят для scoped-стилей, которые не блокируют первый paint.В production все стили извлекаются в CSS-файлы (или inline через features.inlineStyles), поэтому это касается только nuxt dev. Проверяйте стриминг через nuxt build && nuxt preview.
FOUC в production для вложенных async-компонентов: рендерер inline'ит CSS маршрута в чанке сразу после оболочки. Он видит только модули, уже зарегистрированные к этому моменту: страницу, layout и async-компонент прямо внутри <Suspense> (Vue создаёт их eagerly при старте рендера).Async-компонент внутри другого async-компонента создаётся только после resolve родителя, когда первый чанк уже ушёл. Его SFC <style> не попадает в post-shell styles chunk и уезжает в closing HTML за DOM компонента. Браузер рисует его без стилей до финального чанка.Держите paint-critical стили вне глубоко вложенных async-комponentов:
  • Стили, блокирующие первый paint, — в глобальном CSS (css: ['~/assets/main.css']); они попадают в <head> оболочки.
  • Utility-классы (Tailwind, UnoCSS): utility CSS в entry stylesheet, не в per-component <style>.
  • Async-компоненты с paint-critical <style> — прямо под <Suspense>, а не за другим async-родителем.
  • Или отключите стриминг: routeRules: { '/path': { streaming: false } }.
Scoped-стили на вложенных async-компонентах без критичности для первого экрана допустимы: краткая вспышка заметна только above-the-fold.