Vue3 錯誤處理與除錯:Vue.config.errorHandler 完全指南
簡介
在開發大型 Vue3 應用時,錯誤的即時捕捉與統一處理 是提升使用者體驗與維護效率的關鍵。若不加以控制,任何未處理的例外都會直接導致整個組件樹崩潰,使用者會看到空白畫面或瀏覽器的錯誤訊息,這不僅影響產品形象,也讓除錯變得更困難。
Vue3 為了提供全局的錯誤攔截機制,保留了 Vue.config.errorHandler(在 Vue 2 時同樣存在)以及在組件內部的 errorCaptured 鉤子。透過 全局錯誤處理器,開發者可以統一記錄、上報錯誤,甚至在錯誤發生時顯示友善的 UI。本文將深入說明 Vue.config.errorHandler 的使用方式、常見陷阱與最佳實踐,並提供多個實作範例,讓你能在實務專案中立即上手。
核心概念
1. 為什麼需要全局錯誤處理器?
- 統一入口:所有在渲染過程、生命週期鉤子、事件處理器、watcher 中拋出的錯誤,都會被 Vue 捕捉並傳遞給
errorHandler。 - 集中上報:只需要在一個地方加入上報程式碼(例如 Sentry、LogRocket),即可把所有錯誤傳到後端。
- 使用者體驗:可以在錯誤發生時顯示「系統暫時無法使用」的提示頁面,避免白屏。
2. Vue.config.errorHandler 的簽名
Vue.config.errorHandler = (err, vm, info) => {
// err : Error 物件 (包含 stack、message 等)
// vm : 發生錯誤的 Vue 元件實例 (null 表示在根實例之外)
// info : 錯誤發生的上下文字串,例如 "render function"、"watcher"
}
err:實際的例外物件,可直接console.error(err)或傳給上報服務。vm:錯誤所在的組件實例,透過vm.$options.name或vm.$router可取得更多資訊。info:Vue 提供的錯誤類型說明,對於定位問題很有幫助。
注意:在 Vue3 中,我們仍然使用
app.config.errorHandler(app為createApp回傳的實例),而非全域的Vue.config。本文的範例會同時示範兩種寫法,以兼容 Vue2 與 Vue3。
3. 設定方式
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// Vue3 推薦寫法
app.config.errorHandler = (err, vm, info) => {
// 這裡寫入錯誤處理邏輯
console.error('[全局錯誤]', err, info, vm)
}
// 若你仍在使用 Vue2,寫法如下(僅供參考)
// Vue.config.errorHandler = (err, vm, info) => { ... }
app.mount('#app')
4. 與 errorCaptured 的關係
errorCaptured是組件層級的錯誤捕獲鉤子,只會攔截子組件拋出的錯誤,且可自行決定是否向上冒泡(回傳false會阻止冒泡)。errorHandler則是全局的最後一道防線,所有未被errorCaptured捕獲的錯誤最終會到達此處。
程式碼範例
以下示範 5 個實用範例,涵蓋從最簡單的全局錯誤紀錄到結合第三方上報服務、條件過濾與自訂錯誤 UI。
範例 1:最基礎的全局錯誤日誌
// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.config.errorHandler = (err, vm, info) => {
// 直接印出錯誤資訊,適合開發階段快速除錯
console.error('[Vue Error]', err)
console.warn('發生位置:', info)
if (vm) {
console.warn('錯誤來源元件:', vm.$options.name || vm.$.type.name)
}
}
app.mount('#app')
說明:此範例僅在開發環境使用,讓開發者能即時在 console 中看到完整錯誤堆疊。
範例 2:結合 Sentry 的全局上報
// main.js
import { createApp } from 'vue'
import * as Sentry from '@sentry/vue'
import { Integrations } from '@sentry/tracing'
import App from './App.vue'
const app = createApp(App)
// 初始化 Sentry
Sentry.init({
app,
dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0',
integrations: [new Integrations.BrowserTracing()],
tracesSampleRate: 1.0,
})
// 全局錯誤處理器,同時把錯誤送給 Sentry
app.config.errorHandler = (err, vm, info) => {
// Sentry 已自動捕獲 Vue 錯誤,這裡僅做自訂資訊補足
Sentry.captureException(err, {
extra: {
component: vm?.$options?.name,
info,
},
})
// 同時保留 console 輸出,方便本機除錯
console.error('[Sentry]', err)
}
app.mount('#app')
說明:Sentry 內部已註冊自己的錯誤捕獲器,
errorHandler只負責補充自訂欄位(如元件名稱)。
範例 3:條件過濾 – 只上報 production 環境
// utils/errorHandler.js
export function installGlobalErrorHandler(app) {
const isProd = import.meta.env.PROD
app.config.errorHandler = (err, vm, info) => {
// 1. 本機開發階段只打印
if (!isProd) {
console.error('[開發模式]', err)
return
}
// 2. Production:上傳至自家後端 API
fetch('/api/report-error', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: err.message,
stack: err.stack,
component: vm?.$options?.name,
info,
url: location.href,
userAgent: navigator.userAgent,
timestamp: Date.now(),
}),
}).catch(() => {
// 若上報失敗,仍保留 console
console.error('Error reporting failed', err)
})
}
}
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import { installGlobalErrorHandler } from '@/utils/errorHandler'
const app = createApp(App)
installGlobalErrorHandler(app)
app.mount('#app')
說明:在開發階段不會向伺服器發送過多訊息,避免噪音;上線後才正式上報。
範例 4:自訂錯誤 UI – 全局錯誤佈景
<!-- ErrorOverlay.vue -->
<template>
<div v-if="visible" class="error-overlay">
<h2>系統發生錯誤</h2>
<p>我們已自動記錄此錯誤,請稍後再試。</p>
<button @click="reload">重新整理</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const visible = ref(false)
export function showErrorOverlay() {
visible.value = true
}
function reload() {
location.reload()
}
</script>
<style scoped>
.error-overlay {
position: fixed;
inset: 0;
background: rgba(255, 0, 0, 0.1);
color: #c00;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9999;
}
</style>
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import ErrorOverlay, { showErrorOverlay } from '@/components/ErrorOverlay.vue'
const app = createApp(App)
// 全局錯誤處理器:顯示錯誤覆蓋層
app.config.errorHandler = (err, vm, info) => {
console.error('[全局錯誤]', err)
// 只在 production 顯示 UI
if (import.meta.env.PROD) {
showErrorOverlay()
}
}
// 把 ErrorOverlay 注入根組件
app.component('ErrorOverlay', ErrorOverlay)
app.mount('#app')
說明:當錯誤發生時,
showErrorOverlay()會讓覆蓋層顯示,使用者不會直接看到白屏。
範例 5:結合 errorCaptured 進行局部過濾
// MyButton.vue
<template>
<button @click="triggerError">點我會錯誤</button>
</template>
<script>
export default {
name: 'MyButton',
methods: {
triggerError() {
// 故意拋出錯誤測試
throw new Error('按鈕內部錯誤')
},
},
// 只捕獲此組件的錯誤,避免向全局傳遞
errorCaptured(err, vm, info) {
console.warn('[MyButton 捕獲]', err.message)
// 回傳 false,阻止冒泡到全局 errorHandler
return false
},
}
</script>
說明:
errorCaptured讓開發者在特定組件中自行處理錯誤,若回傳false,則不會再進入全局errorHandler,適合不希望上報的預期錯誤(如使用者輸入錯誤導致的驗證失敗)。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 最佳實踐 |
|---|---|---|
忘記在 Vue3 使用 app.config.errorHandler |
仍寫 Vue.config.errorHandler 會在 Vue3 中失效。 |
在 createApp 後立即設定 app.config.errorHandler。 |
在 errorHandler 內部再次拋出錯誤 |
若處理程式本身出錯,會形成無限迴圈或失去錯誤資訊。 | 使用 try…catch 包裹上報程式碼,確保不會再拋出未捕獲例外。 |
| 上報過於頻繁 | 大量錯誤同時上報會造成伺服器壅塞。 | 加入節流或批次上報(如每 5 筆一次或使用 debounce)。 |
在 errorHandler 中直接操作 UI |
若同時觸發多個錯誤,可能導致 UI 狀態不一致。 | 僅負責紀錄/上報,UI 顯示交給單獨的狀態管理(如 Pinia)或全局事件。 |
忽略 info 參數 |
info 能快速定位錯誤發生於 render、watcher…,不使用會失去關鍵線索。 |
在日誌或上報時加入 info,方便日後排查。 |
最佳實踐總結
- 在主入口(
main.js)即完成全局錯誤處理器的安裝,確保所有組件在掛載前已被攔截。 - 區分開發與正式環境:開發時直接
console.error,正式環境才上報。 - 結合第三方服務(Sentry、LogRocket)或自建 API,統一管理錯誤。
- 保留
errorCaptured用於局部過濾,避免非預期錯誤被過度上報。 - 將錯誤資訊傳遞給狀態管理(Pinia、Vuex)或全局事件,讓 UI 只負責呈現。
實際應用場景
1. 電商平台的結帳流程
在結帳頁面,任何渲染錯誤都可能導致使用者無法完成付款。透過 errorHandler 捕捉錯誤後,立即上報至監控系統,同時顯示友善的錯誤覆蓋層(範例 4),讓使用者知道系統暫時不可用,並提供「重新整理」或「聯絡客服」的選項。
2. SaaS 後台管理系統
管理員操作多個互相嵌套的圖表與表格,個別組件的錯誤不應影響整體儀表板。此時在每個圖表組件內使用 errorCaptured(範例 5)自行捕獲,僅在必要時(如資料解析錯誤)向全局上報,避免噪音過多。
3. 行動端 PWA
PWA 需要在離線或網路不穩時仍能提供基本功能。全局錯誤處理器可以偵測網路相關的例外,自動切換到離線模式或顯示「網路不穩」的提示,提升使用者留存率。
總結
Vue.config.errorHandler(Vue3 中的 app.config.errorHandler)是 Vue 全局錯誤攔截的核心,配合 errorCaptured、第三方上報服務與自訂 UI,能夠讓開發者在 開發、測試與上線 三個階段都保持良好的錯誤可視化與可控性。
- 設定位置:在
createApp後立即設定,確保所有組件在掛載前已被攔截。 - 開發 vs Production:開發階段直接
console.error,上線後才上報並顯示友善 UI。 - 避免過度上報:加入環境檢查、節流與錯誤分類。
- 局部過濾:使用
errorCaptured防止不必要的全局上報。 - 實務應用:電商結帳、SaaS 後台、PWA 離線體驗等,都能從全局錯誤處理中受益。
將這些概念與範例內化後,你的 Vue3 專案將不再因為未捕獲的例外而「白屏」,而是以 可觀測、可維護、可回復 的方式持續提供穩定服務。祝開發順利,錯誤遠離!