Vue Component Refactoring Skill
Use when encountering Vue SFCs exceeding 500 lines (especially 1000+ line "monster" files).
Trigger Conditions
- Single
.vue file exceeds 500 lines
- 50+ methods/functions in one
<script> block
- Mixed API styles (Options API + Composition API in same file)
- Multiple responsibilities in one component (data, UI, interaction, API calls)
Refactoring Protocol
Phase 1: Blueprint-First Analysis (NO CODE CHANGES)
Read the full file and map its structure:
- Template line range
- Script line range
- Style line range
- Count: functions, refs, computeds, watches, console.logs
Identify logical boundaries for extraction:
- Data/Grid generation →
useComponentData.js
- Status/State calculations →
useComponentStatus.js
- Click/Interaction handlers →
useComponentInteraction.js
- Drag/Drop/Animation →
useComponentDrag.js
- API calls → keep in interaction composable or separate
useComponentApi.js
Identify UI sub-components:
- Complex popup →
ComponentPopup.vue
- Repeated v-for items →
ComponentItem.vue
- Complex cards →
ComponentCard.vue
Design Props/Emits flow:
- Parent → Child: data, state flags, configuration
- Child → Parent:
@confirm, @cancel, @update:show, custom events
Output blueprint and wait for [APPROVE] before coding.
Phase 2: Step-by-Step Execution
Order of creation:
composables/useComponentData.js — data generation
composables/useComponentStatus.js — computed state
composables/useComponentInteraction.js — event handlers
composables/useComponentDrag.js — (if applicable)
- UI sub-components (popups, cards, items)
- Final: Rewrite main component's
<script> section
File creation pattern (use Python scripts for bulk creation):
import os
BASE = os.path.expanduser("~/project/src/composables")
os.makedirs(BASE, exist_ok=True)
with open(os.path.join(BASE, 'useComponentData.js'), 'w') as f:
f.write(content)
Phase 3: Main Component Rewrite
Strategy: Replace ONLY the <script> section, preserve <template> and <style> unchanged.
# Extract sections
template = lines[:script_start]
style = lines[style_start:]
# Create new script with composable imports
new_script = '''<script setup>
import { useComponentData } from '../composables/useComponentData'
import { useComponentStatus } from '../composables/useComponentStatus'
// ... more imports
const props = defineProps({...})
const emit = defineEmits([...])
const { ... } = useComponentData(props)
const { ... } = useComponentStatus()
// Keep template-referenced functions/refs here
defineExpose({...})
</script>'''
# Combine
new_content = f'{template}\n{new_script}\n{style}'
Phase 4: Verification
Syntax balance check:
open_braces = script_content.count('{')
close_braces = script_content.count('}')
assert open_braces == close_braces
Template ref audit:
- Extract all variable references from template (
{{ var }}, :prop="var", v-if="var")
- Verify each referenced variable exists in the new script
Critical checks:
defineExpose preserved (for parent component access)
provide/inject pairs preserved
- All event handlers wired correctly
- Props types match original
Pitfalls
- DO NOT change template logic in first pass — preserve DOM structure, only replace script
- DO NOT delete business logic — API parameters, role checks, type judgments must remain
- Watch for
uni.$emit/$on — ensure event bus calls are preserved or migrated properly
cloneDeep usage — if drag/drop uses deep clone, keep it in the drag composable
provide/inject — keep in main component, don't move to composables
- Mixed API style — if original uses
data() + methods(), convert ALL to Composition API (ref/computed) in the refactor
- console.log cleanup — remove debug logs during refactor (use conditional logger if needed)
Target Structure After Refactor
components/
├── ComponentName.vue [~300 lines] main assembly layer
├── ComponentPopup.vue [~100-300 lines] extracted popup
└── ComponentCard.vue [~100-200 lines] extracted card
composables/
├── useComponentData.js [~100-250 lines]
├── useComponentStatus.js [~150-400 lines]
├── useComponentInteraction.js [~150-450 lines]
└── useComponentDrag.js [~100-200 lines] (optional)
Success Metrics
- Main component reduced to <400 lines
- Each composable has single responsibility
- All template refs resolve correctly
- Business logic unchanged (verified by test or manual check)
- Zero console.log remaining in production code
1---2name: vue-component-refactoring3description: Refactor giant Vue single-file components (>500 lines) into maintainable structure using composables and sub-components. Covers blueprint-first analysis, extraction patterns, and verification steps for Vue 3 / Uni-app projects.4---5
6# Vue Component Refactoring Skill
7
8Use when encountering Vue SFCs exceeding 500 lines (especially 1000+ line "monster" files).
9
10## Trigger Conditions
11- Single `.vue` file exceeds 500 lines
12- 50+ methods/functions in one `<script>` block
13- Mixed API styles (Options API + Composition API in same file)
14- Multiple responsibilities in one component (data, UI, interaction, API calls)
15
16## Refactoring Protocol
17
18### Phase 1: Blueprint-First Analysis (NO CODE CHANGES)
19
201. **Read the full file** and map its structure:
21 - Template line range
22 - Script line range
23 - Style line range
24 - Count: functions, refs, computeds, watches, console.logs
25
262. **Identify logical boundaries** for extraction:
27 - **Data/Grid generation** → `useComponentData.js`
28 - **Status/State calculations** → `useComponentStatus.js`
29 - **Click/Interaction handlers** → `useComponentInteraction.js`
30 - **Drag/Drop/Animation** → `useComponentDrag.js`
31 - **API calls** → keep in interaction composable or separate `useComponentApi.js`
32
333. **Identify UI sub-components**:
34 - Complex popup → `ComponentPopup.vue`
35 - Repeated v-for items → `ComponentItem.vue`
36 - Complex cards → `ComponentCard.vue`
37
384. **Design Props/Emits flow**:
39 - Parent → Child: data, state flags, configuration
40 - Child → Parent: `@confirm`, `@cancel`, `@update:show`, custom events
41
425. **Output blueprint** and wait for `[APPROVE]` before coding.
43
44### Phase 2: Step-by-Step Execution
45
46**Order of creation**:
471. `composables/useComponentData.js` — data generation
482. `composables/useComponentStatus.js` — computed state
493. `composables/useComponentInteraction.js` — event handlers
504. `composables/useComponentDrag.js` — (if applicable)
515. UI sub-components (popups, cards, items)
526. **Final**: Rewrite main component's `<script>` section
53
54**File creation pattern** (use Python scripts for bulk creation):
55```python
56import os
57BASE = os.path.expanduser("~/project/src/composables")
58os.makedirs(BASE, exist_ok=True)
59with open(os.path.join(BASE, 'useComponentData.js'), 'w') as f:
60 f.write(content)
61```
62
63### Phase 3: Main Component Rewrite
64
65**Strategy**: Replace ONLY the `<script>` section, preserve `<template>` and `<style>` unchanged.
66
67```python
68# Extract sections
69template = lines[:script_start]
70style = lines[style_start:]
71
72# Create new script with composable imports
73new_script = '''<script setup>
74import { useComponentData } from '../composables/useComponentData'
75import { useComponentStatus } from '../composables/useComponentStatus'
76// ... more imports
77
78const props = defineProps({...})
79const emit = defineEmits([...])
80
81const { ... } = useComponentData(props)
82const { ... } = useComponentStatus()
83
84// Keep template-referenced functions/refs here
85defineExpose({...})
86</script>'''
87
88# Combine
89new_content = f'{template}\n{new_script}\n{style}'
90```
91
92### Phase 4: Verification
93
941. **Syntax balance check**:
95 ```python
96 open_braces = script_content.count('{')
97 close_braces = script_content.count('}')
98 assert open_braces == close_braces
99 ```
100
1012. **Template ref audit**:
102 - Extract all variable references from template (`{{ var }}`, `:prop="var"`, `v-if="var"`)
103 - Verify each referenced variable exists in the new script
104
1053. **Critical checks**:
106 - `defineExpose` preserved (for parent component access)
107 - `provide`/`inject` pairs preserved
108 - All event handlers wired correctly
109 - Props types match original
110
111## Pitfalls
112
113- **DO NOT change template logic** in first pass — preserve DOM structure, only replace script
114- **DO NOT delete business logic** — API parameters, role checks, type judgments must remain
115- **Watch for `uni.$emit/$on`** — ensure event bus calls are preserved or migrated properly
116- **`cloneDeep` usage** — if drag/drop uses deep clone, keep it in the drag composable
117- **`provide/inject`** — keep in main component, don't move to composables
118- **Mixed API style** — if original uses `data()` + `methods()`, convert ALL to Composition API (`ref`/`computed`) in the refactor
119- **console.log cleanup** — remove debug logs during refactor (use conditional logger if needed)
120
121## Target Structure After Refactor
122
123```
124components/
125├── ComponentName.vue [~300 lines] main assembly layer
126├── ComponentPopup.vue [~100-300 lines] extracted popup
127└── ComponentCard.vue [~100-200 lines] extracted card
128composables/
129├── useComponentData.js [~100-250 lines]
130├── useComponentStatus.js [~150-400 lines]
131├── useComponentInteraction.js [~150-450 lines]
132└── useComponentDrag.js [~100-200 lines] (optional)
133```
134
135## Success Metrics
136
137- Main component reduced to <400 lines
138- Each composable has single responsibility
139- All template refs resolve correctly
140- Business logic unchanged (verified by test or manual check)
141- Zero console.log remaining in production code