@codihaus/claude-skills 1.6.18 → 1.6.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,750 @@
1
+ # Vue 3
2
+
3
+ > Progressive JavaScript framework for building user interfaces
4
+
5
+ ## Overview
6
+
7
+ **What it is:**
8
+ - Progressive framework (incrementally adoptable)
9
+ - Component-based with Single File Components (SFCs)
10
+ - Composition API for logic reuse (Vue 3+)
11
+ - Reactive and declarative
12
+ - Virtual DOM with optimized reactivity
13
+ - Template syntax with directives
14
+
15
+ **When to use:**
16
+ - Building interactive user interfaces
17
+ - Single-page applications (SPAs)
18
+ - Progressive enhancement of existing sites
19
+ - Projects needing gentle learning curve
20
+ - Teams wanting flexibility and simplicity
21
+
22
+ **Key concepts:**
23
+ - **SFC (Single File Component)** = .vue files with template, script, style
24
+ - **Composition API** = Composable logic with setup()
25
+ - **Reactivity** = ref(), reactive(), computed(), watch()
26
+ - **Template Syntax** = Directives (v-if, v-for, v-bind, v-on)
27
+ - **Components** = Reusable building blocks
28
+ - **Props & Emits** = Parent-child communication
29
+ - **Provide/Inject** = Dependency injection
30
+
31
+ ## Best Practices
32
+
33
+ ### Project Structure
34
+
35
+ ```
36
+ vue-app/
37
+ ├── src/
38
+ │ ├── components/ # Reusable components
39
+ │ │ ├── ui/ # UI primitives
40
+ │ │ ├── forms/ # Form components
41
+ │ │ └── common/ # Shared components
42
+ │ ├── composables/ # Composition API composables
43
+ │ │ └── useAuth.js # use* naming convention
44
+ │ ├── views/ # Page components (routes)
45
+ │ ├── stores/ # Pinia stores
46
+ │ ├── router/ # Vue Router config
47
+ │ ├── assets/ # Static assets
48
+ │ ├── utils/ # Helper functions
49
+ │ ├── types/ # TypeScript types
50
+ │ ├── App.vue # Root component
51
+ │ └── main.js # Entry point
52
+ └── public/ # Public static files
53
+ ```
54
+
55
+ ### Component Structure (SFC)
56
+
57
+ ```vue
58
+ <!-- ComponentName.vue -->
59
+ <script setup>
60
+ // 1. Imports
61
+ import { ref, computed, watch, onMounted } from 'vue'
62
+ import { useRouter } from 'vue-router'
63
+
64
+ // 2. Props & Emits
65
+ const props = defineProps({
66
+ title: String,
67
+ count: { type: Number, required: true }
68
+ })
69
+
70
+ const emit = defineEmits(['update', 'close'])
71
+
72
+ // 3. Composables
73
+ const router = useRouter()
74
+ const { user } = useAuth()
75
+
76
+ // 4. Reactive state
77
+ const localCount = ref(0)
78
+ const doubled = computed(() => localCount.value * 2)
79
+
80
+ // 5. Methods
81
+ function increment() {
82
+ localCount.value++
83
+ emit('update', localCount.value)
84
+ }
85
+
86
+ // 6. Watchers
87
+ watch(() => props.count, (newVal) => {
88
+ localCount.value = newVal
89
+ })
90
+
91
+ // 7. Lifecycle hooks
92
+ onMounted(() => {
93
+ console.log('Component mounted')
94
+ })
95
+ </script>
96
+
97
+ <template>
98
+ <div class="component">
99
+ <h1>{{ title }}</h1>
100
+ <p>Count: {{ localCount }}</p>
101
+ <p>Doubled: {{ doubled }}</p>
102
+ <button @click="increment">Increment</button>
103
+ </div>
104
+ </template>
105
+
106
+ <style scoped>
107
+ .component {
108
+ /* Component styles */
109
+ }
110
+ </style>
111
+ ```
112
+
113
+ ### Composition API Best Practices
114
+
115
+ **Using `<script setup>` (Recommended):**
116
+ ```vue
117
+ DO:
118
+ ✓ Use <script setup> (less boilerplate)
119
+ ✓ Name composables with "use" prefix
120
+ ✓ Keep composables focused (single concern)
121
+ ✓ Return reactive values from composables
122
+ ✓ Use ref() for primitives, reactive() for objects
123
+
124
+ DON'T:
125
+ ✗ Mix Options API and Composition API
126
+ ✗ Use setup() function (use <script setup> instead)
127
+ ✗ Destructure reactive objects (loses reactivity)
128
+ ✗ Forget .value on refs in script
129
+ ✗ Over-abstract into composables too early
130
+ ```
131
+
132
+ **Reactivity:**
133
+ ```javascript
134
+ DO:
135
+ ✓ Use ref() for primitives
136
+ const count = ref(0)
137
+ count.value++ // Access with .value in script
138
+
139
+ ✓ Use reactive() for objects
140
+ const state = reactive({ count: 0 })
141
+ state.count++ // No .value needed
142
+
143
+ ✓ Use computed() for derived state
144
+ const doubled = computed(() => count.value * 2)
145
+
146
+ ✓ Use toRefs() when destructuring reactive objects
147
+ const { count } = toRefs(state)
148
+
149
+ DON'T:
150
+ ✗ Reassign reactive() (loses reactivity)
151
+ state = { count: 1 } // Wrong
152
+ state.count = 1 // Correct
153
+
154
+ ✗ Destructure reactive() directly
155
+ const { count } = reactive({ count: 0 }) // Loses reactivity
156
+
157
+ ✗ Use ref() for large objects (use reactive())
158
+ ✗ Compute values in watchers (use computed)
159
+ ```
160
+
161
+ **Composables Pattern:**
162
+ ```javascript
163
+ DO:
164
+ ✓ Export composable function starting with "use"
165
+ ✓ Return reactive values (refs, computed)
166
+ ✓ Keep composables composable (can call other composables)
167
+ ✓ Handle cleanup in onUnmounted
168
+
169
+ DON'T:
170
+ ✗ Call composables conditionally
171
+ ✗ Call composables in callbacks
172
+ ✗ Call composables outside setup()
173
+ ✗ Return plain values (use ref/reactive)
174
+ ```
175
+
176
+ ### Template Best Practices
177
+
178
+ **Directives:**
179
+ ```vue
180
+ DO:
181
+ ✓ Use v-bind shorthand (:prop)
182
+ <img :src="imageUrl">
183
+
184
+ ✓ Use v-on shorthand (@event)
185
+ <button @click="handler">
186
+
187
+ ✓ Use v-for with unique :key
188
+ <div v-for="item in items" :key="item.id">
189
+
190
+ ✓ Use v-if for conditional rendering
191
+ <div v-if="show">Content</div>
192
+
193
+ ✓ Use v-show for frequent toggles
194
+ <div v-show="visible">Content</div>
195
+
196
+ DON'T:
197
+ ✗ Use v-for with v-if on same element (use computed filter)
198
+ <div v-for="item in items" v-if="item.active"> <!-- BAD -->
199
+
200
+ ✗ Use index as key for dynamic lists
201
+ v-for="(item, i) in items" :key="i" <!-- BAD -->
202
+
203
+ ✗ Forget :key in v-for
204
+ ✗ Use v-html with user input (XSS risk)
205
+ ```
206
+
207
+ **Component Communication:**
208
+ ```vue
209
+ DO:
210
+ ✓ Use props for parent → child
211
+ <Child :title="parentTitle" />
212
+
213
+ ✓ Use emits for child → parent
214
+ emit('update', value)
215
+
216
+ ✓ Use provide/inject for deep hierarchies
217
+ provide('key', value)
218
+ const value = inject('key')
219
+
220
+ ✓ Use Pinia for global state
221
+
222
+ DON'T:
223
+ ✗ Mutate props directly (one-way data flow)
224
+ props.title = 'new' // Wrong
225
+ emit('update:title', 'new') // Correct
226
+
227
+ ✗ Prop drill through many levels (use provide/inject)
228
+ ✗ Use event bus (deprecated in Vue 3)
229
+ ✗ Access $parent or $root (tight coupling)
230
+ ```
231
+
232
+ ### State Management
233
+
234
+ **Local State:**
235
+ ```javascript
236
+ When: Component-specific, not shared
237
+ Example: Form inputs, toggles, local UI state
238
+ Use: ref(), reactive()
239
+ ```
240
+
241
+ **Composables:**
242
+ ```javascript
243
+ When: Reusable logic, shared between components
244
+ Example: useAuth(), useFetch(), useForm()
245
+ Use: Composable functions returning refs/computed
246
+ ```
247
+
248
+ **Pinia (Global Store):**
249
+ ```javascript
250
+ When: Global or feature-level state
251
+ Example: Auth state, cart, user preferences
252
+ DO:
253
+ ✓ One store per feature/domain
254
+ ✓ Use composition stores (setup syntax)
255
+ ✓ Keep actions for mutations
256
+ ✓ Use getters for computed state
257
+ ✓ Modularize stores
258
+
259
+ DON'T:
260
+ ✗ Use Vuex (Pinia is official for Vue 3)
261
+ ✗ Create one giant store
262
+ ✗ Mutate state outside actions
263
+ ✗ Store derived data (use getters)
264
+ ```
265
+
266
+ ### Performance Optimization
267
+
268
+ **Lazy Loading:**
269
+ ```javascript
270
+ DO:
271
+ ✓ Lazy load routes
272
+ const Home = () => import('./views/Home.vue')
273
+
274
+ ✓ Lazy load heavy components
275
+ const Chart = defineAsyncComponent(() => import('./Chart.vue'))
276
+
277
+ ✓ Use Suspense for async components
278
+ <Suspense>
279
+ <AsyncComponent />
280
+ </Suspense>
281
+
282
+ DON'T:
283
+ ✗ Lazy load small components (overhead)
284
+ ✗ Forget loading/error states
285
+ ```
286
+
287
+ **Reactivity Optimization:**
288
+ ```javascript
289
+ DO:
290
+ ✓ Use shallowRef() for large objects (no deep reactivity)
291
+ ✓ Use shallowReactive() for large structures
292
+ ✓ Mark constants with markRaw()
293
+ ✓ Use v-once for static content
294
+ ✓ Use v-memo for expensive list items
295
+
296
+ DON'T:
297
+ ✗ Create reactivity for everything
298
+ ✗ Deep watch large objects unnecessarily
299
+ ✗ Forget to unwatch in cleanup
300
+ ```
301
+
302
+ **List Rendering:**
303
+ ```vue
304
+ DO:
305
+ ✓ Use unique, stable keys (IDs from data)
306
+ <div v-for="item in items" :key="item.id">
307
+
308
+ ✓ Filter/sort in computed, not in template
309
+ const filtered = computed(() => items.filter(fn))
310
+
311
+ ✓ Use v-memo for expensive items
312
+ <div v-for="item in items" :key="item.id" v-memo="[item.id]">
313
+
314
+ DON'T:
315
+ ✗ Use index as key for dynamic lists
316
+ ✗ Filter/sort directly in v-for
317
+ ✗ Create objects/arrays in template (re-renders)
318
+ ```
319
+
320
+ ### Forms & v-model
321
+
322
+ ```vue
323
+ DO:
324
+ ✓ Use v-model for two-way binding
325
+ <input v-model="text">
326
+
327
+ ✓ Use v-model modifiers
328
+ <input v-model.trim="text">
329
+ <input v-model.number="age">
330
+
331
+ ✓ Use custom v-model on components
332
+ defineProps(['modelValue'])
333
+ defineEmits(['update:modelValue'])
334
+
335
+ ✓ Validate on blur or submit
336
+
337
+ DON'T:
338
+ ✗ Validate on every keystroke (performance)
339
+ ✗ Forget to trim/sanitize inputs
340
+ ✗ Store all form state in parent (use composables)
341
+ ```
342
+
343
+ ### TypeScript Integration
344
+
345
+ ```typescript
346
+ DO:
347
+ ✓ Define prop types with TypeScript
348
+ defineProps<{
349
+ title: string
350
+ count?: number
351
+ }>()
352
+
353
+ ✓ Type emit functions
354
+ const emit = defineEmits<{
355
+ update: [value: number]
356
+ close: []
357
+ }>()
358
+
359
+ ✓ Type composables return values
360
+ function useCounter(): { count: Ref<number>, increment: () => void }
361
+
362
+ ✓ Use generic components
363
+ defineComponent<Props, Emits>()
364
+
365
+ DON'T:
366
+ ✗ Use PropType with <script setup> (use TS interface)
367
+ ✗ Forget to type composables
368
+ ✗ Over-use any
369
+ ```
370
+
371
+ ## Anti-Patterns
372
+
373
+ ### Common Mistakes
374
+
375
+ ```vue
376
+ ❌ Mutating props
377
+ props.value = 'new' // Wrong
378
+ emit('update:value', 'new') // Correct
379
+
380
+ ❌ v-for without :key
381
+ <div v-for="item in items"> <!-- Missing :key -->
382
+
383
+ ❌ v-for + v-if on same element
384
+ <div v-for="item in items" v-if="item.active"> <!-- Use computed -->
385
+
386
+ ❌ Destructuring reactive without toRefs
387
+ const { count } = reactive({ count: 0 }) // Loses reactivity
388
+ const { count } = toRefs(reactive({ count: 0 })) // Correct
389
+
390
+ ❌ Not accessing .value on refs in script
391
+ const count = ref(0)
392
+ console.log(count) // Wrong: Ref object
393
+ console.log(count.value) // Correct
394
+
395
+ ❌ Creating reactive values in template
396
+ <Component :data="{ value: x }" /> <!-- New object every render -->
397
+
398
+ ❌ Large computed without caching
399
+ // Computed should be pure and efficient
400
+ const expensive = computed(() => {
401
+ // Heavy calculation on every access
402
+ })
403
+
404
+ ❌ Conditional composables
405
+ if (condition) {
406
+ const data = useData() // Wrong: must be at top level
407
+ }
408
+ ```
409
+
410
+ ## For /dev-specs
411
+
412
+ When writing specs for Vue 3 projects:
413
+
414
+ **Component Specs:**
415
+ - Define props (name, type, required, default)
416
+ - Define emits (event names, payload types)
417
+ - Specify state management approach (local, composable, Pinia)
418
+ - Identify if lazy loading needed
419
+ - Note if TypeScript types required
420
+
421
+ **State Management:**
422
+ - Clarify scope (local, composable, Pinia store)
423
+ - If Pinia: specify store name and location
424
+ - If composable: specify composable name and return shape
425
+
426
+ **Performance Requirements:**
427
+ - List optimization needs (lazy load, v-memo, shallow)
428
+ - Specify bundle size constraints
429
+
430
+ **Patterns to Use:**
431
+ - Composables for reusable logic
432
+ - Provide/inject for deep prop drilling
433
+ - Pinia stores for global state
434
+
435
+ ## For /dev-coding
436
+
437
+ When implementing Vue 3 features:
438
+
439
+ ### 1. Component Creation
440
+
441
+ **Start with:**
442
+ - Read tech-context.md for project's Vue patterns
443
+ - Check if TypeScript is used
444
+ - Identify state management approach (Pinia, composables)
445
+ - Check for UI library (Vuetify, PrimeVue, Element Plus, etc.)
446
+
447
+ **Structure:**
448
+ ```vue
449
+ <script setup lang="ts">
450
+ // 1. Imports
451
+ import { ref, computed, watch, onMounted } from 'vue'
452
+
453
+ // 2. Props & Emits
454
+ const props = defineProps<{
455
+ title: string
456
+ count: number
457
+ }>()
458
+
459
+ const emit = defineEmits<{
460
+ update: [value: number]
461
+ }>()
462
+
463
+ // 3. Composables
464
+ const { user, loading } = useAuth()
465
+
466
+ // 4. State
467
+ const localState = ref(0)
468
+ const derived = computed(() => localState.value * 2)
469
+
470
+ // 5. Methods
471
+ function handleClick() {
472
+ emit('update', localState.value)
473
+ }
474
+
475
+ // 6. Watchers
476
+ watch(() => props.count, (newVal) => {
477
+ localState.value = newVal
478
+ })
479
+
480
+ // 7. Lifecycle
481
+ onMounted(() => {
482
+ // Setup logic
483
+ })
484
+ </script>
485
+
486
+ <template>
487
+ <div>
488
+ <!-- Template -->
489
+ </div>
490
+ </template>
491
+
492
+ <style scoped>
493
+ /* Scoped styles */
494
+ </style>
495
+ ```
496
+
497
+ ### 2. State Management
498
+
499
+ **Choose based on scope:**
500
+ - **Local UI state** → ref(), reactive()
501
+ - **Reusable logic** → Composable (useX)
502
+ - **Feature-level** → Pinia store
503
+ - **Deep hierarchy** → provide/inject
504
+ - **Global config** → app.config.globalProperties
505
+
506
+ ### 3. Composables
507
+
508
+ **Create reusable logic:**
509
+ ```javascript
510
+ // composables/useCounter.js
511
+ import { ref, computed } from 'vue'
512
+
513
+ export function useCounter(initial = 0) {
514
+ const count = ref(initial)
515
+ const doubled = computed(() => count.value * 2)
516
+
517
+ function increment() {
518
+ count.value++
519
+ }
520
+
521
+ return { count, doubled, increment }
522
+ }
523
+
524
+ // Usage in component
525
+ const { count, doubled, increment } = useCounter(10)
526
+ ```
527
+
528
+ ### 4. Pinia Store
529
+
530
+ **Create feature store:**
531
+ ```javascript
532
+ // stores/auth.js
533
+ import { defineStore } from 'pinia'
534
+ import { ref, computed } from 'vue'
535
+
536
+ export const useAuthStore = defineStore('auth', () => {
537
+ // State
538
+ const user = ref(null)
539
+ const token = ref(null)
540
+
541
+ // Getters
542
+ const isAuthenticated = computed(() => !!token.value)
543
+
544
+ // Actions
545
+ async function login(credentials) {
546
+ const response = await api.login(credentials)
547
+ user.value = response.user
548
+ token.value = response.token
549
+ }
550
+
551
+ function logout() {
552
+ user.value = null
553
+ token.value = null
554
+ }
555
+
556
+ return { user, token, isAuthenticated, login, logout }
557
+ })
558
+ ```
559
+
560
+ ### 5. Common Patterns
561
+
562
+ **Fetch data:**
563
+ ```vue
564
+ <script setup>
565
+ import { ref, onMounted } from 'vue'
566
+
567
+ const data = ref(null)
568
+ const loading = ref(true)
569
+ const error = ref(null)
570
+
571
+ onMounted(async () => {
572
+ try {
573
+ data.value = await api.getData()
574
+ } catch (err) {
575
+ error.value = err
576
+ } finally {
577
+ loading.value = false
578
+ }
579
+ })
580
+ </script>
581
+
582
+ <template>
583
+ <div v-if="loading">Loading...</div>
584
+ <div v-else-if="error">Error: {{ error.message }}</div>
585
+ <div v-else>{{ data }}</div>
586
+ </template>
587
+ ```
588
+
589
+ **Form handling:**
590
+ ```vue
591
+ <script setup>
592
+ import { reactive, computed } from 'vue'
593
+
594
+ const form = reactive({
595
+ email: '',
596
+ password: ''
597
+ })
598
+
599
+ const errors = reactive({
600
+ email: '',
601
+ password: ''
602
+ })
603
+
604
+ const isValid = computed(() =>
605
+ form.email && form.password && !errors.email && !errors.password
606
+ )
607
+
608
+ function validateEmail() {
609
+ errors.email = form.email.includes('@') ? '' : 'Invalid email'
610
+ }
611
+
612
+ async function submit() {
613
+ if (!isValid.value) return
614
+ await api.login(form)
615
+ }
616
+ </script>
617
+
618
+ <template>
619
+ <form @submit.prevent="submit">
620
+ <input
621
+ v-model="form.email"
622
+ @blur="validateEmail"
623
+ :class="{ error: errors.email }"
624
+ >
625
+ <span v-if="errors.email">{{ errors.email }}</span>
626
+
627
+ <input v-model="form.password" type="password">
628
+
629
+ <button :disabled="!isValid">Login</button>
630
+ </form>
631
+ </template>
632
+ ```
633
+
634
+ ## For /dev-review
635
+
636
+ When reviewing Vue 3 code:
637
+
638
+ **Component Quality:**
639
+ - [ ] Uses `<script setup>` (not Options API)
640
+ - [ ] Props properly typed (TypeScript or PropType)
641
+ - [ ] Emits properly defined
642
+ - [ ] Component names are PascalCase
643
+ - [ ] SFC order: script → template → style
644
+
645
+ **Composition API:**
646
+ - [ ] Composables follow "use*" naming
647
+ - [ ] No conditional composable calls
648
+ - [ ] Composables called at top level of setup
649
+ - [ ] Reactive values returned from composables
650
+ - [ ] Cleanup handled (watchers, listeners)
651
+
652
+ **Reactivity:**
653
+ - [ ] ref() used for primitives
654
+ - [ ] reactive() used for objects
655
+ - [ ] .value accessed in script (not template)
656
+ - [ ] No destructuring reactive without toRefs
657
+ - [ ] No reassigning reactive objects
658
+ - [ ] computed() for derived state
659
+ - [ ] No complex logic in template
660
+
661
+ **Template:**
662
+ - [ ] v-for has unique :key
663
+ - [ ] No v-for + v-if on same element
664
+ - [ ] v-bind/v-on use shorthands (: and @)
665
+ - [ ] No inline objects/arrays (causes re-renders)
666
+ - [ ] Proper event naming (kebab-case)
667
+
668
+ **State Management:**
669
+ - [ ] Appropriate scope (local, composable, store)
670
+ - [ ] Props not mutated directly
671
+ - [ ] Emits used for child → parent
672
+ - [ ] Pinia stores follow composition pattern
673
+ - [ ] No Vuex (use Pinia)
674
+
675
+ **Performance:**
676
+ - [ ] Heavy components lazy loaded
677
+ - [ ] Large lists use stable keys
678
+ - [ ] v-memo used for expensive items
679
+ - [ ] No unnecessary reactivity (shallowRef/shallowReactive)
680
+ - [ ] Watchers cleaned up
681
+
682
+ **TypeScript:**
683
+ - [ ] Props typed properly
684
+ - [ ] Emits typed
685
+ - [ ] Composables return types defined
686
+ - [ ] No excessive use of any
687
+
688
+ ## Integration with Other Stacks
689
+
690
+ **Vue + Nuxt:**
691
+ - Follow Nuxt conventions (pages/, composables/, server/)
692
+ - Use auto-imports
693
+ - Use Nuxt composables (useAsyncData, useFetch, etc.)
694
+ - Follow SSR guidelines
695
+
696
+ **Vue + Vite:**
697
+ - Fast dev server with HMR
698
+ - Use Vite plugins
699
+ - Leverage Vite's optimized build
700
+
701
+ **Vue + TypeScript:**
702
+ - Use `<script setup lang="ts">`
703
+ - Define props with interface
704
+ - Type emits and composables
705
+ - Use generic components
706
+
707
+ **Vue + Pinia:**
708
+ - Composition-style stores
709
+ - TypeScript support built-in
710
+ - DevTools integration
711
+ - Hot module replacement
712
+
713
+ ## Common Gotchas
714
+
715
+ 1. **Ref .value**: Forgetting .value in script, adding .value in template
716
+ 2. **Destructuring Reactivity**: Losing reactivity when destructuring reactive()
717
+ 3. **Conditional Composables**: Calling composables inside if/loops
718
+ 4. **Props Mutation**: Mutating props directly instead of emitting
719
+ 5. **v-for Key**: Using index or missing key entirely
720
+ 6. **v-for + v-if**: Combining on same element (use computed filter)
721
+ 7. **Template Refs**: Accessing $refs before onMounted
722
+ 8. **Async Setup**: Can't use async setup() without Suspense
723
+
724
+ ## Vue 3 Features
725
+
726
+ **Composition API:**
727
+ - setup() and <script setup>
728
+ - Composables for logic reuse
729
+ - Better TypeScript support
730
+ - More flexible code organization
731
+
732
+ **New APIs:**
733
+ - Teleport (render outside component hierarchy)
734
+ - Fragments (multiple root nodes)
735
+ - Suspense (async component loading)
736
+ - defineAsyncComponent (lazy loading)
737
+
738
+ **Performance:**
739
+ - Faster reactivity system (Proxy-based)
740
+ - Smaller bundle size
741
+ - Better tree-shaking
742
+ - Optimized virtual DOM
743
+
744
+ ## Resources
745
+
746
+ - [Vue 3 Docs](https://vuejs.org) - Official documentation
747
+ - [Vue DevTools](https://devtools.vuejs.org) - Browser extension
748
+ - [Pinia](https://pinia.vuejs.org) - Official state management
749
+ - [Vue Router](https://router.vuejs.org) - Official router
750
+ - [Vite](https://vitejs.dev) - Recommended build tool