← Все статьи

React.lazy и «белый экран» после деплоя: как вернуть пользователя

Старый HTML в вкладке, новый бандл на CDN — chunk не найден. Глобальный listener и cache-bust за ~15 строк.

Содержание

Коротко

После деплоя SPA пользователь с открытой вкладкой может увидеть пустой экран: React.lazy() тянет chunk со старым хешем, а на CDN уже новый бандл. На Dev.to — короткий глобальный обработчик, который перезагружает страницу с параметром сброса кеша.

Что произошло

Классический сценарий: в памяти браузера остаётся старый index.html, при переходе по маршруту динамический импорт бьётся в 404 или сетевую ошибку. В консоли — варианты вроде Failed to fetch dynamically imported module или Loading chunk N failed (формулировки различаются в Chrome, Safari и старых сборках Webpack).

Обычный пользователь не знает про жёсткое обновление — он просто уходит.

Почему это важно

Code splitting экономит первый байт, но связывает версию оболочки и версию чанков. Любой деплой без стратегии кеша HTML создаёт окно, где часть сессий «застревает» между релизами.

Симптом Причина Без фикса
Белый экран после навигации Chunk удалён/переименован Потеря конверсии
Ошибка только у части пользователей Старые вкладки Сложно воспроизвести в support
Hard reload помогает Новый index.html с актуальными хешами Не масштабируется

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

На практике

  1. Повесьте window.addEventListener('error', …) с набором regex под разные тексты ошибок (chunk, dynamic import, CSS chunk, Safari «Importing a module script failed»).
  2. При совпадении — location.replace() с ?_r=<timestamp>, чтобы подтянуть свежий HTML без лишней записи в history (кнопка «Назад» работает).
  3. Добавьте флаг «уже перезагружали», чтобы не уйти в цикл при реальном обрыве сети.
  4. При необходимости дублируйте логику на unhandledrejection, если lazy-импорт падает внутри promise.
  5. Проверка: задеплойте новый билд, оставьте старую вкладку, перейдите на lazy-маршрут — страница должна сама восстановиться.

Долгосрочно дополняйте политикой кеша: короткий TTL или no-cache для index.html, длинный — для hashed assets.

Итог

React.lazy + частые деплои без recovery — предсказуемый инцидент. Глобальный listener не заменяет правильный кеш HTML, но страхует живые вкладки в момент выката.