こんばんは。ニトリのホテルスタイル枕が最高すぎて会社に遅刻しそうになるmorifujiです、
VuejsOsaka#2で発表した内容ですが、一部はしょったり早口で説明した部分が多かったので、ここに細かく書いていこうと思います。
検証に使用したコードはこちら デモはこちら スライドはこちら
背景
弊社の場合、新規PJの開発中などはステージング環境を常にクライアントにOPENにして都度都度フィードバックをもらうことにしています。その中での話。
クライアント「なんかトップページでローディングが止まんないよ」
僕「むむ。コンソールのログ見せてもらえませんか?」
クライアント「。。。(ナニイッテンダコイツ)」(ここでレスが帰ってこなくなる)
こんな感じのことがたまーにあります。このやりとりって結構大変なんですよねクライアントによってITリテラシーがバラバラなので、、、しかもこの後にローカルで環境を再現してエラーの内容を把握してってなると、結構時間が無駄になってる気がします。
また、改めて考えるとサーバーのエラーは当然のようにトラッキングして集約するのに、フロントのエラーがほったらかしなのはどうなのとも思いました。そこで今回はVuejsで構築したSPAの上で発生したエラーをトラッキングするための仕組みを考えてみました。
エラーをトラッキングするとなると、考えることは以下の2点になるかなと思います。
- どうやって検知する?
- どこにエラーの情報を集約する?
どちらも試してみたので、順を追って書いていきます、
どうやって検知する?
ざっくり3種類方法があるようなのでそれぞれ調べてみました。
- window.onerror
- errorCaptured
- Vue.config.errorHandler
window.onerror
Vue.jsはJavascriptの上で動作します。なので、当然Javascript自体のエラー検知の機構を使うことができます。それが window.onerror
です。
[https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror:embed:cite]
使い方はこのような感じ。
window.onerror = function(message, source, line, column, error) {
console.log('catched by `window.onerror_`', message)
<button onclick="HOGEHOGEHOGE">PureなJavascriptでエラー</button>
この状態でbuttonを押すとonerrorがキャッチします。onerrorの引数はこんな感じ。
引数 | 説明 | サンプルでの引数 |
---|---|---|
message | エラーメッセージ(string) | “Uncaught ReferenceError: HOGEHOGEHOGE is not defined” |
source | エラーが発生したJavascriptのファイル名(string) | “http://localhost:8080/index” |
line | エラーが発生したJavascriptの行番号 | 28 |
column | エラーが発生したJavascriptの列番号 | 34 |
error | 発生したエラー | エラーオブジェクト(下記の画像参照) |
[f:id:Kouchannel55:20190808005043p:plain]
errorCaptured
こちらはVuejs独自のエラー検知の機構で、Vuejsの各Component独自に定義することができます。
[https://vuejs.org/v2/api/#errorCaptured:embed:cite]
SFCでの使い方はこのような感じ。
<template>
<div class="hello">Hello World!</div>
</template>
<script>
export default {
name: 'HelloWorld',
errorCaptured(err, vm, info) {
console.log('catched by `CHILD errorCaptured`', err.toString())
},
}
</script>
dataとかpropsとかと並列に定義できます。
親子関係の各Componentに定義されていてなおかつ子Component内でエラーが発生した場合は、以下の図のように親のComponentの errorCaptured
を順番に発火させてエラーが伝播していきます。エラーが発生した孫Componentの errorCaptured
は発火しないのがポイントですね、
[f:id:Kouchannel55:20190808003413p:plain]
このエラー伝播は errorCaptured
の返り値を false
にすることで途中で止めることができます。上記の例では子Componentから親Componentへのエラー伝播を止めることができます。
[f:id:Kouchannel55:20190808003914p:plain]
Vue.config.errorHandler
こちらもVuejs独自のエラー検知の機構で、引数も errorCaptured
と同一ですが、グローバルに設定する点が全く異なります
[https://vuejs.org/v2/api/#errorHandler:embed:cite]
使い方は以下のような感じ。
Vue.config.errorHandler = function(err, vm, info) {
console.log('catched by `Vue.config.errorHandler`', err.toString())
}
errorCaptured
のエラー伝播がルートComponentまで到達した場合は、 Vue.config.errorHandler
が発火します。
[f:id:Kouchannel55:20190808005754p:plain]
ということは途中でエラーの伝播が止まった場合は Vue.config.errorHandler
は発火しません
[f:id:Kouchannel55:20190808010005p:plain]
まとめ
3種類紹介しましたが、これを踏まえて僕なりのエラー検知機構の使い分け場面を考えてみました。
- window.onerror
- 画面内でVuejs以外のPureなJavascriptが動いていて、その部分に関してのエラーを検知したい場合に有効
- errorCaptured
- Vuejsの階層構造の中で、Componentによってエラー検知処理を分けたい場合に有効
- 例えば、画面によってエラーの検知処理を変えたい場合や、特定のComponent内のエラーは握りつぶしたい場合とか?
- Vue.config.errorHandler
- Vuejs内のエラーを一元的に処理したい場合に有効
- 例えば、全ての画面でのどんなエラーでも収集したい場合
他にもこう言う用途があるよ!みたいなのがあれば教えてくださいー
残りの 2. どこにエラーの情報を集約する? と言う話は、別記事にしようと思いますのでもう少しだけお待ちくださいー。
ではでは