08 de ago. de 2025·7 min de leitura

Componentes Vue personalizados na UI gerada — com segurança e regeneração

Aprenda a adicionar componentes Vue personalizados em UIs geradas sem perder trabalho na regeneração, usando padrões de isolamento, fronteiras claras e regras simples de entrega.

Componentes Vue personalizados na UI gerada — com segurança e regeneração

O que quebra quando você edita uma UI gerada

UIs geradas são feitas para serem reconstruídas. Em plataformas como o AppMaster, o código de aplicações web Vue3 é produzido a partir de construtores visuais. A regeneração é como as mudanças permanecem consistentes entre telas, lógica e modelos de dados.

O problema é simples: se você editar arquivos gerados diretamente, a próxima regeneração pode sobrescrever suas alterações.

Por isso as equipes recorrem ao código personalizado. Blocos de UI embutidos costumam cobrir formulários e tabelas padrão, mas aplicações reais geralmente precisam de alguns elementos especiais: gráficos complexos, seletores de mapa, editores de texto rico, áreas de assinatura ou planejadores drag-and-drop. Esses são bons motivos para adicionar componentes Vue personalizados, desde que você os trate como complementos, não como edições.

Quando o código personalizado se mistura ao código gerado, as falhas podem aparecer mais tarde e de forma confusa. Você pode não notar até que a próxima alteração de UI force uma regeneração, ou até que um colega ajuste uma tela no editor visual. Problemas comuns incluem:

  • Sua marcação personalizada desaparece porque o template foi regenerado.
  • Imports ou registro quebram porque nomes de arquivos ou estrutura mudaram.
  • Um “pequeno ajuste” vira conflito de merge em todo deploy.
  • Lógica gerada e lógica customizada divergem, fazendo com que casos de borda comecem a falhar.
  • Atualizações ficam arriscadas porque você não sabe o que será substituído.

O objetivo não é evitar customização. É tornar as reconstruções previsíveis. Se você mantiver uma fronteira limpa entre telas geradas e widgets personalizados, a regeneração continua rotineira em vez de estressante.

Uma regra de fronteira que mantém a regeneração segura

Se você quer customização sem perder trabalho, siga uma regra: nunca edite arquivos gerados. Trate-os como saída somente leitura, como um artefato compilado.

Pense na sua UI como duas zonas:

  • Zona gerada: páginas, layouts e telas produzidos pelo gerador.
  • Zona customizada: seus componentes Vue escritos à mão em uma pasta separada.

A UI gerada deve consumir seus componentes personalizados. Não deve ser o lugar onde esses componentes são construídos.

Para que isso funcione a longo prazo, mantenha a “fronteira” pequena e clara. Um widget customizado deve se comportar como um pequeno produto com um contrato:

  • Props de entrada: apenas o que ele precisa para renderizar.
  • Eventos de saída: apenas o que a página precisa reagir.

Evite acessar estado global ou chamar APIs não relacionadas de dentro do widget, a menos que isso seja explicitamente parte do contrato.

Com telas Vue3 geradas no estilo AppMaster, isso normalmente significa que você faz uma ligação mínima na tela gerada para passar props e lidar com eventos. Essa ligação pode mudar entre regenerações, mas permanece pequena e fácil de refazer. O trabalho real fica seguro na zona customizada.

Padrões de isolamento que funcionam bem com Vue3

O objetivo é direto: a regeneração deve poder substituir arquivos gerados livremente, enquanto o código do seu widget permanece intacto.

Uma abordagem prática é manter widgets sob medida como um pequeno módulo interno: componentes, estilos e utilitários auxiliares em um só lugar. Em apps Vue3 gerados, isso normalmente significa que o código personalizado vive fora das páginas geradas e é importado como dependência.

Um componente wrapper ajuda muito. Deixe o wrapper conversar com o app gerado: leia o formato de dados existente da página, normalize-o e passe props limpas para o widget. Se a forma de dados gerada mudar depois, muitas vezes você atualiza só o wrapper em vez de reescrever o widget.

Alguns padrões que funcionam bem:

  • Trate o widget como uma caixa preta: props entram, events saem.
  • Use um wrapper para mapear respostas da API, datas e IDs em formatos amigáveis ao widget.
  • Mantenha estilos escopados para que páginas regeneradas não sobrescrevam acidentalmente seu widget.
  • Não dependa da estrutura do DOM pai ou de nomes de classes específicos da página.

