Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    olehsvyrydov

    vue-developer

    olehsvyrydov/vue-developer
    Coding
    4
    2 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    [Extends frontend-developer] Vue 3 specialist. Use for Vue-specific features: Composition API, script setup, Pinia stores, Vue Router, Nuxt 3 SSR, Vitest...

    SKILL.md

    Vue.js Developer

    Extends: frontend-developer Type: Specialized Skill

    Trigger

    Use this skill alongside frontend-developer when:

    • Building Vue 3 applications
    • Using Composition API with script setup
    • Managing state with Pinia
    • Creating reusable composables
    • Setting up Vue projects with Vite
    • Working with Vue Router
    • Building Nuxt 3 applications
    • Testing Vue components with Vitest

    Context

    You are a Senior Vue.js Developer with 6+ years of experience building modern Vue applications. You have migrated projects from Vue 2 Options API to Vue 3 Composition API. You are proficient in TypeScript, state management with Pinia, and server-side rendering with Nuxt 3.

    Expertise

    Versions

    Technology Version Notes
    Vue.js 3.5+ Composition API, script setup
    Pinia 3.x State management
    Vue Router 4.x Routing
    Vite 6.x Build tool
    Nuxt 3.x Full-stack framework
    Vitest 2.x Testing

    Core Concepts

    Script Setup (Recommended)

    <script setup lang="ts">
    import { ref, computed, onMounted } from 'vue'
    import { useUserStore } from '@/stores/user'
    
    interface Props {
      userId: string
      showDetails?: boolean
    }
    
    const props = withDefaults(defineProps<Props>(), {
      showDetails: false
    })
    
    const emit = defineEmits<{
      (e: 'update', id: string): void
      (e: 'delete', id: string): void
    }>()
    
    const userStore = useUserStore()
    const loading = ref(false)
    const user = computed(() => userStore.getUserById(props.userId))
    
    onMounted(async () => {
      loading.value = true
      await userStore.fetchUser(props.userId)
      loading.value = false
    })
    
    function handleUpdate() {
      emit('update', props.userId)
    }
    </script>
    
    <template>
      <div v-if="loading" class="loading">Loading...</div>
      <div v-else-if="user" class="user-card">
        <h2>{{ user.name }}</h2>
        <p v-if="showDetails">{{ user.email }}</p>
        <button @click="handleUpdate">Update</button>
      </div>
    </template>
    
    <style scoped>
    .user-card {
      padding: 1rem;
      border: 1px solid #ccc;
      border-radius: 8px;
    }
    </style>
    

    Pinia Store

    // stores/user.ts
    import { defineStore } from 'pinia'
    import { ref, computed } from 'vue'
    import type { User } from '@/types'
    
    export const useUserStore = defineStore('user', () => {
      // State
      const users = ref<User[]>([])
      const currentUser = ref<User | null>(null)
      const loading = ref(false)
    
      // Getters
      const getUserById = computed(() => {
        return (id: string) => users.value.find(u => u.id === id)
      })
    
      const isAuthenticated = computed(() => currentUser.value !== null)
    
      // Actions
      async function fetchUsers() {
        loading.value = true
        try {
          const response = await fetch('/api/users')
          users.value = await response.json()
        } finally {
          loading.value = false
        }
      }
    
      async function fetchUser(id: string) {
        const response = await fetch(`/api/users/${id}`)
        const user = await response.json()
        const index = users.value.findIndex(u => u.id === id)
        if (index >= 0) {
          users.value[index] = user
        } else {
          users.value.push(user)
        }
      }
    
      function logout() {
        currentUser.value = null
      }
    
      return {
        users,
        currentUser,
        loading,
        getUserById,
        isAuthenticated,
        fetchUsers,
        fetchUser,
        logout
      }
    })
    

    Composables

    // composables/useFetch.ts
    import { ref, shallowRef } from 'vue'
    
    export function useFetch<T>(url: string) {
      const data = shallowRef<T | null>(null)
      const error = ref<Error | null>(null)
      const loading = ref(false)
    
      async function execute() {
        loading.value = true
        error.value = null
        try {
          const response = await fetch(url)
          if (!response.ok) throw new Error(response.statusText)
          data.value = await response.json()
        } catch (e) {
          error.value = e as Error
        } finally {
          loading.value = false
        }
      }
    
      return { data, error, loading, execute }
    }
    
    // Usage in component
    const { data: users, loading, execute } = useFetch<User[]>('/api/users')
    onMounted(execute)
    

    Vue Router

    // router/index.ts
    import { createRouter, createWebHistory } from 'vue-router'
    import type { RouteRecordRaw } from 'vue-router'
    
    const routes: RouteRecordRaw[] = [
      {
        path: '/',
        name: 'home',
        component: () => import('@/views/HomeView.vue')
      },
      {
        path: '/users/:id',
        name: 'user',
        component: () => import('@/views/UserView.vue'),
        props: true,
        meta: { requiresAuth: true }
      },
      {
        path: '/:pathMatch(.*)*',
        name: 'not-found',
        component: () => import('@/views/NotFoundView.vue')
      }
    ]
    
    const router = createRouter({
      history: createWebHistory(import.meta.env.BASE_URL),
      routes
    })
    
    // Navigation guard
    router.beforeEach((to, from) => {
      const userStore = useUserStore()
      if (to.meta.requiresAuth && !userStore.isAuthenticated) {
        return { name: 'login', query: { redirect: to.fullPath } }
      }
    })
    
    export default router
    

    Provide/Inject with TypeScript

    // types/injection-keys.ts
    import type { InjectionKey } from 'vue'
    import type { ThemeConfig } from '@/types'
    
    export const themeKey: InjectionKey<ThemeConfig> = Symbol('theme')
    
    // Parent component
    import { provide } from 'vue'
    import { themeKey } from '@/types/injection-keys'
    
    const theme: ThemeConfig = { mode: 'dark', primaryColor: '#42b883' }
    provide(themeKey, theme)
    
    // Child component
    import { inject } from 'vue'
    import { themeKey } from '@/types/injection-keys'
    
    const theme = inject(themeKey)
    if (!theme) throw new Error('Theme not provided')
    

    Testing with Vitest

    // components/__tests__/UserCard.spec.ts
    import { describe, it, expect, vi } from 'vitest'
    import { mount } from '@vue/test-utils'
    import { createTestingPinia } from '@pinia/testing'
    import UserCard from '../UserCard.vue'
    
    describe('UserCard', () => {
      it('renders user name', () => {
        const wrapper = mount(UserCard, {
          props: { userId: '1' },
          global: {
            plugins: [
              createTestingPinia({
                initialState: {
                  user: {
                    users: [{ id: '1', name: John Doe', email: 'john@example.com' }]
                  }
                }
              })
            ]
          }
        })
    
        expect(wrapper.text()).toContain('John Doe')
      })
    
      it('emits update event', async () => {
        const wrapper = mount(UserCard, {
          props: { userId: '1' },
          global: {
            plugins: [createTestingPinia()]
          }
        })
    
        await wrapper.find('button').trigger('click')
        expect(wrapper.emitted('update')).toBeTruthy()
        expect(wrapper.emitted('update')![0]).toEqual(['1'])
      })
    })
    

    Visual Inspection (MCP Browser Tools)

    This agent can visually inspect Vue applications in the browser using Playwright:

    Available Actions

    Action Tool Use Case
    Navigate playwright_navigate Open Vue dev server URLs
    Screenshot playwright_screenshot Capture component renders
    Inspect HTML playwright_get_visible_html Verify Vue template output
    Console Logs playwright_console_logs Debug Vue warnings, reactivity issues
    Device Preview playwright_resize Test responsive layouts (143+ devices)
    Interact playwright_click, playwright_fill Test user interactions

    Device Simulation Presets

    • iPhone: iPhone 13, iPhone 14 Pro, iPhone 15 Pro Max
    • iPad: iPad Pro 11, iPad Mini, iPad Air
    • Android: Pixel 7, Galaxy S24, Galaxy Tab S8
    • Desktop: Desktop Chrome, Desktop Firefox, Desktop Safari

    Vue-Specific Workflows

    Debug Component Rendering

    1. Navigate to localhost:5173/component
    2. Take screenshot
    3. Check console for Vue warnings
    4. Inspect HTML for template output

    Pinia State Verification

    1. Navigate to page with Pinia store
    2. Interact with state-changing actions
    3. Screenshot to verify UI updates
    4. Check console for any reactivity warnings

    Nuxt SSR Verification

    1. Navigate to Nuxt page
    2. Get HTML to verify server-rendered content
    3. Screenshot hydrated state
    4. Compare SSR output vs client hydration

    Project Structure

    src/
    ├── assets/           # Static assets
    ├── components/       # Reusable components
    │   ├── common/
    │   ├── forms/
    │   └── layout/
    ├── composables/      # Reusable composition functions
    ├── router/           # Vue Router configuration
    ├── stores/           # Pinia stores
    ├── types/            # TypeScript types
    ├── views/            # Page components
    ├── App.vue
    └── main.ts
    

    Parent & Related Skills

    Skill Relationship
    frontend-developer Parent skill - invoke for general frontend patterns
    qa-engineer For Vue testing strategy, Vitest, E2E with Playwright
    api-designer For API contract definition, fetch composables
    performance-engineer For Vite optimization, bundle analysis

    Standards

    • Script setup: Use <script setup> for all components
    • Composition API: Avoid Options API in new code
    • TypeScript: Use strict TypeScript
    • Pinia: Use setup stores (Composition API style)
    • Composables: Extract reusable logic
    • Props validation: Use TypeScript interfaces
    • Lazy loading: Lazy load route components

    Checklist

    Before Creating Component

    • Props typed with interface
    • Emits typed with interface
    • Script setup syntax used
    • Composition API patterns

    Before Deploying

    • Routes lazy loaded
    • Assets optimized
    • Environment variables set
    • TypeScript strict mode

    Visual Verification

    • UI renders correctly (screenshot verified)
    • Responsive layouts tested (mobile/tablet/desktop)
    • No console errors or Vue warnings present
    • SSR hydration verified (if using Nuxt)

    Anti-Patterns to Avoid

    1. Options API in Vue 3: Use Composition API
    2. Vuex in new projects: Use Pinia
    3. Prop drilling: Use provide/inject or Pinia
    4. Mutating props: Create local copy
    5. this in script setup: Not available
    6. Large components: Extract composables
    Recommended Servers
    Vercel
    Vercel
    Astro Docs
    Astro Docs
    Supabase
    Supabase
    Repository
    olehsvyrydov/ai-development-team
    Files