404 Not Found

404 Not Found


nginx

Vue 3 のエラー処理とデバッグ:errorHandler、Vue DevTools、Sentry、およびパフォーマンスの最適化

エラー処理は、あらゆる本番環境向けのアプリケーションにとって不可欠な機能です。これにより、クラッシュの原因を迅速に特定し、機能を適切に制限し、ユーザーに通知することが可能になります。Vue 3 では、errorHandler(グローバル)、onErrorCaptured(ローカル)、および errorCaptured フック(コンポーネントレベル)という、多段階のエラー処理が提供されています。

デバッグとパフォーマンスの最適化はどちらも同様に重要です。Vue DevToolsは、コンポーネントツリー、状態、イベント、パフォーマンスのボトルネックを確認できる、欠かせないツールです。

1. 学習内容


2. 「特定できる原因がない」とされる「ホワイトスクリーンクラッシュ」の事象

(1) 課題:1つのAPIでエラーが発生すると、ページ全体が真っ白になってしまう

Aliceの管理画面には、1つの重大なバグがありました:

JS
// ProductList.vue
const products = ref([])
onMounted(async () => {
  const res = await fetch('/api/products')
  products.value = await res.json()  // ❌ The backend returns non-JSON → throws error
})

ユーザー体験:

プロダクトマネージャーのチャーリー:

「アリス、顧客からページが真っ白になるという苦情が寄せられています。1)ページ全体がクラッシュしないようにし、2)エラーメッセージを表示し、3)監視システムにログを記録する必要があります。」

(2) Vueのエラーバウンダリーに対する解決策

VUE
<!-- Parent Component:Error Boundary -->
<template>
  <ErrorBoundary>
    <ProductList />
  </ErrorBoundary>
</template>

<!-- ErrorBoundary.vue -->
<script setup>
import { onErrorCaptured, ref } from 'vue'
const error = ref(null)

onErrorCaptured((err, instance, info) => {
  console.error('Caught:', err)
  // 1. Display error message
  error.value = err.message
  // 2. Report to Sentry
  Sentry.captureException(err)
  // 3. Prevent upward transmission
  return false
})
</script>

<template>
  <div v-if="error" class="error">
    <h3>⚠️ Something went wrong</h3>
    <p>{{ error }}</p>
    <button @click="retry">Retry</button>
  </div>
  <slot v-else />
</template>

ユーザー体験:

(3) 収益

エラー処理の後:


3. 3段階のエラー処理

(1) グローバルなエラー処理:app.config.errorHandler

JS
// main.js
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

// ✅ Global Error Handling
app.config.errorHandler = (err, instance, info) => {
  console.error('Global error:', err)
  console.log('Component:', instance)
  console.log('Info:', info)  // 'render' / 'watch' / 'lifecycle hook'
  
  // Report to Sentry
  Sentry.captureException(err)
  
  // User Notification
  showErrorNotification('Something went wrong')
}

(2) コンポーネントレベルのエラー:onErrorCaptured

VUE
<!-- ErrorBoundary.vue -->
<script setup>
import { onErrorCaptured, ref } from 'vue'

const error = ref(null)

// ✅ Catching Child Component Errors
onErrorCaptured((err, instance, info) => {
  console.error('Boundary caught:', err)
  error.value = {
    message: err.message,
    stack: err.stack,
    info
  }
  
  // Prevent upward transmission
  return false
})
</script>

<template>
  <div v-if="error" class="error-boundary">
    <h3>⚠️ {{ error.message }}</h3>
    <details>
      <summary>Stack trace</summary>
      <pre>{{ error.stack }}</pre>
    </details>
    <button @click="reset">Retry</button>
  </div>
  <slot v-else />
</template>

(3) 誤差レベルの比較

レベル API 適用範囲 対象
グローバル app.config.errorHandler すべての未処理のエラー 本番環境必須
コンポーネント onErrorCaptured 子コンポーネントのエラー ローカルエラー境界
非同期 try/catch / window.onunhandledrejection Promiseエラー 手動での処理

(4) 誤りの5つの主な原因

JS
// 1. Rendering Error(Template syntax error)
app.config.errorHandler = (err, instance, info) => {
  if (info === 'render') console.error('Render error:', err)
}

// 2. Lifecycle Hook Error
if (info === 'mounted') console.error('Mounted error:', err)

// 3. watch Callback Error
if (info === 'watcher callback') console.error('Watch error:', err)

// 4. Custom Command Error
if (info === 'directive') console.error('Directive error:', err)

// 5. Error Handling
if (info === 'v-on handler') console.error('Event error:', err)

4. DevTools ビュー

(1) 4つの主要コアパネル

パネル 機能 目的
コンポーネント コンポーネントツリー、状態、プロパティ、エミット コンポーネントの構造の理解、データのデバッグ
タイムライン イベント、ライフサイクル、パフォーマンス イベントの流れとパフォーマンスのボトルネックを追跡
Pinia/Vuex 状態の保存 グローバル状態のデバッグ
ルート ルートの履歴 ルートのリダイレクトをデバッグ

