|
| 1 | +--- |
| 2 | +name: vue-best-practices |
| 3 | +description: MUST be used for Vue.js tasks. Strongly recommends Composition API with `<script setup>` and TypeScript as the standard approach. Covers Vue 3, SSR, Volar, vue-tsc. Load for any Vue, .vue files, Vue Router, Pinia, or Vite with Vue work. ALWAYS use Composition API unless the project explicitly requires Options API. |
| 4 | +license: MIT |
| 5 | +metadata: |
| 6 | + author: github.com/vuejs-ai |
| 7 | + version: '18.0.0' |
| 8 | +--- |
| 9 | + |
| 10 | +# Vue Best Practices Workflow |
| 11 | + |
| 12 | +Use this skill as an instruction set. Follow the workflow in order unless the user explicitly asks for a different order. |
| 13 | + |
| 14 | +## Core Principles |
| 15 | + |
| 16 | +- **Keep state predictable:** one source of truth, derive everything else. |
| 17 | +- **Make data flow explicit:** Props down, Events up for most cases. |
| 18 | +- **Favor small, focused components:** easier to test, reuse, and maintain. |
| 19 | +- **Avoid unnecessary re-renders:** use computed properties and watchers wisely. |
| 20 | +- **Readability counts:** write clear, self-documenting code. |
| 21 | + |
| 22 | +## 1) Confirm architecture before coding (required) |
| 23 | + |
| 24 | +- Default stack: Vue 3 + Composition API + `<script setup lang="ts">`. |
| 25 | +- If the project explicitly uses Options API, load `vue-options-api-best-practices` skill if available. |
| 26 | +- If the project explicitly uses JSX, load `vue-jsx-best-practices` skill if available. |
| 27 | + |
| 28 | +### 1.1 Must-read core references (required) |
| 29 | + |
| 30 | +- Before implementing any Vue task, make sure to read and apply these core references: |
| 31 | + - `references/reactivity.md` |
| 32 | + - `references/sfc.md` |
| 33 | + - `references/component-data-flow.md` |
| 34 | + - `references/composables.md` |
| 35 | +- Keep these references in active working context for the entire task, not only when a specific issue appears. |
| 36 | + |
| 37 | +### 1.2 Plan component boundaries before coding (required) |
| 38 | + |
| 39 | +Create a brief component map before implementation for any non-trivial feature. |
| 40 | + |
| 41 | +- Define each component's single responsibility in one sentence. |
| 42 | +- Keep entry/root and route-level view components as composition surfaces by default. |
| 43 | +- Move feature UI and feature logic out of entry/root/view components unless the task is intentionally a tiny single-file demo. |
| 44 | +- Define props/emits contracts for each child component in the map. |
| 45 | +- Prefer a feature folder layout (`components/<feature>/...`, `composables/use<Feature>.ts`) when adding more than one component. |
| 46 | + |
| 47 | +## 2) Apply essential Vue foundations (required) |
| 48 | + |
| 49 | +These are essential, must-know foundations. Apply all of them in every Vue task using the core references already loaded in section `1.1`. |
| 50 | + |
| 51 | +### Reactivity |
| 52 | + |
| 53 | +- Must-read reference from `1.1`: [reactivity](references/reactivity.md) |
| 54 | +- Keep source state minimal (`ref`/`reactive`), derive everything possible with `computed`. |
| 55 | +- Use watchers for side effects if needed. |
| 56 | +- Avoid recomputing expensive logic in templates. |
| 57 | + |
| 58 | +### SFC structure and template safety |
| 59 | + |
| 60 | +- Must-read reference from `1.1`: [sfc](references/sfc.md) |
| 61 | +- Keep SFC sections in this order: `<script>` → `<template>` → `<style>`. |
| 62 | +- Keep SFC responsibilities focused; split large components. |
| 63 | +- Keep templates declarative; move branching/derivation to script. |
| 64 | +- Apply Vue template safety rules (`v-html`, list rendering, conditional rendering choices). |
| 65 | + |
| 66 | +### Keep components focused |
| 67 | + |
| 68 | +Split a component when it has **more than one clear responsibility** (e.g. data orchestration + UI, or multiple independent UI sections). |
| 69 | + |
| 70 | +- Prefer **smaller components + composables** over one “mega component” |
| 71 | +- Move **UI sections** into child components (props in, events out). |
| 72 | +- Move **state/side effects** into composables (`useXxx()`). |
| 73 | + |
| 74 | +Apply objective split triggers. Split the component if **any** condition is true: |
| 75 | + |
| 76 | +- It owns both orchestration/state and substantial presentational markup for multiple sections. |
| 77 | +- It has 3+ distinct UI sections (for example: form, filters, list, footer/status). |
| 78 | +- A template block is repeated or could become reusable (item rows, cards, list entries). |
| 79 | + |
| 80 | +Entry/root and route view rule: |
| 81 | + |
| 82 | +- Keep entry/root and route view components thin: app shell/layout, provider wiring, and feature composition. |
| 83 | +- Do not place full feature implementations in entry/root/view components when those features contain independent parts. |
| 84 | +- For CRUD/list features (todo, table, catalog, inbox), split at least into: |
| 85 | + - feature container component |
| 86 | + - input/form component |
| 87 | + - list (and/or item) component |
| 88 | + - footer/actions or filter/status component |
| 89 | +- Allow a single-file implementation only for very small throwaway demos; if chosen, explicitly justify why splitting is unnecessary. |
| 90 | + |
| 91 | +### Component data flow |
| 92 | + |
| 93 | +- Must-read reference from `1.1`: [component-data-flow](references/component-data-flow.md) |
| 94 | +- Use props down, events up as the primary model. |
| 95 | +- Use `v-model` only for true two-way component contracts. |
| 96 | +- Use provide/inject only for deep-tree dependencies or shared context. |
| 97 | +- Keep contracts explicit and typed with `defineProps`, `defineEmits`, and `InjectionKey` as needed. |
| 98 | + |
| 99 | +### Composables |
| 100 | + |
| 101 | +- Must-read reference from `1.1`: [composables](references/composables.md) |
| 102 | +- Extract logic into composables when it is reused, stateful, or side-effect heavy. |
| 103 | +- Keep composable APIs small, typed, and predictable. |
| 104 | +- Separate feature logic from presentational components. |
| 105 | + |
| 106 | +## 3) Consider optional features only when requirements call for them |
| 107 | + |
| 108 | +### 3.1 Standard optional features |
| 109 | + |
| 110 | +Do not add these by default. Load the matching reference only when the requirement exists. |
| 111 | + |
| 112 | +- Slots: parent needs to control child content/layout -> [component-slots](references/component-slots.md) |
| 113 | +- Fallthrough attributes: wrapper/base components must forward attrs/events safely -> [component-fallthrough-attrs](references/component-fallthrough-attrs.md) |
| 114 | +- Built-in component `<KeepAlive>` for stateful view caching -> [component-keep-alive](references/component-keep-alive.md) |
| 115 | +- Built-in component `<Teleport>` for overlays/portals -> [component-teleport](references/component-teleport.md) |
| 116 | +- Built-in component `<Suspense>` for async subtree fallback boundaries -> [component-suspense](references/component-suspense.md) |
| 117 | +- Animation-related features: pick the simplest approach that matches the required motion behavior. |
| 118 | + - Built-in component `<Transition>` for enter/leave effects -> [transition](references/component-transition.md) |
| 119 | + - Built-in component `<TransitionGroup>` for animated list mutations -> [transition-group](references/component-transition-group.md) |
| 120 | + - Class-based animation for non-enter/leave effects -> [animation-class-based-technique](references/animation-class-based-technique.md) |
| 121 | + - State-driven animation for user-input-driven animation -> [animation-state-driven-technique](references/animation-state-driven-technique.md) |
| 122 | + |
| 123 | +### 3.2 Less-common optional features |
| 124 | + |
| 125 | +Use these only when there is explicit product or technical need. |
| 126 | + |
| 127 | +- Directives: behavior is DOM-specific and not a good composable/component fit -> [directives](references/directives.md) |
| 128 | +- Async components: heavy/rarely-used UI should be lazy loaded -> [component-async](references/component-async.md) |
| 129 | +- Render functions only when templates cannot express the requirement -> [render-functions](references/render-functions.md) |
| 130 | +- Plugins when behavior must be installed app-wide -> [plugins](references/plugins.md) |
| 131 | +- State management patterns: app-wide shared state crosses feature boundaries -> [state-management](references/state-management.md) |
| 132 | + |
| 133 | +## 4) Run performance optimization after behavior is correct |
| 134 | + |
| 135 | +Performance work is a post-functionality pass. Do not optimize before core behavior is implemented and verified. |
| 136 | + |
| 137 | +- Large list rendering bottlenecks -> [perf-virtualize-large-lists](references/perf-virtualize-large-lists.md) |
| 138 | +- Static subtrees re-rendering unnecessarily -> [perf-v-once-v-memo-directives](references/perf-v-once-v-memo-directives.md) |
| 139 | +- Over-abstraction in hot list paths -> [perf-avoid-component-abstraction-in-lists](references/perf-avoid-component-abstraction-in-lists.md) |
| 140 | +- Expensive updates triggered too often -> [updated-hook-performance](references/updated-hook-performance.md) |
| 141 | + |
| 142 | +## 5) Final self-check before finishing |
| 143 | + |
| 144 | +- Core behavior works and matches requirements. |
| 145 | +- All must-read references were read and applied. |
| 146 | +- Reactivity model is minimal and predictable. |
| 147 | +- SFC structure and template rules are followed. |
| 148 | +- Components are focused and well-factored, splitting when needed. |
| 149 | +- Entry/root and route view components remain composition surfaces unless there is an explicit small-demo exception. |
| 150 | +- Component split decisions are explicit and defensible (responsibility boundaries are clear). |
| 151 | +- Data flow contracts are explicit and typed. |
| 152 | +- Composables are used where reuse/complexity justifies them. |
| 153 | +- Moved state/side effects into composables if applicable |
| 154 | +- Optional features are used only when requirements demand them. |
| 155 | +- Performance changes were applied only after functionality was complete. |
0 commit comments