Quanto ao estilo, prefira CSS escopado (ou CSS Modules) e namespace em classes compartilhadas. Se o widget precisa combinar com o tema do app, passe tokens de tema como props (cores, espaçamento, tamanho de fonte) em vez de importar estilos da página.

Slots podem ser seguros quando ficam pequenos e opcionais, como uma mensagem de “empty state”. Se os slots começarem a controlar layout ou comportamento central, você terá movido o widget de volta para a camada gerada — é aí que a dor da regeneração começa.

Projetando um contrato de componente estável (props e events)

A maneira mais segura de manter a regeneração sem dores é tratar cada widget como uma interface estável. Telas geradas podem mudar. Seu componente não deveria.

Comece pelas entradas (props). Mantenha-as poucas, previsíveis e fáceis de validar. Prefira primitivos simples e objetos planos que você controla. Adicione valores padrão para que o widget se comporte bem mesmo quando uma página ainda não passar nada. Se algo puder vir malformado (IDs, strings de data, valores tipo enum), valide e falhe de forma suave: mostre um estado vazio em vez de travar.

Para saídas, padronize events para que os widgets fiquem consistentes no restante da aplicação. Um conjunto confiável é:

  • update:modelValue para v-model
  • change para mudanças confirmadas pelo usuário (não a cada tecla)
  • error quando o componente não conseguir completar sua tarefa
  • ready quando trabalho assíncrono terminar e o widget estiver utilizável

Se houver trabalho assíncrono, torne isso parte do contrato. Exponha props como loading e disabled, e considere errorMessage para falhas servidor-side. Se o componente busca dados por conta própria, ainda emita error e ready para que o pai possa reagir (toast, logging, UI de fallback).

Expectativas de acessibilidade

Inclua acessibilidade no contrato. Aceite uma prop label (ou ariaLabel), documente comportamento de teclado e mantenha o foco previsível após ações.

Por exemplo, um widget de linha do tempo num dashboard deve suportar as setas do teclado para navegar entre itens, Enter para abrir detalhes, e deve devolver o foco ao controle que abriu um diálogo quando o diálogo fechar. Isso torna o widget reutilizável em telas regeneradas sem trabalho extra.

Passo a passo: adicionar um widget sob medida sem tocar nos arquivos gerados

Mantenha o código gerado somente leitura
Deixe a plataforma regenerar o código-fonte enquanto sua pasta de customização permanece intocada.
Gerar Código

Comece pequeno: uma tela que os usuários realmente usam, um widget que a torne distinta. Manter a primeira mudança estreita facilita ver o que a regeneração afeta e o que não afeta.

  1. Crie o componente fora da área gerada. Coloque-o em uma pasta que você possua e versiona (frequentemente custom ou extensions).

  2. Mantenha a superfície pública pequena. Poucas props entrando, poucos events saindo. Não passe todo o estado da página.

  3. Adicione um wrapper fino que você também controla. O trabalho dele é traduzir “dados da página gerada” para o contrato do widget.

  4. Integre via um ponto de extensão suportado. Referencie o wrapper de uma forma que não exija editar arquivos gerados.

  5. Regenerar e verificar. Sua pasta custom, o wrapper e o componente devem permanecer inalterados e ainda compilar.

Mantenha as fronteiras afiadas. O widget foca em exibição e interação. O wrapper mapeia dados e encaminha ações. Regras de negócio permanecem na camada de lógica do app (backend ou processos compartilhados), não enterradas no widget.

Um teste mental útil: se a regeneração acontecesse agora, um colega poderia reconstruir o app e obter o mesmo resultado sem refazer edições manuais? Se sim, seu padrão está sólido.

Onde colocar a lógica para que a UI permaneça manutenível

Um widget customizado deve se preocupar principalmente com aparência e resposta às ações do usuário. Quanto mais regras de negócio você colocar no widget, mais difícil será reutilizá-lo, testá-lo e modificá-lo.

Um padrão razoável é: mantenha lógica de negócio na página ou na camada de feature, e deixe o widget “burro”. A página decide quais dados o widget recebe e o que acontece quando o widget emite um evento. O widget renderiza e reporta intenção do usuário.

