Производительность Nuxt

Рекомендации по повышению производительности приложений Nuxt.

В Nuxt есть встроенные возможности для повышения производительности и улучшения Core Web Vitals. Есть и модули ядра Nuxt для точечной оптимизации. В этом разделе — рекомендации по производительности.

Встроенные возможности

Nuxt предоставляет несколько встроенных возможностей для оптимизации. Понимание их работы важно для достижения высокой скорости.

Ссылки

<NuxtLink> заменяет и <RouterLink> Vue Router, и обычный <a>. Компонент определяет внутренняя ссылка или внешняя и рендерит её с учётом оптимизаций (префетч, атрибуты по умолчанию и т.д.)

<template>
  <NuxtLink to="/about">О странице</NuxtLink>
</template>

<!-- Рендерится в ссылку с Vue Router и умным префетчем -->
<a href="/about">О странице</a>

В Nuxt по умолчанию включён умный префетч: когда ссылка попадает в зону видимости (по умолчанию — вьюпорт или при скролле), подгружается JavaScript целевой страницы, чтобы при клике она открывалась быстрее.

Можно включить префетч по взаимодействию:

export default defineNuxtConfig({
  experimental: {
    defaults: {
      nuxtLink: {
        prefetchOn: 'interaction',
      },
    },
  },
})
Узнать больше NuxtLink.

Гибридный рендеринг

В сложных приложениях может понадобиться гибко управлять тем, как рендерится приложение: часть страниц — при сборке, часть — на клиенте.

Гибридный рендеринг задаёт разные правила кэширования по маршрутам через Route Rules:

export default defineNuxtConfig({
  routeRules: {
    '/': {
      prerender: true,
    },
    '/products/**': {
      swr: 3600,
    },
    '/blog': {
      isr: 3600,
    },
    '/admin/**': {
      ssr: false,
    },
  },
})

Nuxt автоматически регистрирует соответствующие middleware и оборачивает маршруты обработчиками кэша Nitro.

Узнать больше Гибридный рендеринг.

Ленивая загрузка компонентов

Чтобы подгружать компонент динамически (lazy-loading), добавьте префикс Lazy к имени компонента. Это полезно, когда компонент нужен не всегда.

<script setup lang="ts">
const show = ref(false)
</script>

<template>
  <div>
    <h1>Горы</h1>
    <LazyMountainsList v-if="show" />
    <button v-if="!show" @click="show = true">Показать список</button>
  </div>
</template>

Префикс Lazy откладывает загрузку кода компонента до нужного момента и помогает уменьшить размер JavaScript-бандла.

Узнать больше Ленивая загрузка компонентов.

Ленивая гидрация

Не всегда нужно гидратировать все компоненты при первой загрузке. Ленивая гидрация позволяет контролировать, когда компонент станет интерактивным, и улучшить время до интерактивности. В Nuxt (с v3.16) можно задать момент гидрации.

<template>
  <div>
    <LazyMyComponent hydrate-on-visible />
  </div>
</template>

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

Узнать больше Ленивая гидрация.

Получение данных

Чтобы не запрашивать одни и те же данные дважды (на сервере и на клиенте), в Nuxt есть useFetch и useAsyncData. Они передают данные с сервера клиенту в payload вместо повторного запроса.

Узнать больше Получение данных.

Модули ядра Nuxt

Помимо встроенных возможностей, команда Nuxt поддерживает модули для дополнительной оптимизации: изображения, шрифты, сторонние скрипты.

Изображения

Неоптимизированные изображения сильно влияют на производительность и метрику Largest Contentful Paint (LCP).

В Nuxt можно использовать модуль Nuxt Image — оптимизация изображений из коробки: изменение размера и преобразования через встроенный оптимизатор или ваш CDN.

<NuxtImg> заменяет тег <img> и добавляет:

  • Оптимизацию локальных и удалённых изображений через встроенный провайдер
  • Преобразование src в оптимизированные URL (WebP, Avif и др.)
  • Автоматическое изменение размера по width и height
  • Генерацию адаптивных sizes при указании опции sizes
  • Нативный lazy loading и остальные атрибуты <img>

Изображения можно разделить по важности: те, что нужны сразу (LCP), и те, что можно подгрузить позже:

<template>
  <!-- 🚨 Нужно загрузить как можно раньше -->
  <NuxtImg
    src="/hero-banner.jpg"
    format="webp"
    preload
    loading="eager"
    fetch-priority="high"
    width="200"
    height="100"
  />

  <!-- 🐌 Можно загрузить позже -->
  <NuxtImg
    src="/facebook-logo.jpg"
    format="webp"
    loading="lazy"
    fetch-priority="low"
    width="200"
    height="100"
  />
</template>
Узнать больше Nuxt Image.

Шрифты

Nuxt Fonts оптимизирует шрифты (включая кастомные) и убирает лишние сетевые запросы для лучшей производительности и приватности.

