Communitygithub.com

vue-patterns

Patrones de la Composition API de Vue.js 3, arquitectura de componentes, mejores prácticas de reactividad, gestión de estado con Pinia, navegación con Vue Router y patrones de Nuxt SSR. Se activa para proyectos Vue, Nuxt, Vite o Pinia. Úsalo al construir o revisar código Vue 3, Nuxt o Pinia — Composition API, reactividad o navegación del router.

¿Qué es vue-patterns?

Este skill proporciona una guía completa y actualizada para el desarrollo con Vue.js 3, centrándose en la Composition API con `<script setup>`. Cubre desde la estructura del proyecto y la arquitectura de componentes (incluyendo componentes contenedor vs. presentacionales), hasta la gestión de estado con Pinia (tiendas Setup), el enrutamiento con Vue Router (definición de rutas, guardias de navegación y parámetros reactivos), y los patrones específicos de Nuxt (autoimportaciones, `useAsyncData`/`useFetch`, rutas del servidor y configuración de tiempo de ejecución). También incluye las nuevas APIs de Vue 3.5+ como `useTemplateRef()`, `onWatcherCleanup()`, `useId()`, y el destructuring reactivo de props. El skill es invaluable para desarrolladores que buscan escribir código Vue moderno, mantenible y de alto rendimiento, y es compatible con proyectos que usan Vue, Nuxt, Vite o Pinia. Incluye una extensa tabla de antipatrones con sus soluciones, y enlaces a skills relacionados para accesibilidad, patrones frontend, TypeScript y estándares de codificación.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/vue-patterns

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Patrones y Mejores Prácticas de Vue.js

Guía completa para el desarrollo con Vue.js 3 usando la Composition API (<script setup>), que cubre diseño de componentes, reactividad, gestión de estado, enrutamiento, pruebas y patrones SSR. Se incluye orientación específica de Nuxt cuando difiere de Vue vanilla.

Cuándo activarlo

Activa este skill cuando:

  • El proyecto usa Vue.js (cualquier versión), Nuxt, Vite + Vue o Pinia.
  • El usuario pregunta sobre arquitectura de componentes Vue, composables, reactividad o gestión de estado.
  • Revisas componentes de un solo archivo de Vue (archivos .vue).
  • Configuras Vue Router, tiendas Pinia o Vite/Vitest.
  • Se discuten patrones de rendimiento, seguridad o SSR específicos de Vue.

1. Estructura del Proyecto

Diseño Recomendado (Primero las Características)

src/
├── api/              # Cliente API y definiciones de endpoints
├── assets/           # Recursos estáticos (imágenes, fuentes, iconos)
├── components/       # Componentes compartidos/reutilizables
│   ├── base/         # Primitivas de UI base (Button, Input, Modal)
│   └── features/     # Componentes compartidos específicos de funcionalidades
├── composables/      # Lógica reutilizable de la Composition API
├── layouts/          # Diseños de página (opcional)
├── pages/            # Componentes de página a nivel de ruta
├── router/           # Configuración de Vue Router
├── stores/           # Tiendas Pinia
├── types/            # Definiciones de tipos TypeScript
├── utils/            # Funciones de utilidad puras
└── App.vue           # Componente raíz

Nomenclatura de Archivos

ConvenciónCuándo Usar
PascalCase.vueTodos los componentes (aplicado por vue/multi-word-component-names)
useCamelCase.tsComposables
camelCase.tsUtilidades, clientes API, tipos
Directorios kebab-caseSegmentos de ruta, carpetas de funcionalidades

2. Arquitectura de Componentes

Orden del Componente de un Solo Archivo

<script setup lang="ts">
// 1. Importaciones (vue → ecosistema → absolutas → relativas)
// 2. Props & Emits & Slots
// 3. Composables
// 4. Estado local (ref/reactive)
// 5. Propiedades computadas
// 6. Métodos
// 7. Observadores
// 8. Hooks del ciclo de vida
</script>

