Как оптимизировать с помощью лэйзи лоадинга и код сплитинга
Что проверяют
Понимаете ли вы, что именно тормозит первую загрузку, и умеете ли откладывать ненужное, не ухудшая то, что пользователь видит сразу. Следом обычно спрашивают, как вы измеряли эффект и чем ленивая загрузка может навредить.
Как отвечать
Разведите два понятия. Code splitting делит JavaScript на чанки: каждый динамический import() сборщик (webpack, Vite, Turbopack) выносит в отдельный файл. Lazy loading это стратегия загрузки чего угодно по требованию: чанков, картинок, iframe.
Каркас:
- сплит по маршрутам: первое и самое выгодное деление. В React Router это
lazyу маршрута илиReact.lazy, во Vue ленивые компоненты роутера, в Next.js App Router маршруты делятся автоматически; - тяжёлые компоненты: редактор, графики, карты грузятся через
React.lazyиSuspenseилиnext/dynamic.React.lazyждёт default-экспорт, для именованного нужна обёртка через.then; - картинки и iframe: нативный
loading="lazy". Для блоков ниже первого экрана подходитIntersectionObserver; - не откладывать LCP: главную картинку первого экрана грузят сразу и с
fetchpriority="high", ленивая загрузка ухудшит LCP; - предзагрузка: prefetch чанка при наведении на ссылку или в простое браузера, чтобы переход не ждал сеть;
- измерения:
webpack-bundle-analyzerилиrollup-plugin-visualizer, вкладка Coverage в DevTools, Lighthouse, а в проде реальные LCP и INP.
Отдельно продумайте ошибки: после деплоя старые чанки с прежним хэшем исчезают, и открытая вкладка получает ошибку загрузки чанка (ChunkLoadError в webpack). Нужен Error Boundary с предложением перезагрузить страницу.
Где спотыкаются
Режут слишком мелко. Вместо одного файла получается водопад из десятков запросов, и страница открывается медленнее.
Ставят loading="lazy" на всё подряд, включая главную картинку, и LCP проседает.
Забывают про fallback: заглушка другого размера, чем компонент, даёт скачок вёрстки и портит CLS.