@pythoughts/vue-skills-mcp 0.1.0
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/README.md +63 -0
- package/index.mjs +139 -0
- package/package.json +34 -0
- package/skills/create-adaptable-composable/SKILL.md +76 -0
- package/skills/vue-best-practices/SKILL.md +154 -0
- package/skills/vue-best-practices/references/animation-class-based-technique.md +254 -0
- package/skills/vue-best-practices/references/animation-state-driven-technique.md +291 -0
- package/skills/vue-best-practices/references/component-async.md +97 -0
- package/skills/vue-best-practices/references/component-data-flow.md +350 -0
- package/skills/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
- package/skills/vue-best-practices/references/component-keep-alive.md +137 -0
- package/skills/vue-best-practices/references/component-slots.md +216 -0
- package/skills/vue-best-practices/references/component-suspense.md +228 -0
- package/skills/vue-best-practices/references/component-teleport.md +108 -0
- package/skills/vue-best-practices/references/component-transition-group.md +128 -0
- package/skills/vue-best-practices/references/component-transition.md +125 -0
- package/skills/vue-best-practices/references/composables.md +290 -0
- package/skills/vue-best-practices/references/directives.md +162 -0
- package/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
- package/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
- package/skills/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
- package/skills/vue-best-practices/references/plugins.md +166 -0
- package/skills/vue-best-practices/references/reactivity.md +346 -0
- package/skills/vue-best-practices/references/render-functions.md +201 -0
- package/skills/vue-best-practices/references/sfc.md +310 -0
- package/skills/vue-best-practices/references/state-management.md +135 -0
- package/skills/vue-best-practices/references/updated-hook-performance.md +187 -0
- package/skills/vue-debug-guides/SKILL.md +205 -0
- package/skills/vue-debug-guides/reference/animation-key-for-rerender.md +160 -0
- package/skills/vue-debug-guides/reference/animation-transitiongroup-performance.md +241 -0
- package/skills/vue-debug-guides/reference/async-component-error-handling.md +115 -0
- package/skills/vue-debug-guides/reference/async-component-keepalive-ref-issue.md +112 -0
- package/skills/vue-debug-guides/reference/async-component-suspense-control.md +84 -0
- package/skills/vue-debug-guides/reference/async-component-vue-router.md +109 -0
- package/skills/vue-debug-guides/reference/attrs-event-listener-merging.md +205 -0
- package/skills/vue-debug-guides/reference/checkbox-true-false-value-form-submission.md +118 -0
- package/skills/vue-debug-guides/reference/cleanup-side-effects.md +172 -0
- package/skills/vue-debug-guides/reference/click-events-on-components.md +180 -0
- package/skills/vue-debug-guides/reference/component-naming-conflicts.md +159 -0
- package/skills/vue-debug-guides/reference/component-ref-requires-defineexpose.md +176 -0
- package/skills/vue-debug-guides/reference/composable-avoid-hidden-side-effects.md +208 -0
- package/skills/vue-debug-guides/reference/composable-call-location-restrictions.md +141 -0
- package/skills/vue-debug-guides/reference/composable-naming-return-pattern.md +139 -0
- package/skills/vue-debug-guides/reference/composable-tovalue-inside-watcheffect.md +182 -0
- package/skills/vue-debug-guides/reference/composition-api-not-functional-programming.md +120 -0
- package/skills/vue-debug-guides/reference/composition-api-script-setup-async-context.md +203 -0
- package/skills/vue-debug-guides/reference/composition-api-vs-react-hooks-differences.md +156 -0
- package/skills/vue-debug-guides/reference/computed-array-mutation.md +148 -0
- package/skills/vue-debug-guides/reference/computed-conditional-dependencies.md +147 -0
- package/skills/vue-debug-guides/reference/computed-no-parameters.md +159 -0
- package/skills/vue-debug-guides/reference/computed-no-side-effects.md +107 -0
- package/skills/vue-debug-guides/reference/computed-return-value-readonly.md +160 -0
- package/skills/vue-debug-guides/reference/configure-app-before-mount.md +89 -0
- package/skills/vue-debug-guides/reference/declare-emits-for-documentation.md +212 -0
- package/skills/vue-debug-guides/reference/define-expose-before-await.md +192 -0
- package/skills/vue-debug-guides/reference/define-model-default-value-sync.md +139 -0
- package/skills/vue-debug-guides/reference/defineEmits-must-be-top-level.md +164 -0
- package/skills/vue-debug-guides/reference/defineEmits-no-runtime-and-type-mixed.md +170 -0
- package/skills/vue-debug-guides/reference/definemodel-object-mutation-no-emit.md +148 -0
- package/skills/vue-debug-guides/reference/dom-update-timing-nexttick.md +90 -0
- package/skills/vue-debug-guides/reference/dynamic-argument-constraints.md +146 -0
- package/skills/vue-debug-guides/reference/dynamic-component-registration-vite.md +147 -0
- package/skills/vue-debug-guides/reference/event-modifier-order-matters.md +101 -0
- package/skills/vue-debug-guides/reference/exact-modifier-for-precise-shortcuts.md +155 -0
- package/skills/vue-debug-guides/reference/fallthrough-attrs-overwrite-vue3.md +159 -0
- package/skills/vue-debug-guides/reference/in-dom-template-parsing-caveats.md +149 -0
- package/skills/vue-debug-guides/reference/inheritattrs-false-for-wrapper-components.md +230 -0
- package/skills/vue-debug-guides/reference/keepalive-router-nested-double-mount.md +222 -0
- package/skills/vue-debug-guides/reference/keepalive-transition-memory-leak.md +144 -0
- package/skills/vue-debug-guides/reference/keyup-modifier-timing.md +137 -0
- package/skills/vue-debug-guides/reference/lifecycle-dom-access-timing.md +216 -0
- package/skills/vue-debug-guides/reference/lifecycle-hooks-synchronous-registration.md +156 -0
- package/skills/vue-debug-guides/reference/lifecycle-ssr-awareness.md +184 -0
- package/skills/vue-debug-guides/reference/local-components-not-in-descendants.md +151 -0
- package/skills/vue-debug-guides/reference/mount-return-value.md +88 -0
- package/skills/vue-debug-guides/reference/multi-root-component-class-attrs.md +93 -0
- package/skills/vue-debug-guides/reference/native-event-collision-with-emits.md +162 -0
- package/skills/vue-debug-guides/reference/no-passive-with-prevent.md +141 -0
- package/skills/vue-debug-guides/reference/no-v-if-with-v-for.md +136 -0
- package/skills/vue-debug-guides/reference/perf-computed-object-stability.md +157 -0
- package/skills/vue-debug-guides/reference/perf-props-stability-update-optimization.md +140 -0
- package/skills/vue-debug-guides/reference/plugin-global-properties-sparingly.md +109 -0
- package/skills/vue-debug-guides/reference/plugin-install-before-mount.md +124 -0
- package/skills/vue-debug-guides/reference/plugin-prefer-provide-inject-over-global-properties.md +120 -0
- package/skills/vue-debug-guides/reference/plugin-typescript-type-augmentation.md +157 -0
- package/skills/vue-debug-guides/reference/prop-defineprops-scope-limitation.md +161 -0
- package/skills/vue-debug-guides/reference/provide-inject-debugging-challenges.md +203 -0
- package/skills/vue-debug-guides/reference/provide-inject-default-value-factory.md +244 -0
- package/skills/vue-debug-guides/reference/provide-inject-reactivity-not-automatic.md +226 -0
- package/skills/vue-debug-guides/reference/provide-inject-synchronous-setup.md +235 -0
- package/skills/vue-debug-guides/reference/reactive-destructuring.md +89 -0
- package/skills/vue-debug-guides/reference/reactivity-debugging-hooks.md +132 -0
- package/skills/vue-debug-guides/reference/reactivity-markraw-for-non-reactive.md +149 -0
- package/skills/vue-debug-guides/reference/reactivity-proxy-identity-hazard.md +96 -0
- package/skills/vue-debug-guides/reference/reactivity-same-tick-batching.md +166 -0
- package/skills/vue-debug-guides/reference/ref-value-access.md +61 -0
- package/skills/vue-debug-guides/reference/refs-in-collections-need-value.md +81 -0
- package/skills/vue-debug-guides/reference/render-function-avoid-internal-vnode-properties.md +151 -0
- package/skills/vue-debug-guides/reference/render-function-vnodes-must-be-unique.md +133 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-h-import-vue3.md +148 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-return-from-setup.md +148 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-slots-as-functions.md +168 -0
- package/skills/vue-debug-guides/reference/rendering-resolve-component-for-string-names.md +231 -0
- package/skills/vue-debug-guides/reference/select-initial-value-ios-bug.md +91 -0
- package/skills/vue-debug-guides/reference/self-referencing-component-name.md +157 -0
- package/skills/vue-debug-guides/reference/sfc-named-exports-forbidden.md +184 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-child-component-styling.md +156 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-dynamic-content.md +193 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-slot-content.md +242 -0
- package/skills/vue-debug-guides/reference/sfc-script-setup-reactivity.md +195 -0
- package/skills/vue-debug-guides/reference/slot-forwarding-to-child-components.md +143 -0
- package/skills/vue-debug-guides/reference/slot-implicit-default-content.md +155 -0
- package/skills/vue-debug-guides/reference/slot-name-reserved-prop.md +109 -0
- package/skills/vue-debug-guides/reference/slot-named-scoped-explicit-default.md +95 -0
- package/skills/vue-debug-guides/reference/slot-render-scope-parent-only.md +135 -0
- package/skills/vue-debug-guides/reference/slot-v-slot-on-components-or-templates-only.md +122 -0
- package/skills/vue-debug-guides/reference/ssr-hydration-mismatch-causes.md +280 -0
- package/skills/vue-debug-guides/reference/ssr-platform-specific-apis.md +256 -0
- package/skills/vue-debug-guides/reference/state-ssr-cross-request-pollution.md +276 -0
- package/skills/vue-debug-guides/reference/suspense-no-builtin-error-handling.md +127 -0
- package/skills/vue-debug-guides/reference/suspense-ssr-hydration-issues.md +159 -0
- package/skills/vue-debug-guides/reference/tailwind-dynamic-class-generation.md +144 -0
- package/skills/vue-debug-guides/reference/teleport-scoped-styles-limitation.md +191 -0
- package/skills/vue-debug-guides/reference/teleport-ssr-hydration.md +152 -0
- package/skills/vue-debug-guides/reference/teleport-target-must-exist.md +113 -0
- package/skills/vue-debug-guides/reference/template-expressions-restrictions.md +114 -0
- package/skills/vue-debug-guides/reference/template-functions-no-side-effects.md +187 -0
- package/skills/vue-debug-guides/reference/template-ref-null-with-v-if.md +123 -0
- package/skills/vue-debug-guides/reference/template-ref-unwrapping-top-level.md +104 -0
- package/skills/vue-debug-guides/reference/template-ref-v-for-order.md +172 -0
- package/skills/vue-debug-guides/reference/textarea-no-interpolation.md +72 -0
- package/skills/vue-debug-guides/reference/transition-group-flip-inline-elements.md +152 -0
- package/skills/vue-debug-guides/reference/transition-group-move-animation-position-absolute.md +130 -0
- package/skills/vue-debug-guides/reference/transition-group-no-default-wrapper-vue3.md +152 -0
- package/skills/vue-debug-guides/reference/transition-js-hooks-done-callback.md +251 -0
- package/skills/vue-debug-guides/reference/transition-nested-duration.md +182 -0
- package/skills/vue-debug-guides/reference/transition-reusable-scoped-style.md +245 -0
- package/skills/vue-debug-guides/reference/transition-router-view-appear.md +193 -0
- package/skills/vue-debug-guides/reference/transition-type-when-mixed.md +172 -0
- package/skills/vue-debug-guides/reference/transition-unmount-hook-timing.md +149 -0
- package/skills/vue-debug-guides/reference/ts-defineprops-boolean-default-false.md +225 -0
- package/skills/vue-debug-guides/reference/ts-defineprops-imported-types-limitations.md +281 -0
- package/skills/vue-debug-guides/reference/ts-event-handler-explicit-typing.md +213 -0
- package/skills/vue-debug-guides/reference/ts-reactive-no-generic-argument.md +196 -0
- package/skills/vue-debug-guides/reference/ts-shallowref-for-dynamic-components.md +218 -0
- package/skills/vue-debug-guides/reference/ts-template-ref-null-handling.md +249 -0
- package/skills/vue-debug-guides/reference/ts-template-type-casting.md +214 -0
- package/skills/vue-debug-guides/reference/ts-withdefaults-mutable-factory-function.md +171 -0
- package/skills/vue-debug-guides/reference/undeclared-emits-double-firing.md +195 -0
- package/skills/vue-debug-guides/reference/use-template-ref-vue35.md +158 -0
- package/skills/vue-debug-guides/reference/v-else-must-follow-v-if.md +136 -0
- package/skills/vue-debug-guides/reference/v-for-component-props.md +95 -0
- package/skills/vue-debug-guides/reference/v-for-computed-reverse-sort.md +86 -0
- package/skills/vue-debug-guides/reference/v-for-key-attribute.md +90 -0
- package/skills/vue-debug-guides/reference/v-for-range-starts-at-one.md +66 -0
- package/skills/vue-debug-guides/reference/v-if-null-check-order.md +171 -0
- package/skills/vue-debug-guides/reference/v-model-ignores-html-attributes.md +83 -0
- package/skills/vue-debug-guides/reference/v-model-ime-composition.md +83 -0
- package/skills/vue-debug-guides/reference/v-model-number-modifier-behavior.md +124 -0
- package/skills/vue-debug-guides/reference/v-show-template-limitation.md +124 -0
- package/skills/vue-debug-guides/reference/watch-async-cleanup.md +180 -0
- package/skills/vue-debug-guides/reference/watch-async-creation-memory-leak.md +176 -0
- package/skills/vue-debug-guides/reference/watch-deep-same-object-reference.md +165 -0
- package/skills/vue-debug-guides/reference/watch-flush-timing.md +189 -0
- package/skills/vue-debug-guides/reference/watch-reactive-property-getter.md +108 -0
- package/skills/vue-debug-guides/reference/watcheffect-async-dependency-tracking.md +173 -0
- package/skills/vue-debug-guides/reference/watcheffect-flush-post-for-refs.md +176 -0
- package/skills/vue-jsx-best-practices/SKILL.md +12 -0
- package/skills/vue-jsx-best-practices/reference/render-function-jsx-vue-vs-react.md +141 -0
- package/skills/vue-options-api-best-practices/SKILL.md +23 -0
- package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-lifecycle-hooks.md +95 -0
- package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-methods.md +68 -0
- package/skills/vue-options-api-best-practices/reference/stateful-methods-lifecycle.md +61 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-arrow-functions-validators.md +141 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-computed-return-types.md +192 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-proptype-complex-types.md +212 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-provide-inject-limitations.md +135 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-type-event-handlers.md +202 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-use-definecomponent.md +172 -0
- package/skills/vue-options-api-best-practices/reference/ts-strict-mode-options-api.md +197 -0
- package/skills/vue-pinia-best-practices/SKILL.md +21 -0
- package/skills/vue-pinia-best-practices/reference/pinia-no-active-pinia-error.md +248 -0
- package/skills/vue-pinia-best-practices/reference/pinia-setup-store-return-all-state.md +227 -0
- package/skills/vue-pinia-best-practices/reference/pinia-store-destructuring-breaks-reactivity.md +193 -0
- package/skills/vue-pinia-best-practices/reference/state-url-for-ephemeral-filters.md +238 -0
- package/skills/vue-pinia-best-practices/reference/state-use-pinia-for-large-apps.md +262 -0
- package/skills/vue-pinia-best-practices/reference/store-method-binding-parentheses.md +191 -0
- package/skills/vue-router-best-practices/SKILL.md +23 -0
- package/skills/vue-router-best-practices/reference/router-beforeenter-no-param-trigger.md +167 -0
- package/skills/vue-router-best-practices/reference/router-beforerouteenter-no-this.md +176 -0
- package/skills/vue-router-best-practices/reference/router-guard-async-await-pattern.md +227 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-infinite-loop.md +187 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-next-deprecated.md +150 -0
- package/skills/vue-router-best-practices/reference/router-param-change-no-lifecycle.md +181 -0
- package/skills/vue-router-best-practices/reference/router-simple-routing-cleanup.md +209 -0
- package/skills/vue-router-best-practices/reference/router-use-vue-router-for-production.md +183 -0
- package/skills/vue-testing-best-practices/SKILL.md +29 -0
- package/skills/vue-testing-best-practices/reference/async-component-testing.md +163 -0
- package/skills/vue-testing-best-practices/reference/teleport-testing-complexity.md +158 -0
- package/skills/vue-testing-best-practices/reference/testing-async-await-flushpromises.md +175 -0
- package/skills/vue-testing-best-practices/reference/testing-browser-vs-node-runners.md +208 -0
- package/skills/vue-testing-best-practices/reference/testing-component-blackbox-approach.md +144 -0
- package/skills/vue-testing-best-practices/reference/testing-composables-helper-wrapper.md +238 -0
- package/skills/vue-testing-best-practices/reference/testing-e2e-playwright-recommended.md +242 -0
- package/skills/vue-testing-best-practices/reference/testing-no-snapshot-only.md +197 -0
- package/skills/vue-testing-best-practices/reference/testing-pinia-store-setup.md +228 -0
- package/skills/vue-testing-best-practices/reference/testing-suspense-async-components.md +229 -0
- package/skills/vue-testing-best-practices/reference/testing-vitest-recommended-for-vue.md +204 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Select Element iOS Bug - Always Include Disabled Placeholder Option
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: On iOS, users cannot select the first option if v-model initial value doesn't match any option
|
|
5
|
+
type: capability
|
|
6
|
+
tags: [vue3, v-model, forms, select, ios, mobile, accessibility]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Select Element iOS Bug - Always Include Disabled Placeholder Option
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - When a `<select>` element's v-model initial value doesn't match any option, iOS renders it as "unselected" and users CANNOT select the first item. iOS doesn't fire a change event when selecting an already-visually-selected option, leaving users stuck.
|
|
12
|
+
|
|
13
|
+
This is a platform-specific bug that only manifests on iOS Safari. Desktop browsers and Android handle this gracefully, making it easy to miss during development. The fix is simple: always include a disabled placeholder option.
|
|
14
|
+
|
|
15
|
+
## Task Checklist
|
|
16
|
+
|
|
17
|
+
- [ ] Always add a disabled placeholder option with empty value to select elements
|
|
18
|
+
- [ ] Ensure v-model initial value is empty string to match the placeholder
|
|
19
|
+
- [ ] Test select inputs on iOS devices or simulators
|
|
20
|
+
- [ ] Consider this for any user-facing forms, especially on mobile-first apps
|
|
21
|
+
|
|
22
|
+
**Problem - iOS users cannot select first option:**
|
|
23
|
+
```html
|
|
24
|
+
<script setup>
|
|
25
|
+
import { ref } from 'vue'
|
|
26
|
+
|
|
27
|
+
// Initial value is empty string, doesn't match any option
|
|
28
|
+
const selected = ref('')
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<!-- PROBLEM: On iOS, "Apple" appears selected but user cannot actually select it -->
|
|
33
|
+
<!-- Tapping "Apple" does nothing because iOS doesn't fire change event -->
|
|
34
|
+
<select v-model="selected">
|
|
35
|
+
<option value="apple">Apple</option>
|
|
36
|
+
<option value="banana">Banana</option>
|
|
37
|
+
<option value="orange">Orange</option>
|
|
38
|
+
</select>
|
|
39
|
+
|
|
40
|
+
<!-- selected remains '' even though "Apple" appears highlighted -->
|
|
41
|
+
</template>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Solution - Add disabled placeholder option:**
|
|
45
|
+
```html
|
|
46
|
+
<script setup>
|
|
47
|
+
import { ref } from 'vue'
|
|
48
|
+
|
|
49
|
+
const selected = ref('') // Matches the placeholder option
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<template>
|
|
53
|
+
<!-- CORRECT: Disabled placeholder ensures user must actively select -->
|
|
54
|
+
<select v-model="selected">
|
|
55
|
+
<option disabled value="">Please select a fruit</option>
|
|
56
|
+
<option value="apple">Apple</option>
|
|
57
|
+
<option value="banana">Banana</option>
|
|
58
|
+
<option value="orange">Orange</option>
|
|
59
|
+
</select>
|
|
60
|
+
</template>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<!-- Variant with required attribute for form validation -->
|
|
65
|
+
<select v-model="selected" required>
|
|
66
|
+
<option disabled value="">-- Select an option --</option>
|
|
67
|
+
<option value="a">Option A</option>
|
|
68
|
+
<option value="b">Option B</option>
|
|
69
|
+
</select>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```html
|
|
73
|
+
<!-- If you MUST have a pre-selected default, set the initial value to match -->
|
|
74
|
+
<script setup>
|
|
75
|
+
import { ref } from 'vue'
|
|
76
|
+
|
|
77
|
+
// Set initial value to match an actual option
|
|
78
|
+
const country = ref('us') // Pre-selects "United States"
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<template>
|
|
82
|
+
<select v-model="country">
|
|
83
|
+
<option value="us">United States</option>
|
|
84
|
+
<option value="uk">United Kingdom</option>
|
|
85
|
+
<option value="ca">Canada</option>
|
|
86
|
+
</select>
|
|
87
|
+
</template>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Reference
|
|
91
|
+
- [Vue.js Form Input Bindings - Select](https://vuejs.org/guide/essentials/forms.html#select)
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Self-Referencing Components Use Filename as Implicit Name
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Understanding this avoids confusion with recursive components
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, component-registration, self-reference, recursive-components, sfc]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Self-Referencing Components Use Filename as Implicit Name
|
|
10
|
+
|
|
11
|
+
**Impact: LOW** - In Single-File Components (SFC), a component can reference itself in its own template using its filename as the component name. This is useful for recursive components like tree structures or nested comments. However, this implicit registration has lower priority than explicitly imported components, which can cause confusion.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Use the filename (without extension) to self-reference a component
|
|
16
|
+
- [ ] Be aware that imported components take precedence over self-reference
|
|
17
|
+
- [ ] For clarity in recursive components, consider explicit naming
|
|
18
|
+
|
|
19
|
+
**Example:**
|
|
20
|
+
```vue
|
|
21
|
+
<!-- TreeItem.vue -->
|
|
22
|
+
<script setup>
|
|
23
|
+
defineProps({
|
|
24
|
+
item: Object
|
|
25
|
+
})
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<template>
|
|
29
|
+
<div class="tree-item">
|
|
30
|
+
<span>{{ item.name }}</span>
|
|
31
|
+
<!-- Self-reference using filename -->
|
|
32
|
+
<TreeItem
|
|
33
|
+
v-for="child in item.children"
|
|
34
|
+
:key="child.id"
|
|
35
|
+
:item="child"
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```vue
|
|
42
|
+
<!-- Comment.vue - recursive comments -->
|
|
43
|
+
<script setup>
|
|
44
|
+
defineProps({
|
|
45
|
+
comment: Object
|
|
46
|
+
})
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<template>
|
|
50
|
+
<div class="comment">
|
|
51
|
+
<p>{{ comment.text }}</p>
|
|
52
|
+
<div class="replies" v-if="comment.replies?.length">
|
|
53
|
+
<!-- Self-reference for nested replies -->
|
|
54
|
+
<Comment
|
|
55
|
+
v-for="reply in comment.replies"
|
|
56
|
+
:key="reply.id"
|
|
57
|
+
:comment="reply"
|
|
58
|
+
/>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</template>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Priority: Imports Override Self-Reference
|
|
65
|
+
|
|
66
|
+
```vue
|
|
67
|
+
<!-- FooBar.vue -->
|
|
68
|
+
<script setup>
|
|
69
|
+
// If you import a component named FooBar, it takes precedence
|
|
70
|
+
import FooBar from './different/FooBar.vue'
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<template>
|
|
74
|
+
<!-- This renders the IMPORTED FooBar, not this file -->
|
|
75
|
+
<FooBar />
|
|
76
|
+
</template>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
To explicitly self-reference when there's a naming conflict:
|
|
80
|
+
|
|
81
|
+
```vue
|
|
82
|
+
<!-- FooBar.vue -->
|
|
83
|
+
<script setup>
|
|
84
|
+
import OtherFooBar from './different/FooBar.vue'
|
|
85
|
+
// No way to explicitly import "self" in script setup
|
|
86
|
+
// Must rename the import to avoid conflict
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
<template>
|
|
90
|
+
<OtherFooBar />
|
|
91
|
+
<!-- FooBar still refers to self (this file) because
|
|
92
|
+
the import was aliased -->
|
|
93
|
+
<FooBar />
|
|
94
|
+
</template>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Options API: Explicit Name Option
|
|
98
|
+
|
|
99
|
+
```vue
|
|
100
|
+
<!-- RecursiveList.vue -->
|
|
101
|
+
<script>
|
|
102
|
+
export default {
|
|
103
|
+
name: 'RecursiveList', // Explicit name for self-reference
|
|
104
|
+
props: {
|
|
105
|
+
items: Array
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<template>
|
|
111
|
+
<ul>
|
|
112
|
+
<li v-for="item in items" :key="item.id">
|
|
113
|
+
{{ item.name }}
|
|
114
|
+
<RecursiveList v-if="item.children" :items="item.children" />
|
|
115
|
+
</li>
|
|
116
|
+
</ul>
|
|
117
|
+
</template>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Common Use Cases for Self-Reference
|
|
121
|
+
|
|
122
|
+
1. **Tree structures** - File explorers, org charts
|
|
123
|
+
2. **Nested comments** - Reddit-style comment threads
|
|
124
|
+
3. **Menu navigation** - Recursive dropdown menus
|
|
125
|
+
4. **Category hierarchies** - Product categories, taxonomies
|
|
126
|
+
|
|
127
|
+
## Avoid Infinite Recursion
|
|
128
|
+
|
|
129
|
+
```vue
|
|
130
|
+
<!-- TreeNode.vue -->
|
|
131
|
+
<script setup>
|
|
132
|
+
defineProps({
|
|
133
|
+
node: Object,
|
|
134
|
+
maxDepth: { type: Number, default: 10 },
|
|
135
|
+
currentDepth: { type: Number, default: 0 }
|
|
136
|
+
})
|
|
137
|
+
</script>
|
|
138
|
+
|
|
139
|
+
<template>
|
|
140
|
+
<div class="node">
|
|
141
|
+
{{ node.name }}
|
|
142
|
+
<!-- Guard against infinite recursion -->
|
|
143
|
+
<template v-if="node.children && currentDepth < maxDepth">
|
|
144
|
+
<TreeNode
|
|
145
|
+
v-for="child in node.children"
|
|
146
|
+
:key="child.id"
|
|
147
|
+
:node="child"
|
|
148
|
+
:max-depth="maxDepth"
|
|
149
|
+
:current-depth="currentDepth + 1"
|
|
150
|
+
/>
|
|
151
|
+
</template>
|
|
152
|
+
</div>
|
|
153
|
+
</template>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Reference
|
|
157
|
+
- [Vue.js Component Registration](https://vuejs.org/guide/components/registration.html)
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: SFC Script Block Must Use Default Export Only
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Named exports in SFC script blocks will fail silently or cause build errors - Vue expects exactly one default export
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, sfc, export, script-block, composition-api]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# SFC Script Block Must Use Default Export Only
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - Vue Single-File Components expect exactly one default export from the `<script>` block. Using named exports for your component will cause build failures or runtime errors because Vue's tooling is designed to process a single default-exported component definition per `.vue` file.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Always use `export default` in `<script>` blocks (Options API)
|
|
16
|
+
- [ ] Use `<script setup>` which handles exports automatically (Composition API)
|
|
17
|
+
- [ ] Move shared utilities to separate `.js`/`.ts` files, not the component's script block
|
|
18
|
+
- [ ] If you need to export types, use a separate `<script>` block alongside `<script setup>`
|
|
19
|
+
|
|
20
|
+
**Problematic Code:**
|
|
21
|
+
```vue
|
|
22
|
+
<!-- MyComponent.vue -->
|
|
23
|
+
<script>
|
|
24
|
+
// BAD: Named exports don't work for the component itself
|
|
25
|
+
export const MyComponent = {
|
|
26
|
+
data() {
|
|
27
|
+
return { count: 0 }
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// BAD: Exporting multiple things from component script
|
|
32
|
+
export const CONSTANT = 42
|
|
33
|
+
export function helper() { }
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<div>{{ count }}</div>
|
|
38
|
+
</template>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Correct Code:**
|
|
42
|
+
```vue
|
|
43
|
+
<!-- MyComponent.vue - Options API -->
|
|
44
|
+
<script>
|
|
45
|
+
// GOOD: Single default export
|
|
46
|
+
export default {
|
|
47
|
+
data() {
|
|
48
|
+
return { count: 0 }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<template>
|
|
54
|
+
<div>{{ count }}</div>
|
|
55
|
+
</template>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```vue
|
|
59
|
+
<!-- MyComponent.vue - Composition API with script setup -->
|
|
60
|
+
<script setup>
|
|
61
|
+
// GOOD: No export needed, component is auto-exported
|
|
62
|
+
import { ref } from 'vue'
|
|
63
|
+
|
|
64
|
+
const count = ref(0)
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<template>
|
|
68
|
+
<div>{{ count }}</div>
|
|
69
|
+
</template>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Exporting Types Alongside Script Setup
|
|
73
|
+
|
|
74
|
+
For TypeScript, use a separate regular script block for type exports:
|
|
75
|
+
|
|
76
|
+
```vue
|
|
77
|
+
<script lang="ts">
|
|
78
|
+
// Regular script block for exports
|
|
79
|
+
export interface User {
|
|
80
|
+
id: number
|
|
81
|
+
name: string
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type Status = 'pending' | 'active' | 'inactive'
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<script setup lang="ts">
|
|
88
|
+
// Setup script for component logic
|
|
89
|
+
import { ref } from 'vue'
|
|
90
|
+
|
|
91
|
+
const users = ref<User[]>([])
|
|
92
|
+
</script>
|
|
93
|
+
|
|
94
|
+
<template>
|
|
95
|
+
<ul>
|
|
96
|
+
<li v-for="user in users" :key="user.id">{{ user.name }}</li>
|
|
97
|
+
</ul>
|
|
98
|
+
</template>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Sharing Utilities Across Components
|
|
102
|
+
|
|
103
|
+
Don't put shared code in component script blocks. Create separate files:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
// utils/constants.ts
|
|
107
|
+
export const ITEMS_PER_PAGE = 20
|
|
108
|
+
export const API_BASE_URL = '/api/v1'
|
|
109
|
+
|
|
110
|
+
// utils/helpers.ts
|
|
111
|
+
export function formatDate(date: Date): string {
|
|
112
|
+
return date.toLocaleDateString()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function formatCurrency(amount: number): string {
|
|
116
|
+
return `$${amount.toFixed(2)}`
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```vue
|
|
121
|
+
<!-- ProductList.vue -->
|
|
122
|
+
<script setup>
|
|
123
|
+
// GOOD: Import shared utilities from external files
|
|
124
|
+
import { ITEMS_PER_PAGE } from '@/utils/constants'
|
|
125
|
+
import { formatCurrency } from '@/utils/helpers'
|
|
126
|
+
import { ref } from 'vue'
|
|
127
|
+
|
|
128
|
+
const products = ref([])
|
|
129
|
+
</script>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Why This Restriction Exists
|
|
133
|
+
|
|
134
|
+
Vue's SFC compiler and build tools expect:
|
|
135
|
+
|
|
136
|
+
1. **One component per file**: The `.vue` file format is designed for single-component definitions
|
|
137
|
+
2. **Predictable structure**: Tools like Volar, vue-tsc, and bundler plugins assume default export
|
|
138
|
+
3. **Hot Module Replacement**: HMR relies on the single-component-per-file convention
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
// How Vue tooling processes SFCs internally
|
|
142
|
+
import MyComponent from './MyComponent.vue'
|
|
143
|
+
// ^ Always expects the default export to be the component
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Common Mistake: Reusing Code via SFC Exports
|
|
147
|
+
|
|
148
|
+
```vue
|
|
149
|
+
<!-- BAD PATTERN: Trying to reuse code from components -->
|
|
150
|
+
<script>
|
|
151
|
+
// This won't work as expected
|
|
152
|
+
export const sharedLogic = () => { ... }
|
|
153
|
+
|
|
154
|
+
export default {
|
|
155
|
+
// component definition
|
|
156
|
+
}
|
|
157
|
+
</script>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Instead, use composables:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
// composables/useSharedLogic.ts
|
|
164
|
+
export function useSharedLogic() {
|
|
165
|
+
// Shared reactive logic
|
|
166
|
+
const state = ref(0)
|
|
167
|
+
const increment = () => state.value++
|
|
168
|
+
|
|
169
|
+
return { state, increment }
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```vue
|
|
174
|
+
<!-- ComponentA.vue -->
|
|
175
|
+
<script setup>
|
|
176
|
+
import { useSharedLogic } from '@/composables/useSharedLogic'
|
|
177
|
+
|
|
178
|
+
const { state, increment } = useSharedLogic()
|
|
179
|
+
</script>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Reference
|
|
183
|
+
- [Vue.js SFC Specification](https://vuejs.org/api/sfc-spec.html)
|
|
184
|
+
- [Vue.js Composition API - Composables](https://vuejs.org/guide/reusability/composables.html)
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Deep Selectors for Styling Child Component Elements
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Scoped styles cannot target elements inside child components without deep selectors, leading to silently broken styles
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, sfc, scoped-css, deep-selector, child-components]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Use Deep Selectors for Styling Child Component Elements
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - When using scoped CSS in Vue SFCs, styles do not penetrate into child components. Without using deep selectors (`:deep()`), your styles will silently fail to apply to elements rendered by child components or third-party libraries.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Use `:deep()` selector to style elements inside child components
|
|
16
|
+
- [ ] Never use deprecated `>>>` or `/deep/` selectors (Vue 3 only supports `:deep()`)
|
|
17
|
+
- [ ] Scope deep selectors to a parent class when possible to limit impact
|
|
18
|
+
- [ ] Consider using unscoped styles or CSS modules for heavily nested styling
|
|
19
|
+
|
|
20
|
+
**Problematic Code:**
|
|
21
|
+
```vue
|
|
22
|
+
<template>
|
|
23
|
+
<div class="container">
|
|
24
|
+
<ThirdPartyDatePicker />
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<style scoped>
|
|
29
|
+
/* BAD: These styles won't apply to elements inside ThirdPartyDatePicker */
|
|
30
|
+
.container .date-input {
|
|
31
|
+
border-color: blue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.container .calendar-popup {
|
|
35
|
+
background: white;
|
|
36
|
+
}
|
|
37
|
+
</style>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Correct Code:**
|
|
41
|
+
```vue
|
|
42
|
+
<template>
|
|
43
|
+
<div class="container">
|
|
44
|
+
<ThirdPartyDatePicker />
|
|
45
|
+
</div>
|
|
46
|
+
</template>
|
|
47
|
+
|
|
48
|
+
<style scoped>
|
|
49
|
+
/* GOOD: Use :deep() to style child component elements */
|
|
50
|
+
.container :deep(.date-input) {
|
|
51
|
+
border-color: blue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.container :deep(.calendar-popup) {
|
|
55
|
+
background: white;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Also correct: deep selector at root level */
|
|
59
|
+
:deep(.date-picker-wrapper) {
|
|
60
|
+
padding: 1rem;
|
|
61
|
+
}
|
|
62
|
+
</style>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## How Scoped CSS Works
|
|
66
|
+
|
|
67
|
+
Vue scoped CSS adds a unique data attribute to all elements in the component's template and appends it to CSS selectors:
|
|
68
|
+
|
|
69
|
+
```vue
|
|
70
|
+
<!-- Template output -->
|
|
71
|
+
<div class="container" data-v-7ba5bd90>
|
|
72
|
+
<!-- Child component elements DON'T get data-v-7ba5bd90 -->
|
|
73
|
+
<div class="date-input">...</div>
|
|
74
|
+
</div>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```css
|
|
78
|
+
/* Generated scoped CSS */
|
|
79
|
+
.container[data-v-7ba5bd90] .date-input[data-v-7ba5bd90] { ... }
|
|
80
|
+
/* ^ This won't match because .date-input doesn't have the attribute */
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Vue 3 Deep Selector Syntax
|
|
84
|
+
|
|
85
|
+
```vue
|
|
86
|
+
<style scoped>
|
|
87
|
+
/* Vue 3 recommended syntax */
|
|
88
|
+
.parent :deep(.child-class) {
|
|
89
|
+
color: red;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* DEPRECATED - don't use these in Vue 3 */
|
|
93
|
+
.parent >>> .child-class { } /* Won't work in SCSS */
|
|
94
|
+
.parent /deep/ .child-class { } /* Deprecated */
|
|
95
|
+
.parent ::v-deep .child-class { } /* Old syntax */
|
|
96
|
+
</style>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Scoping Deep Selectors for Safety
|
|
100
|
+
|
|
101
|
+
Always scope `:deep()` to a parent selector to limit its reach:
|
|
102
|
+
|
|
103
|
+
```vue
|
|
104
|
+
<style scoped>
|
|
105
|
+
/* BAD: Affects ALL .btn elements in child components globally */
|
|
106
|
+
:deep(.btn) {
|
|
107
|
+
background: blue;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* GOOD: Only affects .btn inside .my-component */
|
|
111
|
+
.my-component :deep(.btn) {
|
|
112
|
+
background: blue;
|
|
113
|
+
}
|
|
114
|
+
</style>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Child Component Root Element Exception
|
|
118
|
+
|
|
119
|
+
Note: A child component's root element IS affected by parent scoped CSS. This is intentional for layout purposes:
|
|
120
|
+
|
|
121
|
+
```vue
|
|
122
|
+
<!-- Parent.vue -->
|
|
123
|
+
<template>
|
|
124
|
+
<ChildComponent class="styled-child" />
|
|
125
|
+
</template>
|
|
126
|
+
|
|
127
|
+
<style scoped>
|
|
128
|
+
/* This WILL work - targets child's root element */
|
|
129
|
+
.styled-child {
|
|
130
|
+
margin: 1rem;
|
|
131
|
+
border: 1px solid gray;
|
|
132
|
+
}
|
|
133
|
+
</style>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Performance Consideration
|
|
137
|
+
|
|
138
|
+
Using `:deep()` with element selectors can be slower:
|
|
139
|
+
|
|
140
|
+
```vue
|
|
141
|
+
<style scoped>
|
|
142
|
+
/* SLOWER: Element selector with deep */
|
|
143
|
+
.container :deep(p) {
|
|
144
|
+
color: red;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* FASTER: Class selector with deep */
|
|
148
|
+
.container :deep(.paragraph) {
|
|
149
|
+
color: red;
|
|
150
|
+
}
|
|
151
|
+
</style>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Reference
|
|
155
|
+
- [Vue.js Scoped CSS - Deep Selectors](https://vuejs.org/api/sfc-css-features.html#deep-selectors)
|
|
156
|
+
- [Vue Loader Scoped CSS](https://vue-loader.vuejs.org/guide/scoped-css.html)
|