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です。

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

```txt:Dockerfile
FROM node:10.8.0-stretch

RUN npm install --global @vue/cli

WORKDIR /projects
```

```yaml:docker-compose.yml
version: '3'

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

```sh
> docker-compose up -d
> docker-compose exec app bash
```

```sh:コンテナ内
> 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
```

```sh:コンテナ内
> cd app
> yarn serve
```

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


## 検証

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


```ts: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内でエラー発生させてみます。

```vue: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>
(略)
```

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

<img width="1448" alt="スクリーンショット 2018-09-10 16.42.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/eb2e7425-44d6-5e35-0ac1-526bdd9f995f.png">

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


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

```vue: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>
(略)
```

ブラウザで確認します。

<img width="1341" alt="スクリーンショット 2018-09-10 16.46.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/636c7fd2-62f8-6a13-fd66-5c9808c5c394.png">


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

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

```vue:src/components/HelloWorld.vue
<template>
  <div class="hello">
    <!-- msgをmsg2に変更してエラー -->
    <h1>{{ msg2 }}</h1>
(略)
```

ブラウザで確認します。

<img width="1311" alt="スクリーンショット 2018-09-10 16.49.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/ec0a6b6a-3681-25dc-bb3d-67904983f20e.png">


これもerrorHandlerで拾ってくれず。
templateで発生するエラーに関しては拾えなさそうです。


次にVuexを利用してStoreを実装してみます。
実装は下記の記事を参考にしています。

VuexをTypeScriptで利用するのに悩んだ
https://qiita.com/kai_kou/items/fdd8ecd07995571da8a1

```ts: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で利用できるようにします。

```ts: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」の後ろにある数字がカウントアップするようになりました。

<img width="1315" alt="スクリーンショット 2018-09-10 16.57.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/a0f1f210-16f8-2f49-7698-5f266b484e2f.png">


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

```ts:src/store.ts
(略)
  getters: {
    getCounter: (state, getters) => () => {
      throw new Error('hoge');
      return state.conuter;
    },
  },
(略)
```

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

<img width="1380" alt="スクリーンショット 2018-09-10 16.59.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/6cba3e3e-d42a-e91b-9278-1565a28a13e7.png">


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

続いて```mutations``` に仕込みます。

```ts:src/store.ts
(略)
  mutations: {
    increment(state, payload) {
      throw new Error('hoge');
      state.conuter += 1;
    },
  },
(略)
```

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

<img width="1356" alt="スクリーンショット 2018-09-10 17.00.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/e796f3cf-1a9c-5045-ec08-30a68a8449fc.png">


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

続いて```actions``` に仕込みます。


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

<img width="1354" alt="スクリーンショット 2018-09-10 17.01.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/d19192a4-35b2-9be2-831f-bf6b5334762a.png">


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


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

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


## 参考

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