JavaScript
Vue.js
nuxt.js

Vue.config.errorHandlerはどこで発生したエラーをキャプチャできるのか

どこで発生したエラーがVue.config.errorHandlerでキャプチャできて、どれができないのか、できないやつはどうすればいいのかについて。


🎉 Vue.js v2.6 Macross Released!

2019/03/03追記: Vue.jsの2.6.0で、キャプチャ可能なエラーの発生シチュエーションが増えたためアップデートしました。


忙しい人向け

これで一通りキャプチャできるはず。


main.js

Vue.config.errorHandler = (err, vm, info) => {

console.log(`Captured in Vue.config.errorHandler: ${info}`, err);
};
window.addEventListener("error", event => {
console.log("Captured in error EventListener", event.error);
});
window.addEventListener("unhandledrejection", event => {
console.log("Captured in unhandledrejection EventListener", event.reason);
});


検証用URL

https://clomie.github.io/vue-error-capturing/

console表示させた状態でボタンぽちぽちしてください。

ソースコード: https://github.com/clomie/vue-error-capturing


対象バージョン

現時点での最新版。

Vue.js: v2.6.8

Nuxt.js: v2.0.0


まとめ

Vue.config.errorHandlerでキャプチャできるエラーは下記で発生したもののみ。


  • 描画関数、またはテンプレート


    • フィルタ関数

    • 算出プロパティ関数



  • ウォッチャ

  • 各種インスタンスライフサイクルフック (v2.2.0以降)


  • data関数 (v2.2.5以降)

  • 各種ディレクティブフック (v2.3.0以降)


  • nextTick関数のコールバック (v2.3.0以降)

  • カスタムイベントにバインドしたハンドラ関数 (v2.4.0以降)

  • DOMネイティブイベントにバインドしたハンドラ関数(v2.6.0以降)

  • async修飾子付きの各種インスタンスライフサイクルフック(v2.6.0以降)

  • async修飾子付きのイベントハンドラ関数(v2.6.0以降)

  • 上記の関数から直接呼び出された関数

Nuxt.jsの場合、上記に加えて

下記で発生したエラーはVue.config.errorHandlerではキャプチャできない。それぞれwindowオブジェクトにerror, unhandledrejectionのイベントハンドラを登録することでグローバルにキャプチャできる。


  • setTimeoutやsetIntervalなどの非同期コールバック関数 (error)

  • Promise経由で呼び出される処理 (unhandledrejection)

  • イベントハンドラ、ライフサイクルフック以外のasync修飾子付きの関数 (unhandledrejection)


Vue.config.errorHandler

Vue.js > API > グローバル設定 > errorHandler

実際にはsrc/core/util/error.jsで処理されています。

handleError、およびinvokeWithErrorHandling関数がexportされていて、使用箇所を追ってみると、それぞれどこで発生したエラーをキャプチャしているのかがわかります。

Search · handleError repo:vuejs/vue path:/src/core

https://github.com/search?q=handleError+repo%3Avuejs%2Fvue+path%3A%2Fsrc%2Fcore&type=Code

Search · invokeWithErrorHandling repo:vuejs/vue path:/src/core

https://github.com/search?q=invokeWithErrorHandling+repo%3Avuejs%2Fvue+path%3A%2Fsrc%2Fcore&type=Code

invokeWithErrorHandlingが使われている箇所は、async関数などのPromiseを返す関数のエラーに対応しています。

注意点として、Vue.config.errorHandlerでキャプチャ可能なエラーは、たとえ設定していなかったとしても、後述のerror、またはunhandledrejectionイベントには伝播しません。

これは、Vue.js内のエラー処理で、ブラウザ上で動作している場合、console.errorに直接エラーを出力しているためです。

https://github.com/vuejs/vue/blob/v2.6.8/src/core/util/error.js#L78


Vue.config.warnHandler

Vue.js > API > グローバル設定 > warnHandler

developmentモードでビルドしている際に、コンソールに出力される[Vue warn]:で始まるメッセージについては、このハンドラで受け取れます。ただし、productionモードでビルドするとwarnメッセージは出力されないため、このハンドラも無視されます。

実際はsrc/core/util/debug.jsで処理されており、warn関数としてexportされています。使用箇所は下記のリンクから探せますが、こっちはerrorHandlerよりは多いです。

Search · warn repo:vuejs/vue path:/src/core

https://github.com/search?q=warn+repo%3Avuejs%2Fvue+path%3A%2Fsrc%2Fcore&type=Code

よく遭遇するwarnメッセージとしては下記のようなものが挙げられるかと思います。これらはerrorHandlerではキャプチャできません。


  • template内で使っているコンポーネントのcomponents登録忘れ、コンポーネント名ミス

  • template内のプロパティ名ミス

  • propsのバリデーションエラー


error イベント

GlobalEventHandlers.onerror - Web APIs | MDN

https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror

JavaScriptコード内で発生したキャッチされていないエラーをキャプチャできます。

前述の通り、Vue.config.errorHandlerでキャプチャ可能なエラーはerrorイベントには伝播しません。

コンポーネントに定義したメソッドであっても、setTimeoutやsetIntervalといったネイティブな非同期コールバックからの呼び出し等の場合、Vue.jsのコアライブラリが間に挟まる余地が無いため、errorHandlerではキャプチャできません。


unhandledrejection イベント

unhandledrejection - Event reference | MDN

https://developer.mozilla.org/en-US/docs/Web/Events/unhandledrejection

Promiseの処理でcatchされていないRejectをキャプチャできます。ただし、Vue.config.errorHandlerでキャプチャ可能なエラーはキャプチャできません。また、対応しているブラウザが限られている点に注意が必要です。

Promise内で発生したエラーについても同様にVue.jsのコアライブラリが間に挟まる余地がないため、errorHandlerではキャプチャできません。


vm.errorCaptured フック

Vue.js > API > オプション / ライフサイクルフック > errorCaptured

errorHandlerと同じ用途で、コンポーネントに定義するライフサイクルフックとしてerrorCapturedがあります。

子孫コンポーネントで発生したエラーに対して反応する点に注意が必要です。設定したコンポーネント自体で発生したエラーには反応しません。


その他の参考リンク

かずぽんブログ • Vue.js 2017年まとめ & 今後

Vue.jsでフロント側のエラー検知を共通化する - エス・エム・エスキャリア開発者ブログ

Vue.jsのerrorHandlerがいまいちつかめない - Qiita

ユーザのブラウザで起きた JavaScript のエラーを収集する - Qiita