(2) コンポーネントパネルの使用方法

TEXT
1. Open DevTools(F12 / Cmd+Opt+I)
2. Switch to Vue Tags
3. Click a component in the component tree
4. Display on the right:
   - State(Responsive Data)
   - Props
   - Emits
   - Slots
   - Lifecycle

(3) DevToolsの役立つヒント5選

JS
// 1. Real-time editing state(Development Mode)
// DevTools Edit directly in the document,Watch the component respond in real time

// 2. Time Travel(Pinia)
// Switch to Pinia Panel → Base → You can replay each step state Changes

// 3. Performance Labels
// import { markRaw } from 'vue'
// Big Data Objects Used For markRaw Mark,DevTools Does not perform a deep traversal

// 4. Components highlight
// DevTools → top right corner"Eyes"Icon → Highlight Components on Mouse Hover

// 5. Route Redirection
// DevTools → Routing Tags → Look at each redirect path + params

(4) Vue DevTools をインストールする

BASH
# Chrome Extensions
# https://chromewebstore.google.com/detail/vuejs-devtools/odjccnclnlddjlajjphfdmhnlhaglgki

# Firefox Extensions
# https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/

# or a standalone app(Recommendations)
# https://devtools.vuejs.org/

5. パフォーマンス分析

(1) View 3 Performance API

JS
import { onMounted, onUnmounted } from 'vue'

onMounted(() => {
  performance.mark('app-start')
  
  // Your code
  loadData()
  
  performance.mark('app-end')
  performance.measure('app-load', 'app-start', 'app-end')
  
  const measure = performance.getEntriesByName('app-load')[0]
  console.log(`App loaded in ${measure.duration}ms`)
})

(2) パフォーマンス最適化の5つのヒント

JS
// 1. v-once:Render only once
<h1 v-once>{{ title }}</h1>

// 2. v-memo:Cache Subtree
<div v-memo="[item.id, item.updatedAt]">
  <!-- Only re-render on id or updatedAt changes -->
</div>

// 3. shallowRef:Big Data Does Not Respond Deeply
const bigList = shallowRef([...10000 items])

// 4. markRaw:Third-party library is not responding
const map = markRaw(new Map())

// 5. Lazy Loading:Routing / Components
const Heavy = defineAsyncComponent(() => import('./Heavy.vue'))

(3) 5つの主要業績評価指標

指標 目標値 測定方法
FCP (First Contentful Paint) 1.8秒未満 Lighthouse
LCP (Largest Contentful Paint) 2.5秒未満 Lighthouse
TTI (Time to Interact) < 3.8秒 Lighthouse
TBT (総ブロッキング時間) < 200 ms Lighthouse
CLS(レイアウトシフト) < 0.1 Lighthouse

6. Sentryとの連携

(1) インストール

BASH
npm install @sentry/vue @sentry/tracing

(2) main.js の設定

JS
import { createApp } from 'vue'
import * as Sentry from '@sentry/vue'
import { Integrations } from '@sentry/tracing'
import App from './App.vue'

// 1. Initialization Sentry
Sentry.init({
  app,
  dsn: 'https://your-dsn@sentry.io/123',
  integrations: [
    new Integrations.BrowserTracing()
  ],
  tracesSampleRate: 1.0,
  // Reduce Sampling in the Production Environment
  // tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0
  
  // Vue Specific Placement
  logErrors: true,
  release: '1.0.0',
  environment: process.env.NODE_ENV
})

const app = createApp(App)

// 2. Global Error Reporting
app.config.errorHandler = (err, instance, info) => {
  Sentry.captureException(err, {
    extra: {
      component: instance?.$options.name,
      info
    }
  })
}

(3) ソースマップの設定

JS
// vite.config.js
export default {
  build: {
    sourcemap: true  // Generated in the production environment as well source map
  }
}

// Sentry Upload source map
// @sentry/cli releases -o your-org -p your-project files upload-sourcemaps ./dist

(4) キーセントリーの5つの主な機能

機能 目的
エラー監視 すべてのエラーを自動的に記録し、ダッシュボードで確認できます
パフォーマンストレース 処理に時間がかかるリクエストやデータベースクエリの特定
セッション再生 ユーザーの操作を記録して、エラーが発生した箇所を確認する
健康関連のリリース リリースごとのエラー率の比較
アラート Slack / メール通知

7. 完全な例:5つの重要なデバッグ手法

(1) ▶ サンプル:. 3段階のエラー処理

JS
// main.js:Global
app.config.errorHandler = (err, instance, info) => {
  console.error('Global:', err, info)
  Sentry.captureException(err)
}
▶ 試してみよう
VUE
<!-- ErrorBoundary.vue:Components -->
<script setup>
import { onErrorCaptured, ref } from 'vue'
const error = ref(null)
onErrorCaptured((err, instance, info) => {
  error.value = err.message
  return false
})
</script>
JS
// Asynchronous:Manual try/catch
try {
  await fetch('/api/data')
} catch (err) {
  console.error('Async:', err)
  Sentry.captureException(err)
}

(2) ▶ サンプル:. 5つの主な誤りの原因

