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

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

More than 1 year has passed since last update.

概要

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>
(略)

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

スクリーンショット 2018-09-10 16.42.33.png

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>
(略)

ブラウザで確認します。

スクリーンショット 2018-09-10 16.46.24.png

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

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

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

ブラウザで確認します。

スクリーンショット 2018-09-10 16.49.52.png

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

スクリーンショット 2018-09-10 16.57.10.png

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

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

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

スクリーンショット 2018-09-10 16.59.49.png

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

続いてmutations に仕込みます。

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

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

スクリーンショット 2018-09-10 17.00.55.png

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

続いてactions に仕込みます。

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

スクリーンショット 2018-09-10 17.01.32.png

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

うーん。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

kai_kou
2004年からWeb系のシステムエンジニアとして開発、運用、マネジメントを経験。現在はアイレット(クラウドパック)に所属。 べ、別にいいね貰えたからってモチベーションが上がって記事とコードの品質があがるわけじゃないんだからね///
https://twitter.com/k_aik_ou
cloudpack
Amazon Web Services (AWS) の導入設計、環境構築、運用・保守をサポートするマネジドホスティングサービス
https://cloudpack.jp/
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