Для чего нужен defineAsyncComponent во Vue и в каких кейсах его использовать
Что проверяют
Понимаете ли вы связь между асинхронным компонентом, динамическим import() и разбиением бандла, и можете ли назвать место, где это даёт реальный выигрыш. Следом обычно спрашивают, как обработать ошибку загрузки и нужно ли оборачивать в defineAsyncComponent компоненты маршрутов.
Как отвечать
defineAsyncComponent принимает функцию-загрузчик, которая возвращает промис с компонентом. Обычно это () => import('./Chart.vue'): Vite или webpack выносит компонент в отдельный чанк, и браузер скачивает его только при первом рендере. Результат кешируется, повторной загрузки не будет.
Вторая форма принимает объект с настройками:
loader: та же функция загрузки;loadingComponentиdelay: заглушка на время загрузки. Показывается не сразу, а через 200 мс по умолчанию, чтобы не мигать на быстрой сети;errorComponentиtimeout: что показать при ошибке и сколько ждать. По умолчанию ожидание не ограничено;onError(error, retry, fail, attempts): ручные повторы, например до трёх попыток при сетевой ошибке.
С Vue 3.5 есть опция hydrate для SSR: hydrateOnVisible(), hydrateOnIdle(), hydrateOnInteraction() откладывают гидратацию тяжёлого блока до нужного момента.
Где это окупается: модальные окна и выезжающие панели, графики, редакторы кода или текста, неактивные вкладки, разделы только для админов. Всё тяжёлое, что появляется не сразу или не у всех.
Где спотыкаются
Оборачивают в defineAsyncComponent компоненты маршрутов. Документация Vue Router прямо говорит, что для маршрута достаточно component: () => import('./views/Page.vue'), роутер сам загрузит его лениво.
Делают асинхронным компонент, который виден сразу при открытии страницы. Выигрыша нет, зато появляется лишний запрос и задержка перед показом.
Забывают про Suspense. Асинхронный компонент по умолчанию suspensible, и если выше по дереву есть <Suspense>, его собственные loadingComponent и errorComponent игнорируются, состоянием управляет родитель. Потом удивляются, куда пропал спиннер.