<template>
  <!-- Contenido del template -->
</template>

<style scoped>
  /* Estilos con ámbito */
</style>

Presentacional vs. Contenedor

  • Componentes contenedor: Poseen la obtención de datos, el estado y los efectos secundarios. Renderizan componentes presentacionales.
  • Componentes presentacionales: Reciben props, emiten eventos. Sin llamadas API, sin acceso a la tienda. Solo renderizado puro.

Mejores Prácticas para Props

// Props basados en tipos con valores por defecto
interface Props {
  label: string;
  variant?: "primary" | "secondary";
  disabled?: boolean;
  items: Item[];
}

const props = withDefaults(defineProps<Props>(), {
  variant: "primary",
  disabled: false,
});
  • Siempre proporciona type, y required/default cuando sea apropiado.
  • Props booleanas: isXxx, hasXxx, canXxx.
  • Nunca mutar props — emitir eventos en su lugar.
  • Para enlace v-model, usar defineModel() (Vue 3.4+) o modelValue + update:modelValue.

Eventos

const emit = defineEmits<{
  submit: [];
  "update:modelValue": [value: string];
  select: [id: string, index: number];
}>();
  • Usar kebab-case en las plantillas (@update:model-value).
  • Usar camelCase en el script (emit("update:modelValue", val)).

3. Composables (Lógica Reutilizable)

Estructura

// composables/useDebounce.ts
export function useDebounce<T>(value: MaybeRef<T>, delay: number): Ref<T> {
  const debounced = ref(toValue(value)) as Ref<T>;

  let timer: ReturnType<typeof setTimeout>;
  watch(
    () => toValue(value),
    (newVal) => {
      clearTimeout(timer);
      timer = setTimeout(() => { debounced.value = newVal; }, delay);
    }
  );

  onUnmounted(() => clearTimeout(timer));
  return readonly(debounced);
}

Reglas

  • Debe comenzar con el prefijo use.
  • Devolver valores reactivos (ref, computed, reactive), nunca primitivas simples.
  • Aceptar entradas reactivas mediante MaybeRef / toRef() / toValue().
  • Limpiar efectos secundarios en onUnmounted o en el onCleanup del observador.
  • Sin efectos secundarios a nivel de módulo.

vs Mixins

Los composables reemplazan completamente los mixins de Vue 2:

  • Mixins: Flujo de datos opaco, colisiones de fuente de verdad, conflictos de nombres.
  • Composables: Importaciones explícitas, valores de retorno claros, componibles y tree-shakeables.

4. Gestión de Estado

Cuándo Usar Qué

PatrónCaso de Uso
ref() / reactive()Estado local del componente
Props + EmitsComunicación padre-hijo
Provide / InjectTema, configuración, API de plugins
Tienda PiniaEstado global, compartido y complejo
Composable de estado del servidorDatos de API con caché (envolver fetch/TanStack Query)

Tienda Pinia Setup (Preferida)

// stores/useCartStore.ts
export const useCartStore = defineStore("cart", () => {
  const items = ref<CartItem[]>([]);
  const isLoading = ref(false);

  const totalPrice = computed(() =>
    items.value.reduce((sum, i) => sum + i.price * i.quantity, 0)
  );
  const itemCount = computed(() =>
    items.value.reduce((sum, i) => sum + i.quantity, 0)
  );

  async function addItem(productId: string) {
    isLoading.value = true;
    try {
      const item = await fetchProduct(productId);
      const existing = items.value.find(i => i.id === item.id);
      if (existing) existing.quantity++;
      else items.value.push({ ...item, quantity: 1 });
    } finally {
      isLoading.value = false;
    }
  }

  return { items, isLoading, totalPrice, itemCount, addItem };
});
  • Usar la sintaxis de Setup Store (no Options Store).
  • Preferir acciones para mutaciones a nivel de negocio y $patch() para actualizaciones agrupadas.
  • Cada acción asíncrona: manejar carga + éxito + error.

