# Vue Component Refactoring

> 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.

- Skill: `ichichuang/vue-component-refactoring` (Agent Skill)
- Install (CLI): `npx skillmds@latest add ichichuang/vue-component-refactoring`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ichichuang/vue-component-refactoring/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: ichichuang (https://skillmd.com/u/ichichuang)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/ichichuang/vue-component-refactoring

---


# 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)

1. **Read the full file** and map its structure:
   - Template line range
   - Script line range  
   - Style line range
   - Count: functions, refs, computeds, watches, console.logs

2. **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`

3. **Identify UI sub-components**:
   - Complex popup → `ComponentPopup.vue`
   - Repeated v-for items → `ComponentItem.vue`
   - Complex cards → `ComponentCard.vue`

4. **Design Props/Emits flow**:
   - Parent → Child: data, state flags, configuration
   - Child → Parent: `@confirm`, `@cancel`, `@update:show`, custom events

5. **Output blueprint** and wait for `[APPROVE]` before coding.

### Phase 2: Step-by-Step Execution

**Order of creation**:
1. `composables/useComponentData.js` — data generation
2. `composables/useComponentStatus.js` — computed state
3. `composables/useComponentInteraction.js` — event handlers
4. `composables/useComponentDrag.js` — (if applicable)
5. UI sub-components (popups, cards, items)
6. **Final**: Rewrite main component's `<script>` section

**File creation pattern** (use Python scripts for bulk creation):
```python
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.

```python
# 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

1. **Syntax balance check**:
   ```python
   open_braces = script_content.count('{')
   close_braces = script_content.count('}')
   assert open_braces == close_braces
   ```

2. **Template ref audit**:
   - Extract all variable references from template (`{{ var }}`, `:prop="var"`, `v-if="var"`)
   - Verify each referenced variable exists in the new script

3. **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