Quando precisar de lógica próxima ao widget (formatação, estado pequeno, validação cliente), esconda-a atrás de uma camada de serviço pequena. Em Vue3 isso pode ser um módulo, um composable ou uma store com uma API clara. O widget importa essa API, não internas aleatórias do app.

Uma divisão prática:

  • Widget (componente): estado de UI, tratamento de input, visuais; emite eventos como select, change, retry.
  • Service/composable: modelagem de dados, cache, mapeamento de erros da API para mensagens de usuário.
  • Página/container: regras de negócio, permissões, quais dados carregar, quando salvar.
  • Partes geradas do app: mantidas intactas; passe dados via props e escute events.

Evite chamadas diretas à API dentro do widget a menos que esse seja explicitamente o contrato do componente. Se ele for responsável por buscar dados, deixe isso claro no nome (por exemplo CustomerSearchWidget) e mantenha o código de chamada em um único serviço. Caso contrário, passe items, loading e error como props.

Mensagens de erro devem ser voltadas ao usuário e consistentes. Em vez de exibir texto bruto do servidor, mapeie erros para um conjunto pequeno de mensagens usadas pela aplicação, como “Não foi possível carregar os dados. Tente novamente.” Inclua ação de retry quando possível, e registre erros detalhados fora do widget.

Exemplo: um widget ApprovalBadge personalizado não deveria decidir se uma fatura é aprovável. Deixe a página calcular status e canApprove. O badge emite approve, e a página executa a regra real e chama o backend (por exemplo, a API modelada no AppMaster), então passa um estado limpo de sucesso ou erro de volta para a UI.

Erros comuns que causam dor após a próxima regeneração

Torne o padrão repetível
Defina um padrão de equipe para componentes personalizados que resista a cada regeneração.
Começar a Construir

A maioria dos problemas não é sobre Vue. Vem de misturar trabalho customizado em lugares que o gerador possui, ou depender de detalhes que provavelmente vão mudar.

Erros que mais frequentemente transformam um pequeno widget em uma limpeza recorrente:

  • Editar arquivos Vue gerados diretamente e esquecer o que foi alterado.
  • Usar CSS global ou seletores amplos que afetam outras telas quando a marcação muda.
  • Ler ou mutar formas de estado geradas diretamente, de modo que uma renomeação quebre o widget.
  • Empacotar suposições específicas de página em um único componente.
  • Mudar a API do componente (props/events) sem um plano de migração.

Um cenário comum: você adiciona um widget de tabela customizado e funciona. Um mês depois, uma mudança de layout gerada faz sua regra global .btn afetar páginas de login e admin. Ou um objeto de dados muda de user.name para user.profile.name e o widget falha silenciosamente. O problema não era o widget — era a dependência de detalhes instáveis.

Dois hábitos evitam a maior parte disso:

Primeiro, trate código gerado como somente leitura e mantenha arquivos custom separados, com uma fronteira de importação clara.

Segundo, mantenha o contrato do componente pequeno e explícito. Se precisar evoluí-lo, adicione uma prop de versão simples (por exemplo apiVersion) ou suporte ambas as formas antigas e novas de props por um release.

Checklist rápido antes de enviar um componente personalizado

Personalize a UI sem quebrar
Gere telas Vue3 e adicione widgets personalizados sem editar arquivos gerados.
Experimentar AppMaster

Antes de mesclar um widget sob medida em um app Vue3 gerado, faça um check rápido. Ele deve sobreviver à próxima regeneração sem heroísmos, e outra pessoa deve poder reutilizá-lo.

  • Teste de regeneração: rode uma regeneração completa e reconstrua. Se você teve que re-editar um arquivo gerado, a fronteira está errada.
  • Entradas e saídas claras: props entrando, emits saindo. Evite dependências mágicas como acessar DOM externo ou assumir uma store de página específica.
  • Contenção de estilos: escopo styles e use um prefixo de classe claro (por exemplo timeline-).
  • Todos os estados OK: loading, error e empty states devem existir e ficar sensíveis.
  • Reuso sem clonagem: confirme que é possível usá-lo em uma segunda página mudando apenas props e handlers, não copiando internals.

Uma maneira rápida de validar: imagine adicionar o widget em uma tela de admin e depois em um portal de cliente. Se ambos funcionarem apenas com mudanças de props e tratamento de events, você está em um lugar seguro.