JS
// 1. Rendering Error
if (info === 'render') console.error('Render')

// 2. Life Cycle Errors
if (info === 'mounted') console.error('Mounted')

// 3. watch Error
if (info === 'watcher callback') console.error('Watch')

// 4. Command error
if (info === 'directive') console.error('Directive')

// 5. Event Error
if (info === 'v-on handler') console.error('Event')
▶ 試してみよう

(3) ▶ サンプル:. DevTools ビュー:4つのパネル

パネル 目的
コンポーネント コンポーネントツリー + 状態 + プロパティ
タイムライン イベントストリーム + ライフサイクル
ピニア 店舗の状況
ルート ルートの履歴

(4) ▶ サンプル:. 5つの主要なパフォーマンス最適化

JS
// 1. v-once
<h1 v-once>{{ title }}</h1>

// 2. v-memo
<div v-memo="[item.id]">...</div>

// 3. shallowRef
const list = shallowRef([...])

// 4. markRaw
const map = markRaw(new Map())

// 5. Lazy Loading
const Heavy = defineAsyncComponent(() => import('./Heavy.vue'))
▶ 試してみよう

(5) ▶ サンプル:. よくある5つの間違いに関するクイックリファレンス

エラー 症状 解決策
ホワイトスクリーンによるクラッシュ 1つのコンポーネントのエラーがすべてをクラッシュさせる ErrorBoundaryでラップする
エラーが捕捉されました 子コンポーネントが静かに失敗します onErrorCaptured で false を返すのを忘れないでください
ソースマップが見つかりません 本番環境のエラーを特定できません vite build sourcemap: true
パフォーマンスの低下 1,000件のアイテムを一覧表示する際に遅延が発生 v-memo + shallowRef
メモリリーク コンポーネントの破棄後もタイマーが動作し続ける onUnmounted でのクリーンアップ

(6) ▶ サンプル:5つの主要なデバッグシナリオ

シナリオ ツール
コンポーネントの状態エラー Vue DevTools → 状態
イベントがトリガーされなかった Vue DevTools → タイムライン
ルーティングのリダイレクトエラー DevTools → ルーティング
本番環境のクラッシュ Sentry ダッシュボード
パフォーマンスの低下 Lighthouse + DevTools によるパフォーマンス

❓ よくある質問

Q errorHandler は非同期エラーを捕捉できますか?
A いいえ。errorHandler は Vue 内の同期エラーのみを捕捉します。非同期エラー(Promise / setTimeout)を捕捉するには、try/catch または window.addEventListener('unhandledrejection') が必要です。
Q onErrorCapturedfalse を返さなければならないのでしょうか?
A いいえ、その必要はありません。false を返すことで、エラーが上流へ伝播するのを防ぐことができます。true を返す(あるいは何も返さない)と、エラーは上流のグローバル変数 errorHandler へと伝播し続けます。
Q Vue DevToolsは本番環境で使用できますか?
A はい。本番ビルドでは、DevToolsが自動的に有効になります(パフォーマンスに影響はありません)。ただし、本番環境では、内部構造が外部にさらされるのを防ぐため、Vue.config.devtools = false を使用して無効にすることをお勧めします。
Q Sentryの料金体系はどのようになっていますか?
A 無料プランでは、毎月5,000件のイベントと10,000件のパフォーマンストランザクションが利用可能です。これは中規模のプロジェクトには十分な容量です。この上限を超える利用分については、従量課金制で請求されます。
Q v-memo と v-for はどのように連携するのですか?
A <div v-for="item in items" :key="item.id" v-memo="[item.id, item.updatedAt]">、この div は、id または updatedAt のいずれかが変更された場合にのみ再レンダリングされます。
Q SSRアプリケーションのデバッグ方法は?
A VS CodeのデバッガーとNode.jsのインスペクトモードを使用します。あるいは、Sentryを使ってサーバーサイドのエラーを捕捉することもできます。また、Nuxt 3のNitroデバッグツールを使用することも可能です。
Q Vue 3とVue 2におけるonErrorCapturedの違いは何ですか?
A Vue 2ではerrorCapturedフックですが、Vue 3ではonErrorCapturedコンポジションAPIです。また、Vue 3では新しいグローバル変数app.config.errorHandlerも導入されています。

📖 まとめ


📝 練習問題

(1) 基礎問題(難易度:⭐)

ErrorBoundary コンポーネントを実装します:

(2) 上級問題(難易度:⭐⭐)

包括的なエラー処理システムを実装する:

(3) チャレンジ問題(難易度:⭐⭐⭐)

包括的な「本番環境向け」のデバッグおよびエラー監視を実装する:

  1. ErrorBoundary コンポーネント + 3つの異なる場所
  2. Sentryとの連携(本番環境)
  3. ソースマップの設定
  4. Vue DevTools におけるデバッグの5つのヒント
  5. 5つの主要なパフォーマンス最適化(v-memo / shallowRef / markRaw / 遅延読み込み / v-once)
  6. 5つの主要業績評価指標のモニタリング(Lighthouseとの連携)
Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%