Помилка в рендері, хуку життєвого циклу, спостерігачі чи обробнику події одного компонента без обробки може зламати весь застосунок - користувач побачить «завмерлий» чи порожній екран.
Глобальний обробник - останній рубіж, місце для відправки в моніторинг:
const app = createApp(App);
app.config.errorHandler = (error, instance, info) => {
// info - де сталася помилка: 'render function', 'mounted hook', 'watcher callback'...
Sentry.captureException(error, { extra: { info } });
};
Він ловить помилки з рендеру, хуків, спостерігачів, обробників подій шаблону, setup, provide/inject - тобто з коду, який викликає Vue. Помилки з setTimeout, промісів без await і сторонніх колбеків він не бачить - для них window.onerror і unhandledrejection.
onErrorCaptured - перехоплення помилок нащадків у компоненті-предку. Основа для «межі помилок» (error boundary), як у React:
<!-- ErrorBoundary.vue -->
<script setup>
import { ref, onErrorCaptured } from 'vue';
const error = ref(null);
onErrorCaptured((err, instance, info) => {
error.value = err;
report(err, info);
return false; // не передавати помилку вище
});
</script>
<template>
<div v-if="error" class="widget-error">
Блок не завантажився. <button @click="error = null">Спробувати ще</button>
</div>
<slot v-else />
</template>
<ErrorBoundary>
<RevenueChart />
</ErrorBoundary>
Зламаний графік показує запасний вигляд, решта дашборду працює.
Правила поширення:
- помилка йде вгору ланцюжком батьків, викликаючи кожен
onErrorCaptured; return falseзупиняє поширення - вище й доapp.config.errorHandlerвона не дійде;- якщо сам
onErrorCapturedкидає помилку, вона теж іде до глобального обробника.
Пастки:
- рендер запасного вигляду не повинен знову рендерити зламаний компонент - інакше нескінченний цикл помилок. Тому
v-if/v-else, а не показ поверх; - асинхронні помилки в
setupпісляawaitчи в звичайних промісах можуть не дійти доonErrorCaptured- async-код варто обробляти явно (try/catch); app.config.warnHandler- окремо для попереджень (лише в режимі розробки).