Um exemplo realista: adicionar um widget de linha do tempo a um dashboard

Uma equipe de suporte costuma querer uma tela que conte a história de um ticket: mudanças de status, notas internas, respostas do cliente e eventos de pagamento ou entrega. Um widget de linha do tempo encaixa bem, mas você não quer editar arquivos gerados e perder trabalho na próxima regeneração.

A abordagem segura é manter o widget isolado fora da UI gerada e inseri‑lo na página por meio de um wrapper fino.

O contrato do widget

Mantenha simples e previsível. Por exemplo, o wrapper passa:

  • ticketId (string)
  • range (últimos 7 dias, últimos 30 dias, custom)
  • mode (compact vs detailed)

O widget emite:

  • select quando o usuário clica em um evento
  • changeFilters quando o usuário ajusta range ou mode

Agora o widget não sabe nada sobre a página do dashboard, modelos de dados ou como as requisições são feitas. Ele renderiza uma linha do tempo e reporta ações do usuário.

Como o wrapper conecta ao contexto da página

O wrapper fica ao lado do dashboard e traduz os dados da página para o contrato. Lê o ticketId atual do estado da página, converte filtros da UI em um range e mapeia registros do backend para o formato de evento que o widget espera.

Quando o widget emite select, o wrapper pode abrir um painel de detalhes ou disparar uma ação da página. Quando emite changeFilters, o wrapper atualiza filtros da página e refaz a consulta.

Quando a UI do dashboard for regenerada, o widget permanece intacto porque vive fora dos arquivos gerados. Normalmente você só revisita o wrapper se a página renomear um campo ou mudar como armazena filtros.

Hábitos de teste e release que evitam surpresas

Mantenha lógica fora dos widgets
Comece com o Data Designer e mantenha o código UI personalizado focado apenas na interação.
Modelar Dados

Componentes customizados geralmente falham de formas entediantes: a forma de uma prop muda, um event para de disparar, ou uma página gerada re-renderiza mais vezes do que o widget espera. Alguns hábitos pegam esses problemas cedo.

Testes locais: detectar quebras de fronteira cedo

Trate a fronteira entre UI gerada e seu widget como uma API. Teste o widget sem o app completo primeiro, usando props estáticas que correspondam ao contrato.

Renderize com props de “happy path” e com valores ausentes. Simule eventos chave (salvar, cancelar, selecionar) e confirme que o pai os manipula. Teste dados lentos e telas pequenas. Verifique que não grava em estado global a menos que isso faça parte do contrato.

Se estiver construindo sobre um app AppMaster Vue3, rode esses testes antes de regenerar qualquer coisa. É mais fácil diagnosticar uma quebra de fronteira quando você não mudou duas coisas ao mesmo tempo.

Regressão após regeneração: o que checar primeiro

Após cada regeneração, reavalie os pontos de contato: as mesmas props ainda são passadas? os mesmos events continuam sendo tratados? É aí que a quebra costuma aparecer primeiro.

Mantenha a inclusão previsível. Evite imports frágeis que dependam de caminhos de arquivos que podem se mover. Use uma única entrada estável para seus componentes customizados.

Para produção, adicione logging leve e captura de erros dentro do widget:

  • Mounted com props-chave (sanitizadas)
  • Violações de contrato (prop requerida faltando, tipo errado)
  • Chamadas de API falhadas com um código curto de erro
  • Estados vazios inesperados

Quando algo quebra, você quer responder rápido: a regeneração mudou as entradas ou o widget mudou?

Próximos passos: tornar o padrão repetível no app

Depois que o primeiro widget funcionar, o ganho real é tornar isso repetível para que o próximo não seja um remendo único.

Crie um pequeno padrão interno para contratos de widget e documente onde a equipe guarda notas do app. Mantenha simples: convenções de nomes, props obrigatórias vs opcionais, um conjunto pequeno de events, comportamento de erro e propriedade clara (o que vive no gerado vs sua pasta custom).

Escreva as regras de fronteira em linguagem simples: não edite arquivos gerados, mantenha código custom isolado e passe dados só via props e events. Isso evita o “conserto rápido” que vira um imposto de manutenção permanente.