5. Vue Router

Definiciones de Ruta

const routes = [
  {
    path: "/users/:id",
    name: "user-detail",
    component: () => import("@/pages/UserDetail.vue"), // perezosa
    props: true, // pasar params como props
    meta: { requiresAuth: true },
  },
];

Guardias de Navegación

router.beforeEach((to, from) => {
  const { isLoggedIn } = useAuthStore();
  if (to.meta.requiresAuth && !isLoggedIn) {
    return { name: "login", query: { redirect: to.fullPath } };
  }
});

Parámetros de Ruta Reactivos

Cuando un componente permanece montado pero los parámetros de ruta cambian:

const route = useRoute();
const id = computed(() => route.params.id as string);
watch(id, (newId) => fetchItem(newId));

6. Patrones de Plantilla

Sintaxis de Plantilla

<!-- v-if/v-else-if/v-else -->
<div v-if="isLoading">Cargando...</div>
<div v-else-if="error">Error: {{ error }}</div>
<div v-else>{{ content }}</div>

<!-- v-show para alternancias frecuentes -->
<div v-show="isOpen">Contenido alternado</div>

<!-- v-for con claves estables -->
<div v-for="item in items" :key="item.id">{{ item.name }}</div>

<!-- Lista filtrada computada (no v-if + v-for en el mismo elemento) -->
<div v-for="item in activeItems" :key="item.id">{{ item.name }}</div>

<!-- Manejo de eventos -->
<form @submit.prevent="handleSubmit">
  <button type="submit">Guardar</button>
</form>

<!-- v-model -->
<input v-model="name" />
<CustomInput v-model="value" v-model:title="title" />

7. Rendimiento

TécnicaCuándo Usar
v-memoElementos de lista que rara vez cambian
v-onceContenido renderizado una vez y estático para siempre
shallowRef()Grandes estructuras de datos reemplazadas por completo
shallowReactive()Solo las propiedades de nivel superior son reactivas
v-show sobre v-ifAlternancias de visibilidad frecuentes
<KeepAlive :max="10">Cachear vistas alternadas
Rutas perezosas() => import(...) para rutas no críticas
SuspenseCarga de componentes asíncronos con fallback

8. Pruebas

Stack

  • Vitest para pruebas unitarias y de componentes
  • Vue Test Utils para montaje e interacción
  • @pinia/testing para simular tiendas
  • Playwright para E2E

Patrón de Prueba de Componente

import { mount } from "@vue/test-utils";
import { createPinia, setActivePinia } from "pinia";
import UserCard from "./UserCard.vue";

beforeEach(() => { setActivePinia(createPinia()); });

it("renderiza y emite", async () => {
  const wrapper = mount(UserCard, {
    props: { user: { id: "1", name: "Alicia" } },
  });
  expect(wrapper.text()).toContain("Alicia");
  await wrapper.find("button").trigger("click");
  expect(wrapper.emitted("select")![0]).toEqual(["1"]);
});

9. Patrones Específicos de Nuxt

Autoimportaciones

Nuxt autoimporta ref, computed, watch, useFetch, useAsyncData, etc. Úsalos directamente sin importar. Para proyectos que no son Nuxt, siempre importa explícitamente.

useAsyncData / useFetch

const { data: user, pending, error, refresh } = await useAsyncData(
  "user", // clave única para caché
  () => $fetch(`/api/users/${id}`),
);

const { data: posts } = await useFetch("/api/posts", {
  query: { page: 1 },
  key: "posts-page-1", // deduplica solicitudes
});

Rutas del Servidor

// server/api/users/[id].ts
export default defineEventHandler(async (event) => {
  const { id } = await getValidatedRouterParams(event, z.object({
    id: z.string().uuid(),
  }).parse);
  // ... obtener y devolver
});

