Edited at

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


概要

Vue.jsでエラーハンドリングをどうしようか悩んでたときにerrorHandlerなるものがあることを知ったけれど、想定していた挙動と違って利用するのをやめた話。

参考にさせてもらった記事は以下です。感謝!

Vue.jsでフロント側のエラー検知を共通化する

http://sms-c-engineer.hatenablog.com/entry/2018/04/24/142445

GitHubに利用したプロジェクトをUPしています。実際に試してみたい方どうぞ^^

https://github.com/kai-kou/vue-js-typescript-error-handling


準備

ここではDockerを利用して環境構築していますが、ローカルで構築してもらってもOKです。

> mkdir 任意のディレクトリ

> cd 任意のディレクトリ
> vi Dockerfile
> vi docker-compose.yml


Dockerfile

FROM node:10.8.0-stretch

RUN npm install --global @vue/cli

WORKDIR /projects



docker-compose.yml

version: '3'

services:
app:
build: .
ports:
- "8080:8080"
volumes:
- ".:/projects"
tty: true


> docker-compose up -d

> docker-compose exec app bash


コンテナ内

> vue create app

Vue CLI v3.0.1
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, TS, Vuex, Linter
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript for auto-detected polyfills? Yes
? Pick a linter / formatter config: TSLint
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
? Pick the package manager to use when installing dependencies: (Use arrow keys)
❯ Use Yarn
Use NPM



コンテナ内

> cd app

> yarn serve

これで環境が整いました。


検証

errorHandlerを利用してエラー検知できるようにします。


src/main.ts

import Vue from 'vue';

import App from './App.vue';
import store from './store';

Vue.config.productionTip = false;

Vue.config.errorHandler = (err, vm, info) => {
console.log('error!!!');
console.log(err);
console.log(vm);
console.log(info);
};

new Vue({
store,
render: (h) => h(App),
}).$mount('#app');


App.vueのtemplate内でエラー発生させてみます。


src/App.vue

<template>

<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<!-- HelloWorldをHelloWorld2に変更してエラー -->
<HelloWorld2 msg="Welcome to Your Vue.js + TypeScript App"/>
</div>
</template>
(略)

どうなるか、ブラウザで確認してみます。

errorHandlerにひっかからず、ブラウザでエラー発生がされてしまいました。

App.vueのscript内でエラーを発生させてみます。


src/App.vue

(略)

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from './components/HelloWorld.vue';

@Component({
components: {
HelloWorld,
},
})
export default class App extends Vue {
private created() {
throw new Error('hoge');
}
}
</script>
(略)


ブラウザで確認します。

こちらはerrorHandlerにひっかかりました。

お次はHelloWorldコンポーネントのtemplate内でエラーを発生させてみます。


src/components/HelloWorld.vue

<template>

<div class="hello">
<!-- msgをmsg2に変更してエラー -->
<h1>{{ msg2 }}</h1>
(略)

ブラウザで確認します。

これもerrorHandlerで拾ってくれず。

templateで発生するエラーに関しては拾えなさそうです。

次にVuexを利用してStoreを実装してみます。

実装は下記の記事を参考にしています。

VuexをTypeScriptで利用するのに悩んだ

https://qiita.com/kai_kou/items/fdd8ecd07995571da8a1


src/store.ts

import Vue from 'vue';

import Vuex from 'vuex';

Vue.use(Vuex);

interface State {
conuter: number;
}

export default new Vuex.Store({
state: {
conuter: 0,
} as State,
getters: {
getCounter: (state, getters) => () => {
return state.conuter;
},
},
mutations: {
increment(state, payload) {
state.conuter += 1;
},
},
actions: {
incrementAction(context) {
context.commit('increment');
},
},
});


App.vueで利用できるようにします。


src/App.vue

<template>

<div id="app">
<img alt="Vue logo" src="./assets/logo.png" @click="increment">
<HelloWorld :msg="`Welcome to Your Vue.js + TypeScript App ${this.counter}`"/>
</div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from './components/HelloWorld.vue';

@Component({
components: {
HelloWorld,
},
})
export default class App extends Vue {
private get counter(): number {
return this.$store.getters.getCounter();
}

private increment(): void {
this.$store.dispatch('incrementAction');
}
}
</script>
()


これで、画像をクリックすると「TypeScript App」の後ろにある数字がカウントアップするようになりました。

storeのgetters にエラーを仕込んでみます。


src/store.ts

()

getters: {
getCounter: (state, getters) => () => {
throw new Error('hoge');
return state.conuter;
},
},
()

ブラウザで確認しています。

errorHandlerでエラーを拾ってます。

続いてmutations に仕込みます。


src/store.ts

()

mutations: {
increment(state, payload) {
throw new Error('hoge');
state.conuter += 1;
},
},
()

ブラウザで確認しています。

むむ。errorHandlerで拾ってくれません。

続いてactions に仕込みます。

ブラウザで確認しています。

むむむ。拾ってくれません。

うーん。Vue.config.errorHandler 利用方法の理解がそもそも間違っているのかもしれませんが、template内のエラーはともかく、mutationsactions で発生したエラーは検知してほしい。。。

最終的に拾いきれてないエラーを検知するのに利用できるかなと期待していたのですが、ひとまず、思っていたのと違うぞってことがわかりました。


参考

Vue.jsでフロント側のエラー検知を共通化する

http://sms-c-engineer.hatenablog.com/entry/2018/04/24/142445

API — Vue.js#errorHandler

https://jp.vuejs.org/v2/api/index.html#errorHandler

Vue.js+TypeScriptで開発するときの参考記事まとめ

https://qiita.com/kai_kou/items/19b494a41023d84bacc7