mdk-skills 2.2.2 → 2.2.3
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.
- package/.claude/.install.log +9 -40
- package/.claude/backups/20260510.151953/.install.log +1 -0
- package/package.json +1 -1
- package/scripts/web-ui/server.js +8 -1
- package/.claude/backups/20260510.145547/.install.log +0 -18
- package/.claude/backups/20260510.145547/settings.json +0 -35
- package/.claude/backups/20260510.145547/skills/test1/.meta.json +0 -6
- package/.claude/backups/20260510.145547/skills/test2/.meta.json +0 -6
- package/.claude/backups/20260510.145651/.install.log +0 -19
- package/.claude/backups/20260510.145651/profiles.json +0 -67
- package/.claude/backups/20260510.145651/skills/frontend-code-review/.meta.json +0 -6
- package/.claude/backups/20260510.145651/skills/frontend-code-review/SKILL.md +0 -167
- package/.claude/backups/20260510.145651/skills/frontend-code-review/references/checklist.md +0 -298
- package/.claude/backups/20260510.145651/skills/frontend-design/.meta.json +0 -6
- package/.claude/backups/20260510.145651/skills/frontend-design/LICENSE.txt +0 -177
- package/.claude/backups/20260510.145651/skills/frontend-design/SKILL.md +0 -42
- package/.claude/backups/20260510.145651/skills/skill-creator/.meta.json +0 -6
- package/.claude/backups/20260510.145651/skills/skill-creator/SKILL.md +0 -356
- package/.claude/backups/20260510.145651/skills/skill-creator/references/output-patterns.md +0 -82
- package/.claude/backups/20260510.145651/skills/skill-creator/references/workflows.md +0 -28
- package/.claude/backups/20260510.145651/skills/skill-creator/scripts/init_skill.py +0 -303
- package/.claude/backups/20260510.145651/skills/skill-creator/scripts/package_skill.py +0 -110
- package/.claude/backups/20260510.145651/skills/skill-creator/scripts/quick_validate.py +0 -95
- package/.claude/backups/20260510.145651/skills/test1/.meta.json +0 -6
- package/.claude/backups/20260510.145651/skills/test2/.meta.json +0 -6
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/.meta.json +0 -6
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/SKILL.md +0 -228
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/charts.csv +0 -26
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/colors.csv +0 -97
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/landing.csv +0 -31
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/products.csv +0 -97
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/prompts.csv +0 -24
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/react.csv +0 -54
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/stacks/vue.csv +0 -50
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/styles.csv +0 -59
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/typography.csv +0 -58
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/scripts/core.py +0 -238
- package/.claude/backups/20260510.145651/skills/ui-ux-pro-max/scripts/search.py +0 -61
- package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/.meta.json +0 -6
- package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/SKILL.md +0 -26
- package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/references/infinite-scroll.md +0 -292
- package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/references/pinia-store.md +0 -174
- package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/references/service-layer.md +0 -198
- package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/references/tab-anchor.md +0 -1125
- package/.claude/backups/20260510.145651/skills/v3-fe-biz-patterns/references/use-loading.md +0 -114
- package/.claude/backups/20260510.145651/skills/vue/.meta.json +0 -6
- package/.claude/backups/20260510.145651/skills/vue/SKILL.md +0 -103
- package/.claude/backups/20260510.145651/skills/vue/references/components.md +0 -323
- package/.claude/backups/20260510.145651/skills/vue/references/composables.md +0 -358
- package/.claude/backups/20260510.145651/skills/vue/references/directives.md +0 -225
- package/.claude/backups/20260510.145651/skills/vue/references/gotchas.md +0 -438
- package/.claude/backups/20260510.145651/skills/vue/references/provide-inject.md +0 -174
- package/.claude/backups/20260510.145651/skills/vue/references/reactivity.md +0 -289
- package/.claude/backups/20260510.145651/skills/vue/references/router.md +0 -181
- package/.claude/backups/20260510.145651/skills/vue/references/testing.md +0 -294
- package/.claude/backups/20260510.145651/skills/vue/references/typescript.md +0 -172
- package/.claude/backups/20260510.145651/skills/vue/references/utils-client.md +0 -156
- package/.claude/backups/20260510.150310/.install.log +0 -30
- package/.claude/backups/20260510.150310/profiles.json +0 -67
- package/.claude/backups/20260510.150310/settings.json +0 -29
- package/.claude/backups/20260510.150310/skills/frontend-code-review/.meta.json +0 -6
- package/.claude/backups/20260510.150310/skills/frontend-code-review/SKILL.md +0 -167
- package/.claude/backups/20260510.150310/skills/frontend-code-review/references/checklist.md +0 -298
- package/.claude/backups/20260510.150310/skills/frontend-design/.meta.json +0 -6
- package/.claude/backups/20260510.150310/skills/frontend-design/LICENSE.txt +0 -177
- package/.claude/backups/20260510.150310/skills/frontend-design/SKILL.md +0 -42
- package/.claude/backups/20260510.150310/skills/skill-creator/.meta.json +0 -6
- package/.claude/backups/20260510.150310/skills/skill-creator/SKILL.md +0 -356
- package/.claude/backups/20260510.150310/skills/skill-creator/references/output-patterns.md +0 -82
- package/.claude/backups/20260510.150310/skills/skill-creator/references/workflows.md +0 -28
- package/.claude/backups/20260510.150310/skills/skill-creator/scripts/init_skill.py +0 -303
- package/.claude/backups/20260510.150310/skills/skill-creator/scripts/package_skill.py +0 -110
- package/.claude/backups/20260510.150310/skills/skill-creator/scripts/quick_validate.py +0 -95
- package/.claude/backups/20260510.150310/skills/test1/.meta.json +0 -6
- package/.claude/backups/20260510.150310/skills/test2/.meta.json +0 -6
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/.meta.json +0 -6
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/SKILL.md +0 -228
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/charts.csv +0 -26
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/colors.csv +0 -97
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/landing.csv +0 -31
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/products.csv +0 -97
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/prompts.csv +0 -24
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/react.csv +0 -54
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/stacks/vue.csv +0 -50
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/styles.csv +0 -59
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/typography.csv +0 -58
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/scripts/core.py +0 -238
- package/.claude/backups/20260510.150310/skills/ui-ux-pro-max/scripts/search.py +0 -61
- package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/.meta.json +0 -6
- package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/SKILL.md +0 -26
- package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/references/infinite-scroll.md +0 -292
- package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/references/pinia-store.md +0 -174
- package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/references/service-layer.md +0 -198
- package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/references/tab-anchor.md +0 -1125
- package/.claude/backups/20260510.150310/skills/v3-fe-biz-patterns/references/use-loading.md +0 -114
- package/.claude/backups/20260510.150310/skills/vue/.meta.json +0 -6
- package/.claude/backups/20260510.150310/skills/vue/SKILL.md +0 -103
- package/.claude/backups/20260510.150310/skills/vue/references/components.md +0 -323
- package/.claude/backups/20260510.150310/skills/vue/references/composables.md +0 -358
- package/.claude/backups/20260510.150310/skills/vue/references/directives.md +0 -225
- package/.claude/backups/20260510.150310/skills/vue/references/gotchas.md +0 -438
- package/.claude/backups/20260510.150310/skills/vue/references/provide-inject.md +0 -174
- package/.claude/backups/20260510.150310/skills/vue/references/reactivity.md +0 -289
- package/.claude/backups/20260510.150310/skills/vue/references/router.md +0 -181
- package/.claude/backups/20260510.150310/skills/vue/references/testing.md +0 -294
- package/.claude/backups/20260510.150310/skills/vue/references/typescript.md +0 -172
- package/.claude/backups/20260510.150310/skills/vue/references/utils-client.md +0 -156
- package/.claude/backups/CLAUDE.md.20260510.145155 +0 -131
- package/.claude/backups/CLAUDE.md.20260510.145651 +0 -131
- package/.claude/backups/CLAUDE.md.20260510.150310 +0 -131
- package/.claude/skills/test1/.meta.json +0 -6
- package/.claude/skills/test2/.meta.json +0 -6
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/profiles.json +0 -0
- /package/.claude/backups/{20260510.145651 → 20260510.151953}/settings.json +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/frontend-code-review/.meta.json +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/frontend-code-review/SKILL.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/frontend-code-review/references/checklist.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/frontend-design/.meta.json +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/frontend-design/LICENSE.txt +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/frontend-design/SKILL.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/.meta.json +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/SKILL.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/references/output-patterns.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/references/workflows.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/scripts/init_skill.py +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/scripts/package_skill.py +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/skill-creator/scripts/quick_validate.py +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/.meta.json +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/SKILL.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/charts.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/colors.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/landing.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/products.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/prompts.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/flutter.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/nextjs.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/react-native.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/react.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/svelte.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/swiftui.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/stacks/vue.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/styles.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/typography.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/data/ux-guidelines.csv +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/scripts/core.py +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/ui-ux-pro-max/scripts/search.py +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/.meta.json +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/SKILL.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/references/infinite-scroll.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/references/pinia-store.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/references/service-layer.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/references/tab-anchor.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/v3-fe-biz-patterns/references/use-loading.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/.meta.json +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/SKILL.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/components.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/composables.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/directives.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/gotchas.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/provide-inject.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/reactivity.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/router.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/testing.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/typescript.md +0 -0
- /package/.claude/backups/{20260510.145547 → 20260510.151953}/skills/vue/references/utils-client.md +0 -0
- /package/.claude/backups/{CLAUDE.md.20260510.144501 → CLAUDE.md.20260510.151953} +0 -0
|
@@ -1,438 +0,0 @@
|
|
|
1
|
-
# Vue Common Gotchas & Edge Cases
|
|
2
|
-
|
|
3
|
-
Critical Vue 3 gotchas that cause silent failures or hard-to-debug issues.
|
|
4
|
-
|
|
5
|
-
> Based on [vuejs-ai/skills](https://github.com/vuejs-ai/skills) vue-best-practices. For comprehensive coverage (200+ rules), see the upstream repo.
|
|
6
|
-
|
|
7
|
-
## Reactivity
|
|
8
|
-
|
|
9
|
-
### Always Use `.value` When Accessing ref() in Scripts
|
|
10
|
-
|
|
11
|
-
**Impact: HIGH** - Forgetting `.value` causes silent failures.
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
const count = ref(0)
|
|
15
|
-
|
|
16
|
-
// WRONG
|
|
17
|
-
count++ // Tries to increment the ref object
|
|
18
|
-
count = 5 // Reassigns variable, loses reactivity
|
|
19
|
-
items.push(4) // Error: push is not a function
|
|
20
|
-
|
|
21
|
-
// CORRECT
|
|
22
|
-
count.value++
|
|
23
|
-
count.value = 5
|
|
24
|
-
items.value.push(4)
|
|
25
|
-
|
|
26
|
-
// In templates - NO .value needed (Vue unwraps automatically)
|
|
27
|
-
// {{ count }} works, not {{ count.value }}
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### Never Destructure reactive() Objects Directly
|
|
31
|
-
|
|
32
|
-
**Impact: HIGH** - Destructuring breaks reactive connection.
|
|
33
|
-
|
|
34
|
-
```ts
|
|
35
|
-
const state = reactive({ count: 0, name: 'Vue' })
|
|
36
|
-
|
|
37
|
-
// WRONG - destructured variables lose reactivity
|
|
38
|
-
const { count, name } = state
|
|
39
|
-
state.count++
|
|
40
|
-
console.log(count) // Still 0!
|
|
41
|
-
|
|
42
|
-
// CORRECT - use toRefs()
|
|
43
|
-
const { count, name } = toRefs(state)
|
|
44
|
-
state.count++
|
|
45
|
-
console.log(count.value) // 1
|
|
46
|
-
|
|
47
|
-
// BEST - just use ref() instead of reactive()
|
|
48
|
-
const count = ref(0)
|
|
49
|
-
const name = ref('Vue')
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Proxy Identity Hazard with reactive()
|
|
53
|
-
|
|
54
|
-
```ts
|
|
55
|
-
const raw = {}
|
|
56
|
-
const proxy = reactive(raw)
|
|
57
|
-
|
|
58
|
-
// WRONG - comparing different objects
|
|
59
|
-
console.log(proxy === raw) // false
|
|
60
|
-
|
|
61
|
-
// WRONG - creating multiple proxies
|
|
62
|
-
const a = reactive({})
|
|
63
|
-
const b = reactive(a) // Returns same proxy
|
|
64
|
-
console.log(a === b) // true (same object)
|
|
65
|
-
|
|
66
|
-
// GOTCHA - nested objects get proxied too
|
|
67
|
-
const nested = reactive({ obj: {} })
|
|
68
|
-
console.log(nested.obj === nested.obj) // true (same proxy)
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Computed Properties
|
|
72
|
-
|
|
73
|
-
### No Side Effects in Computed Getters
|
|
74
|
-
|
|
75
|
-
**Impact: HIGH** - Side effects break reactivity model.
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
// WRONG - mutates state
|
|
79
|
-
const doubled = computed(() => {
|
|
80
|
-
count.value++ // Side effect!
|
|
81
|
-
return count.value * 2
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
// WRONG - async operation
|
|
85
|
-
const data = computed(async () => {
|
|
86
|
-
return await fetch('/api') // Side effect!
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
// CORRECT - pure computation only
|
|
90
|
-
const doubled = computed(() => count.value * 2)
|
|
91
|
-
|
|
92
|
-
// For side effects, use watch:
|
|
93
|
-
watch(count, (newVal) => {
|
|
94
|
-
document.title = `Count: ${newVal}`
|
|
95
|
-
})
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### Computed Returns Are Read-Only
|
|
99
|
-
|
|
100
|
-
```ts
|
|
101
|
-
const fullName = computed(() => `${first.value} ${last.value}`)
|
|
102
|
-
|
|
103
|
-
// WRONG - computed values are read-only
|
|
104
|
-
fullName.value = 'John Doe' // Error!
|
|
105
|
-
|
|
106
|
-
// CORRECT - use writable computed
|
|
107
|
-
const fullName = computed({
|
|
108
|
-
get: () => `${first.value} ${last.value}`,
|
|
109
|
-
set: (val) => {
|
|
110
|
-
const [f, l] = val.split(' ')
|
|
111
|
-
first.value = f
|
|
112
|
-
last.value = l
|
|
113
|
-
}
|
|
114
|
-
})
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## Watchers
|
|
118
|
-
|
|
119
|
-
### Clean Up Async Operations to Prevent Race Conditions
|
|
120
|
-
|
|
121
|
-
**Impact: HIGH** - Stale requests can overwrite newer data.
|
|
122
|
-
|
|
123
|
-
```ts
|
|
124
|
-
const query = ref('')
|
|
125
|
-
const results = ref([])
|
|
126
|
-
|
|
127
|
-
// WRONG - race condition
|
|
128
|
-
watch(query, async (q) => {
|
|
129
|
-
const res = await fetch(`/api?q=${q}`)
|
|
130
|
-
results.value = await res.json() // May overwrite newer results!
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
// CORRECT - use onWatcherCleanup (Vue 3.5+)
|
|
134
|
-
watch(query, async (q) => {
|
|
135
|
-
const controller = new AbortController()
|
|
136
|
-
onWatcherCleanup(() => controller.abort())
|
|
137
|
-
|
|
138
|
-
try {
|
|
139
|
-
const res = await fetch(`/api?q=${q}`, { signal: controller.signal })
|
|
140
|
-
results.value = await res.json()
|
|
141
|
-
} catch (e) {
|
|
142
|
-
if (e.name !== 'AbortError') throw e
|
|
143
|
-
}
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
// Or use onCleanup parameter
|
|
147
|
-
watch(query, async (q, oldQ, onCleanup) => {
|
|
148
|
-
const controller = new AbortController()
|
|
149
|
-
onCleanup(() => controller.abort())
|
|
150
|
-
// ... same as above
|
|
151
|
-
})
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### Deep Watch Returns Same Object Reference
|
|
155
|
-
|
|
156
|
-
```ts
|
|
157
|
-
const obj = reactive({ nested: { count: 0 } })
|
|
158
|
-
|
|
159
|
-
// GOTCHA - oldValue === newValue for deep watches
|
|
160
|
-
watch(obj, (newVal, oldVal) => {
|
|
161
|
-
console.log(newVal === oldVal) // true! Same object
|
|
162
|
-
}, { deep: true })
|
|
163
|
-
|
|
164
|
-
// If you need old value, clone first:
|
|
165
|
-
watch(
|
|
166
|
-
() => structuredClone(obj),
|
|
167
|
-
(newVal, oldVal) => { /* now different */ }
|
|
168
|
-
)
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
## Props
|
|
172
|
-
|
|
173
|
-
### Props Are Read-Only - Never Mutate
|
|
174
|
-
|
|
175
|
-
**Impact: HIGH** - Breaks one-way data flow.
|
|
176
|
-
|
|
177
|
-
```ts
|
|
178
|
-
const props = defineProps<{ count: number; user: User }>()
|
|
179
|
-
|
|
180
|
-
// WRONG - direct mutation
|
|
181
|
-
props.count++ // Vue warning
|
|
182
|
-
props.user.name = 'New' // No warning but still wrong!
|
|
183
|
-
|
|
184
|
-
// CORRECT - emit to parent
|
|
185
|
-
const emit = defineEmits(['update:count', 'update-user'])
|
|
186
|
-
emit('update:count', props.count + 1)
|
|
187
|
-
emit('update-user', { ...props.user, name: 'New' })
|
|
188
|
-
|
|
189
|
-
// Or create local copy
|
|
190
|
-
const localUser = ref({ ...props.user })
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### Destructured Props Don't Update Watchers (pre-3.5)
|
|
194
|
-
|
|
195
|
-
```ts
|
|
196
|
-
// WRONG (Vue < 3.5)
|
|
197
|
-
const { count } = defineProps<{ count: number }>()
|
|
198
|
-
watch(count, () => {}) // Won't trigger!
|
|
199
|
-
|
|
200
|
-
// CORRECT - use getter
|
|
201
|
-
const props = defineProps<{ count: number }>()
|
|
202
|
-
watch(() => props.count, () => {})
|
|
203
|
-
|
|
204
|
-
// Vue 3.5+ - destructuring works with reactive props
|
|
205
|
-
const { count } = defineProps<{ count: number }>()
|
|
206
|
-
watch(() => count, () => {}) // Works in 3.5+
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
## Lifecycle Hooks
|
|
210
|
-
|
|
211
|
-
### Register Hooks Synchronously During Setup
|
|
212
|
-
|
|
213
|
-
**Impact: HIGH** - Async hooks silently fail.
|
|
214
|
-
|
|
215
|
-
```ts
|
|
216
|
-
// WRONG - hook registered after await
|
|
217
|
-
async setup() {
|
|
218
|
-
const data = await fetchData()
|
|
219
|
-
onMounted(() => {}) // Will NEVER run!
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// WRONG - hook in setTimeout
|
|
223
|
-
setup() {
|
|
224
|
-
setTimeout(() => {
|
|
225
|
-
onMounted(() => {}) // Will NEVER run!
|
|
226
|
-
}, 100)
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// CORRECT - register synchronously, async inside
|
|
230
|
-
setup() {
|
|
231
|
-
onMounted(async () => {
|
|
232
|
-
const data = await fetchData()
|
|
233
|
-
})
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
## Templates
|
|
238
|
-
|
|
239
|
-
### Never Use v-if with v-for on Same Element
|
|
240
|
-
|
|
241
|
-
**Impact: HIGH** - Vue 2/3 precedence differs.
|
|
242
|
-
|
|
243
|
-
```vue
|
|
244
|
-
<!-- WRONG - ambiguous precedence -->
|
|
245
|
-
<li v-for="user in users" v-if="user.active" :key="user.id">
|
|
246
|
-
|
|
247
|
-
<!-- Vue 3: v-if runs FIRST, 'user' undefined! -->
|
|
248
|
-
|
|
249
|
-
<!-- CORRECT - computed filter -->
|
|
250
|
-
<li v-for="user in activeUsers" :key="user.id">
|
|
251
|
-
|
|
252
|
-
<script setup>
|
|
253
|
-
const activeUsers = computed(() => users.filter(u => u.active))
|
|
254
|
-
</script>
|
|
255
|
-
|
|
256
|
-
<!-- CORRECT - template wrapper -->
|
|
257
|
-
<template v-for="user in users" :key="user.id">
|
|
258
|
-
<li v-if="user.active">{{ user.name }}</li>
|
|
259
|
-
</template>
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### Template Refs Are Null with v-if
|
|
263
|
-
|
|
264
|
-
```ts
|
|
265
|
-
const inputRef = ref<HTMLInputElement | null>(null)
|
|
266
|
-
|
|
267
|
-
// GOTCHA - ref is null when element hidden
|
|
268
|
-
<input v-if="show" ref="inputRef" />
|
|
269
|
-
|
|
270
|
-
// WRONG - may be null
|
|
271
|
-
inputRef.value.focus() // Error if !show
|
|
272
|
-
|
|
273
|
-
// CORRECT - null check
|
|
274
|
-
inputRef.value?.focus()
|
|
275
|
-
|
|
276
|
-
// Or use watchEffect with flush: 'post'
|
|
277
|
-
watchEffect(() => {
|
|
278
|
-
inputRef.value?.focus()
|
|
279
|
-
}, { flush: 'post' })
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
## defineModel
|
|
283
|
-
|
|
284
|
-
### Object Mutations Don't Emit
|
|
285
|
-
|
|
286
|
-
```ts
|
|
287
|
-
const model = defineModel<{ name: string }>()
|
|
288
|
-
|
|
289
|
-
// WRONG - mutation doesn't notify parent
|
|
290
|
-
model.value.name = 'New' // Parent won't know!
|
|
291
|
-
|
|
292
|
-
// CORRECT - replace entire object
|
|
293
|
-
model.value = { ...model.value, name: 'New' }
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
### Updated Value Needs nextTick
|
|
297
|
-
|
|
298
|
-
```ts
|
|
299
|
-
const model = defineModel<string>()
|
|
300
|
-
|
|
301
|
-
// WRONG - value not updated yet
|
|
302
|
-
model.value = 'new'
|
|
303
|
-
console.log(model.value) // Still old value!
|
|
304
|
-
|
|
305
|
-
// CORRECT - wait for nextTick
|
|
306
|
-
model.value = 'new'
|
|
307
|
-
await nextTick()
|
|
308
|
-
console.log(model.value) // Now 'new'
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
## Component Events
|
|
312
|
-
|
|
313
|
-
### Undeclared Emits Can Fire Twice
|
|
314
|
-
|
|
315
|
-
```ts
|
|
316
|
-
// WRONG - missing emit declaration causes double firing
|
|
317
|
-
const emit = defineEmits([]) // 'click' not declared
|
|
318
|
-
<button @click="emit('click')"> // Fires twice!
|
|
319
|
-
|
|
320
|
-
// CORRECT - declare all custom events
|
|
321
|
-
const emit = defineEmits(['click'])
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
### Events Don't Bubble Through Components
|
|
325
|
-
|
|
326
|
-
```vue
|
|
327
|
-
<!-- Parent can't listen to grandchild events directly -->
|
|
328
|
-
<Grandparent>
|
|
329
|
-
<Parent>
|
|
330
|
-
<Child @custom="handler" /> <!-- Only Parent can listen -->
|
|
331
|
-
</Parent>
|
|
332
|
-
</Grandparent>
|
|
333
|
-
|
|
334
|
-
<!-- Solution: re-emit or use provide/inject -->
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
## Provide/Inject
|
|
338
|
-
|
|
339
|
-
### Reactivity Not Automatic
|
|
340
|
-
|
|
341
|
-
```ts
|
|
342
|
-
// Provider
|
|
343
|
-
const count = ref(0)
|
|
344
|
-
provide('count', count) // Pass the ref, not .value
|
|
345
|
-
|
|
346
|
-
// Consumer
|
|
347
|
-
const count = inject('count') // Receives the ref
|
|
348
|
-
console.log(count.value) // Reactive!
|
|
349
|
-
|
|
350
|
-
// WRONG - loses reactivity
|
|
351
|
-
provide('count', count.value) // Just passes number
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
### Must Call Provide Synchronously
|
|
355
|
-
|
|
356
|
-
```ts
|
|
357
|
-
// WRONG - provide after async
|
|
358
|
-
async setup() {
|
|
359
|
-
await fetchData()
|
|
360
|
-
provide('key', value) // Silently fails!
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// CORRECT
|
|
364
|
-
setup() {
|
|
365
|
-
provide('key', value) // Synchronous
|
|
366
|
-
onMounted(async () => {
|
|
367
|
-
await fetchData()
|
|
368
|
-
})
|
|
369
|
-
}
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
## SSR
|
|
373
|
-
|
|
374
|
-
### Lifecycle Hooks Don't Run on Server
|
|
375
|
-
|
|
376
|
-
```ts
|
|
377
|
-
// onMounted, onUpdated, onUnmounted - client only
|
|
378
|
-
onMounted(() => {
|
|
379
|
-
// Only runs in browser
|
|
380
|
-
window.addEventListener('resize', handler)
|
|
381
|
-
})
|
|
382
|
-
|
|
383
|
-
// For SSR, use onServerPrefetch for data
|
|
384
|
-
onServerPrefetch(async () => {
|
|
385
|
-
data.value = await fetchData()
|
|
386
|
-
})
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
### Hydration Mismatch Causes
|
|
390
|
-
|
|
391
|
-
Common causes:
|
|
392
|
-
|
|
393
|
-
- Browser-only APIs (`window`, `localStorage`)
|
|
394
|
-
- Different timestamps
|
|
395
|
-
- Random values
|
|
396
|
-
- User-agent specific rendering
|
|
397
|
-
|
|
398
|
-
```ts
|
|
399
|
-
// WRONG
|
|
400
|
-
const width = ref(window.innerWidth) // undefined on server
|
|
401
|
-
|
|
402
|
-
// CORRECT
|
|
403
|
-
const width = ref(0)
|
|
404
|
-
onMounted(() => {
|
|
405
|
-
width.value = window.innerWidth
|
|
406
|
-
})
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
## Performance
|
|
410
|
-
|
|
411
|
-
### Use shallowRef for Large Non-Reactive Data
|
|
412
|
-
|
|
413
|
-
```ts
|
|
414
|
-
// WRONG - deep reactivity overhead
|
|
415
|
-
const hugeList = ref(thousandsOfItems)
|
|
416
|
-
|
|
417
|
-
// CORRECT - only track .value assignment
|
|
418
|
-
const hugeList = shallowRef(thousandsOfItems)
|
|
419
|
-
|
|
420
|
-
// Trigger update by replacing entire array
|
|
421
|
-
hugeList.value = [...hugeList.value, newItem]
|
|
422
|
-
```
|
|
423
|
-
|
|
424
|
-
### markRaw for Non-Reactive Objects
|
|
425
|
-
|
|
426
|
-
```ts
|
|
427
|
-
// WRONG - Chart.js instance becomes reactive (breaks it)
|
|
428
|
-
const chart = ref(new Chart(ctx, config))
|
|
429
|
-
|
|
430
|
-
// CORRECT - mark as non-reactive
|
|
431
|
-
const chart = ref(markRaw(new Chart(ctx, config)))
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
## References
|
|
435
|
-
|
|
436
|
-
- [vuejs-ai/skills vue-best-practices](https://github.com/vuejs-ai/skills/tree/main/skills/vue-best-practices) - Full 200+ rules
|
|
437
|
-
- [Vue Style Guide](https://vuejs.org/style-guide/)
|
|
438
|
-
- [Vue 3 Migration Guide](https://v3-migration.vuejs.org/)
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Provide / Inject
|
|
3
|
-
description: Pass data through component tree without prop drilling
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Provide / Inject
|
|
7
|
-
|
|
8
|
-
Provide data from ancestor components to any descendant, avoiding prop drilling.
|
|
9
|
-
|
|
10
|
-
## Basic Usage
|
|
11
|
-
|
|
12
|
-
```vue
|
|
13
|
-
<!-- Provider.vue -->
|
|
14
|
-
<script setup lang="ts">
|
|
15
|
-
import { provide, ref } from 'vue'
|
|
16
|
-
|
|
17
|
-
const message = ref('hello')
|
|
18
|
-
provide('message', message)
|
|
19
|
-
</script>
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
```vue
|
|
23
|
-
<!-- DeepChild.vue (any level deep) -->
|
|
24
|
-
<script setup lang="ts">
|
|
25
|
-
import { inject } from 'vue'
|
|
26
|
-
|
|
27
|
-
const message = inject('message')
|
|
28
|
-
</script>
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Typing with InjectionKey
|
|
32
|
-
|
|
33
|
-
Use `InjectionKey` for type safety between provider and injector:
|
|
34
|
-
|
|
35
|
-
```ts
|
|
36
|
-
// keys.ts
|
|
37
|
-
import type { InjectionKey, Ref } from 'vue'
|
|
38
|
-
|
|
39
|
-
export const messageKey = Symbol() as InjectionKey<Ref<string>>
|
|
40
|
-
export const countKey = Symbol() as InjectionKey<number>
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
```vue
|
|
44
|
-
<!-- Provider.vue -->
|
|
45
|
-
<script setup lang="ts">
|
|
46
|
-
import { provide, ref } from 'vue'
|
|
47
|
-
import { messageKey } from './keys'
|
|
48
|
-
|
|
49
|
-
const message = ref('hello')
|
|
50
|
-
provide(messageKey, message)
|
|
51
|
-
</script>
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
```vue
|
|
55
|
-
<!-- Injector.vue -->
|
|
56
|
-
<script setup lang="ts">
|
|
57
|
-
import { inject } from 'vue'
|
|
58
|
-
import { messageKey } from './keys'
|
|
59
|
-
|
|
60
|
-
const message = inject(messageKey) // Ref<string> | undefined
|
|
61
|
-
</script>
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## Default Values
|
|
65
|
-
|
|
66
|
-
```ts
|
|
67
|
-
// Simple default
|
|
68
|
-
const value = inject('message', 'default value')
|
|
69
|
-
|
|
70
|
-
// Factory function (for expensive defaults)
|
|
71
|
-
const value = inject('key', () => new ExpensiveClass(), true)
|
|
72
|
-
// ^ treat as factory
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## App-Level Provide
|
|
76
|
-
|
|
77
|
-
Available to all components:
|
|
78
|
-
|
|
79
|
-
```ts
|
|
80
|
-
// main.ts
|
|
81
|
-
import { createApp } from 'vue'
|
|
82
|
-
|
|
83
|
-
const app = createApp(App)
|
|
84
|
-
app.provide('globalConfig', { theme: 'dark' })
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## Reactive Provide/Inject
|
|
88
|
-
|
|
89
|
-
Provide reactive values for automatic updates:
|
|
90
|
-
|
|
91
|
-
```vue
|
|
92
|
-
<!-- Provider.vue -->
|
|
93
|
-
<script setup lang="ts">
|
|
94
|
-
import { provide, ref } from 'vue'
|
|
95
|
-
|
|
96
|
-
const count = ref(0)
|
|
97
|
-
provide('count', count)
|
|
98
|
-
</script>
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
The injected value maintains reactivity connection.
|
|
102
|
-
|
|
103
|
-
## Mutations Best Practice
|
|
104
|
-
|
|
105
|
-
Keep mutations in the provider, expose update functions:
|
|
106
|
-
|
|
107
|
-
```vue
|
|
108
|
-
<!-- Provider.vue -->
|
|
109
|
-
<script setup lang="ts">
|
|
110
|
-
import { provide, ref, readonly } from 'vue'
|
|
111
|
-
|
|
112
|
-
const location = ref('North Pole')
|
|
113
|
-
|
|
114
|
-
function updateLocation(newLocation: string) {
|
|
115
|
-
location.value = newLocation
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
provide('location', {
|
|
119
|
-
location: readonly(location), // Prevent direct mutation
|
|
120
|
-
updateLocation
|
|
121
|
-
})
|
|
122
|
-
</script>
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
```vue
|
|
126
|
-
<!-- Injector.vue -->
|
|
127
|
-
<script setup lang="ts">
|
|
128
|
-
import { inject } from 'vue'
|
|
129
|
-
|
|
130
|
-
const { location, updateLocation } = inject('location')!
|
|
131
|
-
</script>
|
|
132
|
-
|
|
133
|
-
<template>
|
|
134
|
-
<button @click="updateLocation('South Pole')">
|
|
135
|
-
{{ location }}
|
|
136
|
-
</button>
|
|
137
|
-
</template>
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## Using Symbol Keys
|
|
141
|
-
|
|
142
|
-
Recommended for libraries and large apps to avoid collisions:
|
|
143
|
-
|
|
144
|
-
```ts
|
|
145
|
-
// keys.ts
|
|
146
|
-
export const myKey = Symbol('myKey')
|
|
147
|
-
|
|
148
|
-
// provider
|
|
149
|
-
provide(myKey, value)
|
|
150
|
-
|
|
151
|
-
// injector
|
|
152
|
-
inject(myKey)
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
## Type Helpers
|
|
156
|
-
|
|
157
|
-
```ts
|
|
158
|
-
// String key with explicit type
|
|
159
|
-
const foo = inject<string>('foo')
|
|
160
|
-
// ^? string | undefined
|
|
161
|
-
|
|
162
|
-
// With default (removes undefined)
|
|
163
|
-
const foo = inject<string>('foo', 'default')
|
|
164
|
-
// ^? string
|
|
165
|
-
|
|
166
|
-
// Force non-undefined (use when certain it's provided)
|
|
167
|
-
const foo = inject('foo') as string
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
<!--
|
|
171
|
-
Source references:
|
|
172
|
-
- https://vuejs.org/guide/components/provide-inject.html
|
|
173
|
-
- https://vuejs.org/guide/typescript/composition-api.html#typing-provide-inject
|
|
174
|
-
-->
|