JAVASCRIPT
Global Error Handling and Component Error Boundaries in Vue 3
Implement robust error handling in Vue 3 applications using `app.config.errorHandler` for global catches and `errorCaptured` lifecycle hook for component-specific error boundaries.
// main.js
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
// 1. Global Error Handler
app.config.errorHandler = (err, vm, info) => {
console.error('Global Error Handler Caught:', err, vm, info);
// Report to an error tracking service (e.g., Sentry, Bugsnag)
};
// Global warning handler (optional, for non-critical issues)
app.config.warnHandler = (msg, vm, trace) => {
// console.warn('Global Warning Handler Caught:', msg, vm, trace);
};
app.mount('#app');
// components/ErrorBoundary.vue (Example of a component error boundary)
<template>
<div v-if="hasError" class="error-boundary">
<h2>Something went wrong in this component!</h2>
<p>We're sorry for the inconvenience. Please try refreshing the page or contact support.</p>
<details v-if="error">
<summary>Error Details</summary>
<pre>{{ error }}</pre>
<pre>{{ errorInfo }}</pre>
</details>
</div>
<slot v-else></slot>
</template>
<script setup>
import { ref, onErrorCaptured } from 'vue';
const hasError = ref(false);
const error = ref(null);
const errorInfo = ref(null);
onErrorCaptured((err, vm, info) => {
hasError.value = true;
error.value = err;
errorInfo.value = info;
console.error('Component Error Boundary Caught:', err, vm, info);
// Return `false` to stop the error from propagating further up the component tree.
// If you return `true` or nothing, it continues to the global handler.
return false;
});
</script>
<style scoped>
.error-boundary {
border: 2px solid red;
padding: 20px;
margin: 20px 0;
background-color: #ffebeb;
color: #cc0000;
border-radius: 8px;
}
</style>
// components/BuggyComponent.vue (A component designed to throw an error)
<template>
<div class="buggy-component">
<p>This component is about to throw an error.</p>
<button @click="throwError">Click to trigger error</button>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
const throwError = () => {
throw new Error('This is an intentional error from BuggyComponent!');
};
// Example of an error during a lifecycle hook
// onMounted(() => {
// throw new Error('Error during BuggyComponent mounted hook!');
// });
</script>
<style scoped>
.buggy-component {
border: 1px dashed blue;
padding: 15px;
margin: 10px 0;
}
</style>
// App.vue (Usage of ErrorBoundary)
<template>
<h1>My Vue 3 App</h1>
<p>Content above the error boundary.</p>
<ErrorBoundary>
<BuggyComponent />
<p>This text is also within the ErrorBoundary slot.</p>
</ErrorBoundary>
<p>Content below the error boundary.</p>
<button @click="throwGlobalError">Throw Global Error</button>
</template>
<script setup>
import ErrorBoundary from './components/ErrorBoundary.vue';
import BuggyComponent from './components/BuggyComponent.vue';
const throwGlobalError = () => {
throw new Error('This error is thrown outside any ErrorBoundary!');
};
</script>
How it works: This snippet demonstrates two crucial aspects of error handling in Vue 3: a global error handler and component-level error boundaries. The `app.config.errorHandler` in `main.js` catches all uncaught errors bubbling up from components, providing a centralized point for logging or reporting. The `ErrorBoundary.vue` component utilizes the `onErrorCaptured` lifecycle hook, acting as a "catch-all" for errors originating from its child components (via slots). This allows isolating errors to specific parts of the UI, preventing the entire application from crashing and providing a graceful fallback UI.