Add centralized error handler for sync Vue app

This commit is contained in:
Eli Ribble 2026-05-08 23:33:49 +00:00
parent da90401b2d
commit 01f35b603e
No known key found for this signature in database
3 changed files with 83 additions and 1 deletions

View file

@ -1,14 +1,50 @@
<style>
.global-error-toast {
position: fixed;
top: 20px;
right: 20px;
background: #c00;
color: white;
padding: 16px 20px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
z-index: 9999;
max-width: 400px;
animation: slideIn 0.3s ease;
}
@keyframes slideIn {
from {
transform: translateX(400px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
</style>
<template>
<router-view />
<div id="app">
<div v-if="error" class="global-error-toast">
{{ error.message }}
<button @click="errorClear">x</button>
</div>
<router-view />
</div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
import { apiClient } from "@/client";
import router from "@/route/config";
import { useErrorHandler } from "@/composable/error-handler";
import { SSEManager, type SSEMessageResource } from "@/SSEManager";
const { error, errorClear } = useErrorHandler();
onMounted(() => {
SSEManager.connect("/api/events");
SSEManager.subscribe((msg: SSEMessageResource) => {

View file

@ -0,0 +1,29 @@
import { ref } from "vue";
interface ErrorState {
hasError: boolean;
message: string;
timestamp: Date;
}
const globalError = ref<ErrorState | null>(null);
export function useErrorHandler() {
const setError = (error: Error) => {
globalError.value = {
hasError: true,
message: error.message,
timestamp: new Date(),
};
};
const errorClear = () => {
globalError.value = null;
};
return {
error: globalError,
setError,
errorClear,
};
}

View file

@ -4,6 +4,7 @@ import App from "@/AppSync.vue";
import * as config from "@/config";
import router from "@/route/config";
import * as sentry from "@/sentry";
import { useErrorHandler } from "@/composable/error-handler";
import "maplibre-gl/dist/maplibre-gl.css";
@ -18,8 +19,24 @@ import "@/gen/custom-icons.scss";
import * as bootstrap from "bootstrap";
window.bootstrap = bootstrap;
const { setError } = useErrorHandler();
const pinia = createPinia();
const app = createApp(App);
app.config.errorHandler = (err, instance, info) => {
// err: the error object
// instance: the component instance where error occurred
// info: Vue-specific error info, e.g., lifecycle hook
console.error("Global error:", err);
console.error("Error info:", info);
console.error("Error instance:", instance);
// You could dispatch to a store, send to error tracking service, etc.
// For example, trigger a global error state
setError(err);
};
app.use(pinia);
app.use(router);
sentry.Init(app, pinia).then(() => {