Модуль автоматически хостит шрифты (через fontaine), что уменьшает сдвиги верстки при загрузке веб-шрифтов.

Nuxt Fonts обрабатывает CSS и при объявлении font-family автоматически:

  1. Находит шрифты — ищет файлы в public/, затем провайдеры (Google, Bunny, Fontshare).
  2. Генерирует @font-face — подставляет правила загрузки из нужных источников.
  3. Проксирует и кэширует — перенаправляет URL на /_fonts, скачивает и кэширует локально.
  4. Создаёт метрики fallback — подстраивает системные шрифты под веб-шрифты, снижая CLS.
  5. Включает шрифты в сборку — добавляет в проект с хешированием имён и длинным кэшем.

Поддерживаются несколько провайдеров, их можно расширять и заменять.

Скрипты

Сторонние ресурсы (аналитика, виджеты, карты, соцсети) улучшают функциональность, но могут сильно ухудшать Interaction to Next Paint (INP) и LCP.

Nuxt Scripts загружает сторонние скрипты с лучшей производительностью, приватностью и безопасностью.

Nuxt Scripts даёт слой поверх сторонних скриптов с поддержкой SSR и типизацией, сохраняя контроль над способом загрузки.

const { onLoaded, proxy } = useScriptGoogleAnalytics(
  {
    id: 'G-1234567',
    scriptOptions: {
      trigger: 'manual',
    },
  },
)
// ставить события в очередь до загрузки ga
proxy.gtag('config', 'UA-123456789-1')
// или дождаться загрузки ga
onLoaded((gtag) => {
  // скрипт загружен
})
Узнать больше Nuxt Scripts.

Инструменты профилирования

Чтобы улучшать производительность, её нужно измерять: сначала в разработке, затем на продакшене.

Nuxi Analyze

Команда nuxi позволяет анализировать продакшен-бандл приложения Nuxt. Используется vite-bundle-visualizer (аналог webpack-bundle-analyzer) для визуализации бандла и поиска самых тяжёлых частей.

Крупные блоки на диаграмме часто указывают на возможность оптимизации: разбиение, ленивая загрузка или замена библиотеки. Большие блоки из многих элементов можно уменьшить, импортируя только нужные части; отдельные крупные блоки — вынести в lazy loading.

Nuxt DevTools

Nuxt DevTools даёт представление о приложении Nuxt, помогает находить узкие места и управлять конфигурацией.

Возможности для оценки производительности:

  1. Timeline — время на рендеринг, обновление и инициализацию компонентов.
  2. Assets — размеры файлов (например, изображений) без преобразований.
  3. Render Tree — связи между компонентами Vue, скриптами и стилями для оптимизации загрузки.
  4. Inspect — список файлов приложения с размерами и временем выполнения.

Chrome DevTools

В Chrome DevTools полезны вкладки Performance и Lighthouse.

В Performance сразу видны LCP и CLS для текущей страницы (хорошо / нужно улучшить / плохо). При взаимодействии с страницей фиксируется INP — картина Core Web Vitals с учётом устройства и сети.

Lighthouse проверяет производительность, доступность, SEO, PWA и лучшие практики и формирует отчёт. Неуспешные проверки подсказывают, что улучшить.

У каждой проверки есть документация: зачем она нужна и как исправить проблемы.

PageSpeed Insights

PageSpeed Insights (PSI) оценивает опыт пользователя на мобильных и десктопах и даёт рекомендации по улучшению.

Есть лабораторные и полевые данные: лабораторные помогают отлаживать в контролируемых условиях, полевые отражают реальный опыт пользователей.

Web Page Test

WebPageTest — инструмент для детальной диагностики производительности страницы в разных условиях.

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

Типичные проблемы

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

Перебор с плагинами

Проблема: много плагинов или плагины с тяжёлой инициализацией замедляют гидрацию и ухудшают UX.

Решение: проверьте, можно ли часть логики перенести в композабл или утилиту.

Неиспользуемый код и зависимости

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

Решение: проверьте package.json на лишние зависимости и код на неиспользуемые утилиты, композаблы и функции.

Игнорирование рекомендаций Vue по производительности

Проблема: в документации Vue описаны приёмы оптимизации, применимые и в Nuxt, но разработчики часто фокусируются только на Nuxt и забывают про Vue.

Решение: используйте shallowRef, v-memo, v-once и другие приёмы из документации Vue.

Отход от принятых паттернов

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

Решение: зафиксируйте правила и паттерны, например Good practices and Design Patterns for Vue Composables.

Загрузка всего сразу

Проблема: без явного порядка загрузки всё запрашивается одновременно, что замедляет страницу и ухудшает UX.

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

Полезные материалы

  1. Apply instant loading with the PRPL pattern
  2. Perceived performance
  3. Understanding Critical Rendering Path