Como refatorar o seu código front-end utilizando GitHub Copilot com Instructions, Agents e Skills especializadas - Parte 1

Como refatorar o seu código front-end utilizando GitHub Copilot com Instructions, Agents e Skills especializadas - Parte 1

16 de junho de 2026

O GitHub Copilot deixou de ser apenas um autocomplete sofisticado. Com a chegada dos Custom Agents, Instructions e Skills, é possível ensinar o GitHub Copilot a conhecer profundamente o seu projeto, sua arquitetura, seus padrões visuais, suas convenções de nomenclatura e aplicar tudo isso de forma consistente em cada componente gerado. Neste artigo, mostro como usei essas ferramentas para refatorar uma aplicação Vue 3 + PrimeVue do zero: eliminando valores hardcoded, reorganizando a estrutura de pastas e garantindo que cada novo componente respeite os mesmos padrões sem que eu precise lembrar cada detalhe.

Para acompanhar os exemplos, você precisa do Node.js instalado na máquina. Para verificar se já está disponível:

node -v
npm -v

Com o Node.js pronto, crie o projeto via Vite:

npm create vue@latest

O assistente vai solicitar configurações como nome do projeto, TypeScript, Vue Router, Pinia e ESLint. Após responder, acesse a pasta e instale as dependências:

cd nome-do-projeto
npm install

Com o projeto rodando em http://localhost:5173, instale o PrimeVue e seus pacotes auxiliares:

npm install primevue @primeuix/themes primeicons
  • primevue — conjunto de componentes UI prontos para uso
  • primeicons — biblioteca de ícones utilizada pelos componentes
  • @primeuix/themes — sistema de temas que permite customizar tokens visuais via definePreset

O ponto de partida era um projeto de autenticação com três telas Login, Register e Forgot Password funcionando, mas com problemas que qualquer dev reconhece: border-radius: 12px repetido em cinco arquivos, box-shadow com valores de cor escritos diretamente no CSS, componentes espalhados em pastas sem critério, e lógica de navegação misturada com lógica de formulário. O tipo de dívida técnica que cresce silenciosamente.

→ Sign in

→ Create account

→ Reset password

→ Estrutura inicial do projeto com arquivos desorganizados na pasta src/views>

O primeiro movimento foi criar um arquivo frontend-standards.instructions.md. Esse arquivo é carregado automaticamente pelo Github Copilot para qualquer arquivo que corresponda ao padrão definido no frontmatter no caso, src/**/*.vue. Ele funciona como uma fonte de verdade: descreve a estrutura de pastas esperada, os padrões de importação do PrimeVue, o modelo de validação com computed + submitted, e a identidade visual com tokens CSS. O Github Copilot lê esse arquivo antes de sugerir qualquer código, e o resultado é que cada componente gerado já nasce aderente à arquitetura do projeto.

---
description: "Use when creating new screens, views, components, layouts, or any Vue file in this project. Enforces folder structure, PrimeVue patterns, and visual identity."
applyTo: "src/**/*.vue"
---

applyTo é o mecanismo que transforma as instruções de "dica opcional" em regra automática. Qualquer arquivo dentro de src com extensão .vue carrega as instruções no contexto da conversa sem precisar mencionar ou invocar nada manualmente.

Com as instruções no lugar, o próximo passo foi atacar os valores hardcoded. O problema central era que border-radiuspadding e o box-shadow de foco estavam escritos diretamente nos arquivos .vue com :deep(), repetidos em cada card. A solução certa não é usar uma variável CSS global, mas usar o sistema de tokens do próprio PrimeVue especificamente o definePreset, que permite customizar tokens semânticos do tema Aura no ponto de entrada da aplicação.

const AppPreset = definePreset(Aura, {
  semantic: {
    primary: {
      50: '{blue.50}',
      100: '{blue.100}',
      // ...
      950: '{blue.950}'
    },
    formField: {
      paddingX: '0.9rem',
      paddingY: '0.95rem',
      borderRadius: '12px'
    },
    focusRing: {
      width: '0',
      style: 'none',
      color: 'transparent',
      offset: '0',
      shadow: '0 0 0 0.22rem color-mix(in srgb, {primary.300} 28%, transparent)'
    }
  }
})

O token formField controla padding e border-radius de todos os inputs da aplicação de uma só vez. O token focusRing define o comportamento do foco global incluindo a sombra customizada com color-mix. Antes dessa mudança, cada card tinha blocos :deep(.p-inputtext) com padding: 0.95rem 0.9remborder-radius: 12px e box-shadow idênticos. Depois, esses blocos simplesmente desapareceram o tema cuida disso, e os cards ficam responsáveis apenas pelo que é realmente exclusivo deles.

Antes de mover os tokens para o definePreset

Depois de mover os tokens para o definePreset

A reestruturação de pastas foi o próximo passo. O padrão que adotei separa responsabilidades de forma cirúrgica: layouts/ para grids e espaçamento sem nenhum estado, views/ para o orquestrador de cada tela, components/<feature>/ para os cards e hero panels, e types/ para os payloads TypeScript compartilhados. Nenhuma dessas camadas conhece o interior das outras, a LoginView simplesmente monta AuthLayout, LoginHero e LoginCard, e delega os eventos para cima.

