mcpField
V
vue-composition

vue-composition

github.com/claude-dev-suite開発4636 回インストール2 日前に更新
リポジトリ

vue-composition について

Vue アプリケーションを開発する方向けの、Vue 3 Composition API リファレンススキルです。リアクティビティやコンポーザブルに加え、セキュリティ、エラー処理、パフォーマンス、アクセシビリティ、テストを扱います。

主な機能

  1. 01リアクティビティ API と状態
  2. 02コンポーザブル関数のパターン
  3. 03コンポーネントと props の実践
  4. 04セキュリティとエラー処理
  5. 05パフォーマンスとアクセシビリティ
  6. 06テスト設定

活用シーン

  1. 01再利用可能なコンポーザブルの作成
  2. 02コンポーネントのリアクティブな状態管理
  3. 03Vue アプリのセキュリティと性能の確認

MCP 対応

包括的な Vue ドキュメントの参照先として `mcp__documentation__fetch_docs` を案内します。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill vue-composition

インストール後、Claude Code で/vue-compositionを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

advanced.md
quick-ref/
composables.md
reactivity-cheatsheet.md

詳細

Vue 3 Composition API

完全なリファレンス:WebSocket コンポーザブル、provide/inject プラグインパターン、Socket.IO の統合、ルーム管理については、advanced.md を参照してください。

詳細な知識:包括的なドキュメントについては、technology: vue を指定して mcp__documentation__fetch_docs を使用してください。

このスキルを使用しない場合

次の場合は、このスキルを使用しないでください。

  • Vue 2 Options API を使用する場合(legacy Vue docs を使用してください)
  • React アプリケーションを構築する場合(frontend-react を使用してください)
  • Angular フレームワークを使用する場合(angular を使用してください)
  • Svelte を使用する場合(svelte を使用してください)
  • サーバーサイドのみのロジックを扱う場合(フレームワークは不要です)

コンポーネントの構成

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'

interface Props {
  title: string
  count?: number
}

const props = defineProps<Props>()
const emit = defineEmits<{
  update: [value: string]
}>()

const localState = ref('')
const doubled = computed(() => props.count * 2)

onMounted(() => {
  console.log('Component mounted')
})
</script>

<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ doubled }}</p>
  </div>
</template>

リアクティビティシステム

API目的
ref()プリミティブなリアクティブ値
reactive()リアクティブオブジェクト
computed()派生状態
watch()リアクティブソースを監視
watchEffect()依存関係を自動追跡

コンポーザブルのパターン

// useCounter.ts
export function useCounter(initial = 0) {
  const count = ref(initial)
  const increment = () => count.value++
  const decrement = () => count.value--
  return { count, increment, decrement }
}

主な概念

  • <script setup> が推奨される構文です
  • プリミティブには ref、オブジェクトには reactive を使用します
  • 双方向バインディングには v-model を使用します
  • コンテンツの配信にはスロットを使用します

アンチパターン

アンチパターン問題点正しい方法
プリミティブに reactive() を使用する分割代入するとリアクティビティが失われますプリミティブには ref() を使用します
props を直接変更する一方向のデータフローが崩れますイベントを発行し、v-model を使用します
サニタイズせずに v-html を使用するXSS の脆弱性につながりますレンダリング前に DOMPurify を使用します
メモ化せずに大きな computed を使用するレンダリングのたびに再計算されます小さな computed に分割します
onUnmounted でクリーンアップしないメモリリークが発生しますタイマーをクリアし、購読を解除します
computed で十分な場合に watch を使用する不必要に複雑になります派生状態には computed を使用します

よくある問題のトラブルシューティング

問題考えられる原因解決策
Computed が更新されないref に .value を付け忘れている.value で ref にアクセスします
テンプレートがリアクティブにならないref の代わりに let を使用しているref() または reactive() に変換します
props の変更に関する警告props を直接変更しているprops を複製するか、更新イベントを発行します
コンポーネントが再レンダリングされないプリミティブに reactive を使用しているプリミティブには ref() を使用します
メモリリーククリーンアップを忘れているonUnmounted でクリーンアップを追加します
v-model が動作しないイベント名が間違っているupdate:modelValue イベントを使用します

本番環境への準備

セキュリティのベストプラクティス
<script setup lang="ts">
// NEVER use v-html with user input without sanitization
import DOMPurify from 'dompurify'

const props = defineProps<{ userContent: string }>()
const sanitizedContent = computed(() => DOMPurify.sanitize(props.userContent))
</script>