Antes de construir um segundo widget, faça um pequeno teste de regeneração. Entregue o primeiro widget e regenere pelo menos duas vezes durante mudanças normais (uma alteração de label, mudança de layout, novo campo) e confirme que nada quebrou.

Se você usa AppMaster, frequentemente funciona melhor manter a maior parte da UI e lógica nos editores visuais (UI builders, Business Process Editor e Data Designer). Reserve componentes Vue personalizados para widgets verdadeiramente sob medida que os editores não conseguem expressar, como timelines especializadas, interações avançadas em gráficos ou controles de input incomuns. Se quiser um ponto de partida limpo para essa abordagem, o AppMaster em appmaster.io é desenhado em torno da regeneração, então manter widgets isolados tende a ser natural no fluxo de trabalho.

FAQ

Por que minhas mudanças na UI desaparecem depois que eu regeno o app?

Editar arquivos Vue gerados é arriscado porque a regeneração pode sobrescrevê-los por completo. Mesmo que sua alteração pareça persistir uma vez, uma pequena edição visual no construtor pode recriar templates e apagar seus ajustes manuais.

Como posso customizar uma UI gerada sem perder o trabalho na próxima regeneração?

Coloque todo o código Vue escrito à mão em uma pasta separada e de sua responsabilidade (por exemplo custom ou extensions) e importe-a como dependência. Trate as páginas geradas como saída somente leitura e conecte-se aos seus componentes por meio de uma interface pequena e estável.

O que é um componente wrapper e por que ele ajuda com telas geradas?

Um wrapper é um componente fino que você controla e que fica entre a página gerada e seu widget. Ele traduz a forma de dados da página em props limpas e converte eventos do widget em ações da página, então se os dados gerados mudarem depois você normalmente só atualiza o wrapper.

Qual é a maneira mais segura de desenhar props e events para um widget reutilizável?

Mantenha o contrato pequeno: poucas props com os dados que o widget precisa e poucos eventos para reportar intenções do usuário. Prefira valores simples e objetos que você controla, adicione defaults, valide entradas e falhe de forma suave mostrando um estado vazio em vez de lançar erros.

Quando devo emitir `update:modelValue` vs `change` de um componente personalizado?

update:modelValue é ideal quando o widget se comporta como um controle de formulário e deve suportar v-model. change é mais adequado para ações “confirmadas”, como quando o usuário clica em Salvar ou finaliza uma seleção, para que o pai não processe cada tecla digitada.

Como evito que o CSS do meu widget quebre outras páginas geradas?

Escopo seus estilos e use um prefixo claro de classes para que páginas regeneradas não sobreponham seu CSS acidentalmente. Se precisar do tema da aplicação, passe tokens de tema como props (cores, espaçamento, tamanho de fonte) em vez de importar ou depender de estilos de página.

Onde deve ficar a lógica de negócio se eu adicionar componentes UI personalizados?

Por padrão, mantenha regras de negócio fora do widget. Deixe a página ou o backend decidir permissões, validações e comportamento de salvamento, enquanto o widget foca em renderizar e emitir eventos como select, retry ou approve.

Quais são as razões mais comuns para componentes personalizados quebrarem após a regeneração?

Evite depender de detalhes instáveis como caminhos de arquivos gerados, estrutura do DOM pai ou formato interno de objetos de estado. Se precisar deles, esconda essa dependência em um wrapper para que uma renomeação como user.name para user.profile.name não force a reescrita do widget.

O que devo testar antes e depois de regenerar para detectar problemas cedo?

Teste o widget isoladamente com props fixas que correspondam ao contrato, incluindo valores ausentes ou malformados. Depois regenere e verifique duas coisas primeiro: as mesmas props ainda são passadas e os mesmos events ainda são tratados pela página.

Quando vale a pena construir um widget Vue sob medida em vez de usar blocos de UI integrados?

Nem toda UI precisa de código personalizado; use componentes customizados para o que o construtor visual não expressa bem, como gráficos complexos, seletores de mapas, assinaturas ou planners drag-and-drop. Se um requisito pode ser atendido ajustando a UI gerada e os processos visuais, isso tende a ser mais fácil de manter a longo prazo.

Fácil de começar
Criar algo espantoso

Experimente o AppMaster com plano gratuito.
Quando estiver pronto, você poderá escolher a assinatura adequada.

Comece