Оптимизация использования памяти

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

Рассмотрим стратегии и техники оптимизации памяти, а также способы решения распространённых проблем с памятью в Next.js.

Уменьшение количества зависимостей

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

Анализатор бандлов (Bundle Analyzer) поможет выявить крупные зависимости в вашем приложении, которые можно удалить для улучшения производительности и снижения потребления памяти.

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

Начиная с версии v15.0.0, вы можете добавить experimental.webpackMemoryOptimizations: true в файл next.config.js, чтобы изменить поведение Webpack, уменьшающее максимальное потребление памяти, но потенциально незначительно увеличивающее время компиляции.

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

Запуск next build с --experimental-debug-memory-usage

Начиная с версии 14.2.0, вы можете запустить next build --experimental-debug-memory-usage для выполнения сборки в режиме, где Next.js будет непрерывно выводить информацию о потреблении памяти в процессе сборки, такую как использование кучи и статистику сборки мусора. Снимки кучи (heap snapshots) также будут автоматически создаваться при приближении к установленному лимиту памяти.

Важно знать: Эта функция несовместима с опцией Webpack build worker, которая автоматически включается, если у вас нет пользовательской конфигурации Webpack.

Запись профиля кучи

Для поиска проблем с памятью вы можете записать профиль кучи из Node.js и загрузить его в Chrome DevTools для выявления потенциальных источников утечек памяти.

В терминале передайте флаг --heap-prof в Node.js при запуске сборки Next.js:

node --heap-prof node_modules/next/dist/bin/next build

После завершения сборки Node.js создаст файл .heapprofile.

В Chrome DevTools откройте вкладку "Memory" и нажмите кнопку "Load Profile" для визуализации файла.

Анализ снимка кучи

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

При запуске команд next build или next dev добавьте NODE_OPTIONS=--inspect в начало команды. Это откроет агент инспектора на стандартном порту. Если вы хотите остановить выполнение до запуска пользовательского кода, используйте --inspect-brk. Во время работы процесса вы можете подключиться к порту отладки через инструменты вроде Chrome DevTools, чтобы записать и проанализировать снимок кучи для определения удерживаемой памяти.

Начиная с версии 14.2.0, вы также можете запустить next build с флагом --experimental-debug-memory-usage для упрощения создания снимков кучи.

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

Снимок кучи сохранится в корне проекта Next.js и может быть загружен в любой анализатор кучи, например Chrome DevTools, для просмотра удерживаемой памяти. Этот режим пока несовместим с Webpack build workers.

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

Webpack build worker

Webpack build worker позволяет запускать компиляции Webpack в отдельном Node.js воркере, что уменьшает потребление памяти приложением во время сборок.

Эта опция включена по умолчанию, начиная с версии v14.1.0, если в приложении нет пользовательской конфигурации Webpack.

Если вы используете более старую версию Next.js или имеете пользовательскую конфигурацию Webpack, вы можете включить эту опцию, установив experimental.webpackBuildWorker: true в файле next.config.js.

Важно знать: Эта функция может быть несовместима со всеми пользовательскими плагинами Webpack.

Отключение кэша Webpack

Кэш Webpack сохраняет сгенерированные модули Webpack в памяти и/или на диске для ускорения сборок. Это может улучшить производительность, но также увеличит потребление памяти приложением для хранения кэшированных данных.

Вы можете отключить это поведение, добавив пользовательскую конфигурацию Webpack в ваше приложение:

next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (
    config,
    { buildId, dev, isServer, defaultLoaders, nextRuntime, webpack }
  ) => {
    if (config.cache && !dev) {
      config.cache = Object.freeze({
        type: 'memory',
      })
    }
    // Важно: вернуть изменённую конфигурацию
    return config
  },
}

export default nextConfig

Отключение статического анализа

Проверка типов и линтинг могут потреблять много памяти, особенно в крупных проектах. Однако большинство проектов имеют выделенный CI-раннер, который уже выполняет эти задачи. Если сборка вызывает ошибки нехватки памяти на этапе "Linting and checking validity of types", вы можете отключить эти задачи во время сборки:

next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  eslint: {
    // Предупреждение: Это позволяет успешно завершать продакшен-сборки,
    // даже если в проекте есть ошибки ESLint.
    ignoreDuringBuilds: true,
  },
  typescript: {
    // !! ВНИМАНИЕ !!
    // Опасная опция: позволяет успешно завершать продакшен-сборки,
    // даже если в проекте есть ошибки типов.
    // !! ВНИМАНИЕ !!
    ignoreBuildErrors: true,
  },
}

export default nextConfig

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

Отключение source maps

Генерация source maps потребляет дополнительную память во время сборки.

Вы можете отключить генерацию source maps, добавив productionBrowserSourceMaps: false и experimental.serverSourceMaps: false в конфигурацию Next.js.

Важно знать: Некоторые плагины могут включать source maps и могут требовать пользовательской конфигурации для отключения.

Проблемы с памятью в Edge runtime

В версии Next.js v14.1.3 была исправлена проблема с памятью при использовании Edge runtime. Обновитесь до этой версии (или новее), чтобы проверить, решает ли она вашу проблему.

Предзагрузка записей

При запуске сервера Next.js предзагружает JavaScript-модули каждой страницы в память, а не во время запроса.

Эта оптимизация обеспечивает более быстрые отклики в обмен на большее начальное потребление памяти.

Для отключения этой оптимизации установите флаг experimental.preloadEntriesOnStart в false.

import type { NextConfig } from 'next'

const config: NextConfig = {
  experimental: {
    preloadEntriesOnStart: false,
  },
}

export default config
/** @type {import('next').NextConfig} */
const config = {
  experimental: {
    preloadEntriesOnStart: false,
  },
}

export default config

Next.js не выгружает эти JavaScript-модули, поэтому даже с отключённой оптимизацией потребление памяти сервером Next.js в конечном итоге будет таким же, если все страницы будут запрошены.