Configuración en Tiempo de Ejecución

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    // solo servidor
    apiSecret: "",
    // público (expuesto al cliente)
    public: {
      apiBase: "https://api.example.com",
    },
  },
});

10. Nuevas APIs de Vue 3.5+

Destructuring Reactivo de Props

Vue 3.5 estabilizó el destructuring reactivo de props — las variables destructureadas de defineProps() son automáticamente reactivas:

// Vue 3.5+: props destructureadas son reactivas (no se necesita toRefs)
const { count = 0, msg = "hola" } = defineProps<{
  count?: number;
  msg?: string;
}>();

// Limitación: no se puede observar una prop destructureada directamente
watch(() => count, (newVal) => { ... }); // SE REQUIERE un getter

useTemplateRef()

Reemplaza las refs simples con coincidencia de nombre por useTemplateRef() para referencias a plantillas:

import { useTemplateRef } from "vue";
const inputEl = useTemplateRef<HTMLInputElement>("input");
// "input" coincide con el atributo ref="input" en la plantilla, no con el nombre de la variable

Soporta IDs de ref dinámicos: useTemplateRef(dynamicRefId).

onWatcherCleanup()

API de limpieza de observador importable globalmente (Vue 3.5+). Debe llamarse sincrónicamente dentro del callback del observador:

import { watch, onWatcherCleanup } from "vue";

watch(userId, async (newId) => {
  const controller = new AbortController();
  onWatcherCleanup(() => controller.abort());
  // ... obtener con señal
});

useId()

Generación de ID único estable para SSR para elementos de formulario y accesibilidad:

import { useId } from "vue";
const id = useId();

Teletransporte defer

<Teleport defer> permite teletransportar a destinos renderizados en el mismo ciclo:

<Teleport defer to="#container">Contenido</Teleport>
<div id="container"></div>

Hidratación Perezosa (SSR)

defineAsyncComponent() ahora soporta estrategias hydrate:

import { defineAsyncComponent, hydrateOnVisible } from "vue";
const AsyncComp = defineAsyncComponent({
  loader: () => import("./Comp.vue"),
  hydrate: hydrateOnVisible(),
});

Antipatrones

AntipatrónPor Qué Está MalLa Solución
Destructuring defineProps() (Vue < 3.5)Captura una instantánea, pierde reactividadAcceder mediante props.xxx o usar toRefs()
watch() sobre prop destructureada (Vue 3.5+)Error en tiempo de compilación — las props destructureadas no se pueden observar directamenteUsar envoltorio getter: watch(() => count, ...)
v-if + v-for en el mismo elementoOrden de ejecución ambiguoUsar matriz filtrada computada
v-for con clave = índiceEstado roto al reordenarUsar IDs de base de datos estables
Mutar propsViola el flujo de datos unidireccionalEmitir eventos o usar v-model
v-html con contenido de usuarioVulnerabilidad XSSSanitizar con DOMPurify
Mixins en Vue 3Opacos, propensos a colisionesReemplazar con composables
Efectos secundarios a nivel de módulo en composablesCompartidos entre instanciasLimitar en onMounted + onUnmounted
reactive() para estado reemplazableEl reemplazo rompe la reactividadUsar ref() en su lugar
Observador sin limpiezaFugas de memoria, condiciones de carreraUsar onCleanup o onWatcherCleanup() (Vue 3.5+)
Options API en código Vue 3 nuevoEl ecosistema se mueve a la Composition APIUsar <script setup>
Ref simple para referencias de plantillaSin soporte de ref dinámico, coincidencia de nombre frágilUsar useTemplateRef() (Vue 3.5+)

Skills Relacionados

  • accessibility — ARIA, HTML semántico, gestión de enfoque
  • frontend-patterns — Arquitectura frontend entre frameworks
  • typescript — Mejores prácticas de TypeScript aplicadas a proyectos Vue
  • coding-standards — Estándares generales de calidad de código

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

Skills relacionados