5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

VueでDRYなエラーハンドリングを行う。

Posted at

エラーの処理、どうしていますか?
今まで毎回下のようにコードに埋め込んでいたのですが、これではエラーハンドリングやエラーメッセージの保守コストが高くなります。
throw new Error('エラーだよ。')

よりDRYに書く方法はないかと調べているとすばらしい記事がヒットしました。
https://speakerdeck.com/nori3tsu/vue-dot-js-nuxt-dot-jsfalsekuroharuerahantorinkushi-zhuang

vueのpluginとしてエラーハンドリングを登録することでグローバルレベルでエラーハンドリングの定義が可能です。
また、自作のエラークラス(CustomError)を作成することでエラーの可読性や再利用性を高めています。

以下でvue3での実装を忘備録として書き残します。

エラープラグインを作成・登録

ErrorHandlingPlugin.ts
import { App } from 'vue'
import { CustomError, MissingConnectionError } from 'CustomError'

const ErrorHandlingPlugin = {
  install: function (app: App<Element>) {

    app.config.errorHandler = (err: unknown) => {
      handler(err)
    }

    // Vue.js以外のエラー
    window.addEventListener('error', (event) => {
      handler(event.error)
    })

    // Promise経由で呼び出されるエラー(Promise.reject)
    window.addEventListener('unhandledrejection', (event) => {
      handler(event.reason)
    })
  },
}

const handler = (err: unknown) => {
  if (err instanceof MissingConnectionError) {
    alert(err.message)
    // retry、画面再読み込みなど
  } else if (err instanceof 自作のエラークラス) {
    // ... 
  } else if (err instanceof CustomError) {
    console.info('CustomError')
    // エラー後の共通の処理(モーダル出すとか)
  } else if (err instanceof Error) {
    console.error('Error')
    // エラー後の共通の処理(5xxエラー画面飛ばすとか)
  }
}

export { ErrorHandlingPlugin }

main.ts
import { createApp } from 'vue'
import { ErrorHandlingPlugin } from 'ErrorHandlingPlugin'

const app = createApp(App)
app.use(ErrorHandlingPlugin)
// ...

自作のエラークラス

CustomError.ts
// メッセージの内容はenumで定義しておく
const ErrorMessage = {
  MISSING_CONNECTION: '通信エラーが発生しました。',
} as const
type ErrorMessage = typeof ErrorMessage[keyof typeof ErrorMessage]

interface CustomErrorInterface {
  message: string
  name: string
}

class CustomError extends Error implements CustomErrorInterface {
  constructor(message: string) {
    super(message)
    this.name = 'CustomError'
  }
}

// 自作のエラーはCustomErrorを拡張。命名としてErrorをつけるようにしている
class MissingConnectionError extends CustomError {
  constructor() {
    super(ErrorMessage.MISSING_CONNECTION)
    this.name = 'MissingConnectionError'
  }
}

export {
  ErrorMessage,
  CustomError,
  MissingConnectionError,
}

エラー呼び出し

あとはエラーが出た時に自作エラーを投げれば共通の処理を行なってくれます!

client.js
try {
  // エラーが出そうな処理
} catch (e) {
  console.error(e)
  throw new MissingConnectionError()
}

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?