2026-09-22

Баги, которые живут только в production

Я делаю этот сайт открыто. Один монорепозиторий, Fastify рендерит React, рядом небольшое API на Hono, а всё это живёт в k3s на одной ARM-машине.

Локально проект тоже работает в Docker с примонтированным исходным кодом, поэтому в контейнерах крутится ровно то, что я только что написал.

Но на этой неделе два бага существовали только в production-сборке. Как раз хороший повод про них рассказать.

Padding, который исчезал

У каждой страницы свои отступы:

padding: 96px 24px 120px

А общий .container задавал:

padding: 0 24px

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

В development последним оказывался стиль страницы, и всё выглядело нормально. В production порядок менялся, побеждал .container, верхний отступ становился нулевым, а текст уезжал под фиксированную шапку.

Починка — буквально одно слово: padding-inline.

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

Переводы, которых не было

В production SSR-плагин импортирует серверный бандл ещё при регистрации в Fastify — до того, как сервер начал слушать порт.

А мой entry запускал i18next.init() прямо во время импорта. Локали i18next загружал по HTTP с этого же сервера, который в этот момент ещё не был доступен.

Запрос падал, ошибка оставалась в состоянии i18next, и дальше SSR отдавал вместо переводов ключи вроде stack_lead.

В development этого не происходило: Vite загружал entry уже при первом запросе, когда сервер был запущен.

Я перенёс инициализацию i18next на первый рендер. А initImmediate: false закрыл ещё одну гонку: теперь init() не заканчивается раньше, чем локали действительно оказываются в store.

Что у них общего

Оба бага про одно и то же: development и production — не совсем одна и та же программа.

Меняется порядок файлов, момент загрузки модулей и последовательность старта. Тесты этого не поймали. Я тоже не поймал, пока не собрал настоящий production-образ и не открыл его как обычный пользователь.

Поэтому production-стек у меня поднимается одной командой. И прежде чем считать что-то рабочим, я стараюсь хотя бы один раз посмотреть на него именно там.

все заметки