Gatsby на сервере: частые ошибки и решения
Локально Gatsby-сайт собирается и работает без вопросов, а на сервере начинаются сюрпризы: сборка падает по памяти, GraphQL внезапно не находит поля, после деплоя открывается белый экран, а прямой переход по внутренней ссылке даёт 404 вместо страницы. Часть этих ошибок специфична именно для Gatsby — они растут из связки Node.js, webpack, GraphQL-слоя и service worker, которых нет у более простых генераторов статики. Ниже — конкретные причины и рабочие решения для каждой из них, с командами и логами, где их искать.
Содержание
- Сборка падает с JavaScript heap out of memory
- Падает npm install: node-gyp, sharp, python
- GraphQL-ошибки при сборке или пустые данные на сайте
- Белый экран после деплоя: «There was a problem loading this website»
- 404 при прямом переходе на внутренний маршрут
- Диск заполняется: node_modules, .cache и повторные сборки
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Сборка падает с JavaScript heap out of memory
Самая частая жалоба на VPS с 1-2 ГБ ОЗУ. gatsby build прогоняет несколько тяжёлых стадий подряд — GraphQL-слой, рендер React-компонентов в HTML, сборку клиентского бандла через webpack, обработку изображений через sharp — и на пике потребление памяти заметно выше, чем у готового работающего сайта. Процесс падает с ошибкой вида:
<--- Last few GCs --->
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
Первое, что стоит проверить, — сколько памяти реально доступно в момент сборки: free -h. Если свободной памяти сверх лимита Node действительно хватает, поднимите лимит V8 для процесса сборки:
NODE_OPTIONS="--max-old-space-size=4096" npx gatsby build
Это раздвигает потолок памяти движка, но не создаёт память из ниоткуда — если физической ОЗУ на сервере реально не хватает, команда просто упадёт позже с той же ошибкой. В этом случае добавьте swap как временную подушку:
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Swap спасает от падения, но сборка на нём заметно медленнее из-за подкачки на диск — это временная мера, а не постоянное решение для сайта, который растёт. Если страниц уже несколько сотен и сборка регулярно упирается в память, разумнее либо взять VPS с большим ОЗУ, либо вообще перенести сборку в CI (GitHub Actions, GitLab CI) и заливать на сервер только готовую папку public/ — тогда серверу вообще не нужен запас памяти под webpack. Общие принципы подбора ОЗУ под нагрузку разобраны в статье почему растёт потребление памяти Nginx и как его удержать — логика с запасом на пиковые нагрузки применима и здесь.
Падает npm install: node-gyp, sharp, python
Ошибка вылезает ещё до gatsby build, на этапе установки зависимостей, и обычно выглядит так:
gyp ERR! find Python
gyp ERR! configure error
node-gyp rebuild failed
Причина — gatsby-plugin-sharp и gatsby-plugin-image тянут нативный модуль sharp для обработки изображений, а он собирается через node-gyp, которому нужны компилятор и Python. На свежем минимальном Ubuntu/Debian их часто просто нет. Ставим:
sudo apt install -y build-essential python3
Вторая типичная ситуация — sharp ставился на другой ОС (например, вы скопировали node_modules с macOS-ноутбука на Linux-сервер) и на сервере просто не запускается, потому что нативный бинарник собран под другую платформу. Правило простое: node_modules не переносится между разными ОС и архитектурами, ставьте зависимости на той же машине, где будете собирать сайт. Если такое уже произошло — удалите node_modules и переустановите на сервере:
rm -rf node_modules
npm install
Третья причина — несовпадение версии Node.js с той, что ожидает проект. Если в package.json указано поле engines, сверьте его с node -v на сервере. Проще всего держать версию через nvm и не полагаться на системный пакет:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install 20
nvm use 20
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверGraphQL-ошибки при сборке или пустые данные на сайте
Gatsby строит GraphQL-слой поверх всех источников данных ещё до рендера страниц, и любая проблема с источником всплывает именно тут — либо сборка падает, либо страницы собираются, но с пустыми полями. Если данные приходят из headless CMS, первая проверка — доступен ли эндпоинт вообще с сервера:
curl -I https://cms.example.com/graphql
Если сервер не может достучаться до CMS (закрыт исходящий трафик, IP CMS сменился, истёк токен API), сборка либо зависает на таймауте, либо падает с сетевой ошибкой на стадии source-nodes. Проверьте, что переменные окружения из .env.production реально загружены и не содержат опечаток в названии — Gatsby требует префикс GATSBY_ только для переменных, которые нужны в браузере, серверные (токены, URL API) можно называть как угодно, но точность имени критична.
Отдельный случай — ошибка вида There was an error in your GraphQL query: Cannot query field "x" on type "y". Это значит, что схема, которую Gatsby построил на предыдущей сборке, закэширована и не совпадает с тем, что реально приходит сейчас из CMS (в CMS изменили тип контента, добавили или переименовали поле). Первое, что нужно попробовать, — сброс кэша:
npx gatsby clean
npx gatsby build
gatsby clean удаляет .cache/ и public/, заставляя Gatsby пересобрать GraphQL-схему с нуля по актуальным данным. Это медленнее обычной инкрементальной сборки, зато убирает рассинхрон между старой схемой и новым контентом — держите эту команду под рукой на случай странных ошибок после изменений в CMS.
Белый экран после деплоя: «There was a problem loading this website»
Сайт собрался, файлы на сервере на месте, но у части посетителей вместо страницы — белый экран или сообщение об ошибке загрузки. Обычно причина в gatsby-plugin-offline, который регистрирует service worker в браузере пользователя для оффлайн-доступа. Service worker кэширует список файлов сборки (app-data.json и хэшированные чанки) и при следующем визите пытается брать их из кэша. Если между визитами вы задеплоили новую сборку, а старые файлы с прошлыми хэшами уже удалены с сервера, service worker пытается запросить файл, которого больше нет — и получает ошибку вместо страницы.
Диагностика — в DevTools браузера, вкладка Application → Service Workers: видно, зарегистрирован ли worker и какой версии. Быстрое решение для конкретного пользователя — снять регистрацию worker вручную или сделать жёсткое обновление (Ctrl+Shift+R). Системное решение — на стороне деплоя:
- используйте
rsync --deleteпри копированииpublic/, чтобы на сервере никогда не оставалось смеси файлов старой и новой сборки одновременно; - копируйте новую версию в отдельную временную папку и переключайте на неё симлинк одной атомарной операцией, а не перезаписывайте файлы по одному «на живую» под трафиком;
- если сайт обновляется часто и оффлайн-режим не критичен, рассмотрите отключение
gatsby-plugin-offline— он больше подходит для сайтов с редкими обновлениями, где полезен полноценный оффлайн-доступ.
404 при прямом переходе на внутренний маршрут
Если в проекте есть client-only маршруты (клиентская навигация через Reach Router или @reach/router для, например, личного кабинета или динамических разделов вида /app/*), для них не существует отдельного статического HTML-файла — Gatsby не знает заранее все возможные пути. Внутри сайта переход по ссылке работает, потому что срабатывает клиентский роутер без перезагрузки страницы. А вот прямой заход по URL или обновление страницы (F5) на таком маршруте уходит прямиком в Nginx, который честно ищет файл /app/kakoy-to-put/index.html, не находит и отдаёт 404.
Решение — научить Nginx отдавать точку входа клиентского роутера для всего префикса таких маршрутов:
location /app/ {
try_files $uri $uri/ /app/index.html;
}
Так любой путь под /app/ при отсутствии точного файла получит index.html этого раздела, а дальше маршрутизацией уже займётся React в браузере. Если client-only маршрутов несколько и с разными префиксами, добавьте по такому блоку на каждый — общий try_files ... /404.html на весь сайт для этой задачи не подходит, потому что тогда посетитель просто увидит страницу 404 вместо приложения.
Диск заполняется: node_modules, .cache и повторные сборки
Gatsby оставляет за собой заметный след на диске: node_modules — сотни мегабайт с десятками тысяч мелких файлов, .cache/ — внутренний кэш сборки, который тоже может разрастись до гигабайта на большом сайте, и public/ — готовая статика. Если деплой устроен так, что каждая сборка происходит прямо на VPS через git pull && npm install && gatsby build, диск постепенно забивается — особенно если периодически не подчищать старое. Смотрите не только на свободное место, но и на количество inode — node_modules из-за обилия мелких файлов способен исчерпать лимит inode при формально свободном месте на диске:
df -h
df -i
du -sh node_modules .cache public
Если проблема именно в inode при свободном месте — подробный разбор причины и решений в статье не хватает inode при свободном месте на диске. Практические меры для Gatsby: используйте npm ci вместо npm install в скрипте деплоя — она чище работает с package-lock.json и не оставляет мусора от предыдущих версий зависимостей; периодически прогоняйте npx gatsby clean для сброса разросшегося .cache/; и если позволяет процесс, перенесите тяжёлую часть (установку зависимостей и сборку) в CI, оставив на VPS только готовые файлы из public/ — так вообще исчезает необходимость держать node_modules на боевом сервере. Полная схема такого разделения описана в статье про деплой Gatsby-сайта на VPS.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Почему сборка Gatsby падает именно на VPS, хотя локально всё собирается без проблем?
Обычно из-за разницы в объёме ОЗУ — на рабочем ноутбуке часто 16 ГБ и больше, а на VPS-тарифе может быть 1-2 ГБ. Смотрите первый раздел: поднимите NODE_OPTIONS --max-old-space-size, добавьте swap как временную меру и закладывайте более мощный тариф под сборку заранее, если сайт растёт.
После смены CMS-платформы или переименования полей сборка падает с ошибкой GraphQL — это баг Gatsby?
Нет, это устаревший локальный кэш .cache/, который не совпадает с новой схемой данных. Выполните gatsby clean и пересоберите сайт с нуля.
Можно ли просто скопировать node_modules с рабочего компьютера на сервер, чтобы не ждать npm install?
Не стоит, если ОС отличается (например, macOS и Linux) — нативные модули вроде sharp собраны под конкретную платформу и не заработают на другой. Ставьте зависимости на той же машине, где будет проходить сборка.
Как понять, что белый экран у пользователя — это именно проблема service worker, а не сломанная сборка?
Проверьте DevTools → Application → Service Workers на стороне клиента и одновременно откройте сайт в приватном окне браузера без установленного worker. Если в приватном окне всё открывается нормально — дело в закэшированном service worker у конкретного посетителя, а не в самой сборке на сервере.
Нужен ли для Gatsby именно Nginx, или подойдёт другой веб-сервер?
Подойдёт любой сервер, умеющий отдавать статику и настраивать try_files-подобные fallback-правила для клиентских маршрутов. Nginx просто самый распространённый вариант для такой задачи на VPS.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →