← Усі статті

React.lazy і «білий екран» після деплою: як повернути користувача

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

React.lazy і «білий екран» після деплою: як повернути користувача
Зміст

Коротко

Після деплою 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, але страхує живі вкладки в момент викату.