<template>
  
  <div v-html="userContent" />

  
  <div v-html="sanitizedContent" />
</template>
// Validate external URLs
const isValidUrl = (url: string): boolean => {
  try {
    const parsed = new URL(url)
    return ['http:', 'https:'].includes(parsed.protocol)
  } catch {
    return false
  }
}

// Never expose secrets in client code
// Use runtime config or server routes instead
const config = useRuntimeConfig()
// config.public.* is safe for client
// config.* (without public) stays server-side
エラー処理
<script setup lang="ts">
import { onErrorCaptured } from 'vue'

// Component-level error boundary
onErrorCaptured((error, instance, info) => {
  // Log to error tracking service
  logError(error, { component: instance?.$options.name, info })

  // Return false to prevent error propagation
  return false
})
</script>
// Global error handler (main.ts)
const app = createApp(App)

app.config.errorHandler = (error, instance, info) => {
  console.error('Global error:', error)
  // Send to error tracking (Sentry, etc.)
  captureException(error, { extra: { info } })
}

app.config.warnHandler = (msg, instance, trace) => {
  // Log warnings in development
  if (import.meta.env.DEV) console.warn(msg, trace)
}
パフォーマンスの最適化
<script setup lang="ts">
import { defineAsyncComponent, shallowRef } from 'vue'

// Lazy load heavy components
const HeavyChart = defineAsyncComponent({
  loader: () => import('./HeavyChart.vue'),
  loadingComponent: LoadingSpinner,
  delay: 200,
  errorComponent: ErrorDisplay,
})

// Use shallowRef for large objects that don't need deep reactivity
const largeDataset = shallowRef<DataItem[]>([])

// Computed with getter/setter for derived state
const filteredItems = computed(() =>
  items.value.filter(item => item.active)
)
</script>

<template>
  
  <header v-once>
    <h1>{{ appTitle }}</h1>
  </header>

  
  <div v-for="item in list" :key="item.id" v-memo="[item.id, item.updated]">
    <ExpensiveComponent :data="item" />
  </div>

  
  <VirtualList :items="largeDataset" :item-height="50" />
</template>
アクセシビリティ(a11y)
<template>
  
  <button @click="handleClick">Submit</button>

  
  <div role="alert" aria-live="polite" v-if="error">
    {{ error }}
  </div>

  
  <dialog ref="dialogRef" @vue:mounted="dialogRef?.focus()">
    <h2 id="dialog-title">Confirm Action</h2>
    <div aria-labelledby="dialog-title">...</div>
  </dialog>
</template>
テストのセットアップ
// Component testing with Vue Test Utils
import { mount } from '@vue/test-utils'
import { describe, it, expect, vi } from 'vitest'

describe('UserForm', () => {
  it('emits submit with form data', async () => {
    const wrapper = mount(UserForm)

    await wrapper.find('input[name="email"]').setValue('[email protected]')
    await wrapper.find('form').trigger('submit')

    expect(wrapper.emitted('submit')).toBeTruthy()
    expect(wrapper.emitted('submit')[0]).toEqual([{ email: '[email protected]' }])
  })
})
監視するメトリクス
メトリクスアラートのしきい値
Largest Contentful Paint(LCP)> 2.5s
First Input Delay(FID)> 100ms
Cumulative Layout Shift(CLS)> 0.1
JavaScript バンドルサイズ> 200KB(gzip 圧縮後)
コンポーネントのレンダリング時間> 16ms
ビルドの最適化
// vite.config.ts
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vue: ['vue', 'vue-router', 'pinia'],
          ui: ['@headlessui/vue', '@vueuse/core'],
        },
      },
    },
    sourcemap: true,
  },
})
チェックリスト
  • グローバルエラーハンドラーを設定済み
  • クライアントの状態に機密データが含まれていない
  • v-html のコンテンツに DOMPurify を使用
  • コード分割に非同期コンポーネントを使用
  • 大きな非リアクティブデータに shallowRef を使用
  • コストの高いリストのレンダリングに v-memo を使用
  • 長いリストに仮想スクロールを使用
  • セマンティック HTML と ARIA ラベルを使用
  • Core Web Vitals を監視
  • バンドルサイズを最適化
  • エラー報告サービスを統合

リファレンスドキュメント

詳細な知識:包括的なドキュメントについては、technology: vue を指定して mcp__documentation__fetch_docs を使用してください。

コメント