Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

どこで発生したエラーが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

clomie
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away