<template>
  <AuthLayout>
    <LoginHero />
    <LoginCard
      @submit="onLogin"
      @go-to-register="emit('goToRegister')"
      @go-to-forgot-password="emit('goToForgotPassword')"
    />
  </AuthLayout>
</template>
  • LoginView.vue, orquestra a tela, não tem conhecimento de inputs ou validação
  • LoginCard.vue, formulário completo, emite o payload tipado, nunca acessa o mundo externo diretamente
  • LoginHero.vue, painel visual esquerdo, sem estado, sem emits

Essa separação não é só estética. Ela define contratos claros: o card emite um LoginPayload, a view processa, e o layout nunca sabe que existe um formulário. Quando o Copilot conhece essa arquitetura via instructions file, ele reproduz exatamente esse padrão em novos componentes sem questionamentos.

Antes de aplicar a estrutura via instructions file

Depois de aplicar a estrutura via instructions file

O padrão de validação também foi padronizado. Antes, alguns componentes validavam no @input, outros no @blur, e um deles não validava nada. O padrão adotado usa um ref<boolean> chamado submitted como guarda os erros são calculados como computed, mas só aparecem na tela após o primeiro submit. Isso elimina a experiência frustrante de ver mensagens de erro enquanto o usuário ainda está digitando.

const submitted = ref(false)

const errors = computed(() => ({
  email: !email.value.trim()
    ? 'Email is required.'
    : !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.value)
      ? 'Enter a valid email address.'
      : '',
  password: !password.value ? 'Password is required.' : ''
}))

const hasErrors = computed(() => Object.values(errors.value).some(Boolean))

const onSubmit = () => {
  submitted.value = true
  if (hasErrors.value) return
  emit('submit', { email: email.value, password: password.value, remember: remember.value })
}
  • submitted — flag que libera a exibição de erros apenas após o primeiro clique em submit
  • errors — computed reativo que recalcula automaticamente quando os valores dos campos mudam
  • hasErrors — portão do submit; se verdadeiro, a função retorna antes de emitir qualquer payload
  • onSubmit — único ponto de entrada para submissão, nunca chamado diretamente por validação de campo

Vale reforçar: nenhuma alteração visual foi feita durante todo esse processo. A interface continuou idêntica antes e depois de cada etapa — mesma tela de login, mesmo glassmorphism, mesma paleta azul, mesmos efeitos de hover. A refatoração foi puramente estrutural e de governança. Isso é exatamente o que diferencia uma boa refatoração: o usuário final não percebe nada, mas o próximo desenvolvedor que abrir o projeto encontra uma base muito mais fácil de entender, manter e escalar.

Para escalar esse padrão para novos componentes, criei uma Skill específica em SKILL.md. Skills no GitHub Copilot são documentos estruturados que o agente lê sob demanda, diferente das instructions que são carregadas automaticamente, a skill é invocada quando a tarefa é criação de componente. Ela consolida todos os padrões: imports individuais do PrimeVue (nunca barrel imports), os :deep() obrigatórios, a regra crítica de nunca colocar position: relative no .field (isso quebra o ícone do campo de senha), e o checklist de nova tela.

// Correto — imports individuais
import Button from 'primevue/button'
import Card from 'primevue/card'
import Password from 'primevue/password'

// Errado — barrel import, não usar
import { Button, Card, Password } from 'primevue'

O agente front-end-especialize amarra tudo isso. Ele é definido em front-end-especialize.agent.md com uma lista de ferramentas mínima leitura, edição, busca e execução e um procedimento explícito: leia as instructions antes de qualquer coisa e carregue a skill correspondente quando for criar um componente. O resultado é um colaborador que nunca esquece os padrões, nunca usa #2563eb em vez de var(--p-primary-500), e nunca coloca arquivos em pastas erradas.

O impacto real dessa abordagem aparece quando você adiciona a quarta tela reset-passwordverify-email, o que for. Com o agente e as skills no lugar, você descreve o que quer ("crie a tela de redefinição de senha com campo de nova senha e confirmação"), e o Github Copilot já sabe onde criar cada arquivo, qual estrutura de validação usar, quais tokens CSS aplicar, e o que precisa ser atualizado no auth.types.ts e no App.vue. O checklist da nova tela está na skill. O padrão visual está nas instructions. A arquitetura está no agente.

A lição mais importante desse processo não é técnica, mas sim, a de processo. Investir tempo em capturar as decisões do projeto em arquivos de governança do Github Copilot é o equivalente moderno de escrever um bom CONTRIBUTING.md, com a diferença que o Github Copilot realmente lê e aplica o que está escrito. Cada padrão documentado nas instructions é um padrão que você não vai precisar revisar em code review. Cada token movido do CSS para o definePreset é uma inconsistência visual a menos no futuro.

Na parte-2 que será o próximo artigo, mostro como integrar Tailwind CSS a esse setup sem abrir mão dos tokens do PrimeVue e quando faz sentido usar cada um.

O código completo deste projeto está disponível no meu repositório:
https://github.com/flpdefaria/poc-frontend-ghc

Links e Docs:

Confira mais:

Fique por dentro das novidades

Assine nossa newsletter e receba as últimas atualizações e artigos diretamente em seu email.

Assinar gratuitamente