Cordis e Arquitetura de Plugins em TypeScript Sem a Dor de Cabeça
Se você já escreveu uma aplicação extensível em Node.js ou TypeScript, provavelmente encontrou os mesmos problemas. Um usuário ou sistema conecta um plugin. O plugin anexa cinco listeners de eventos, inicia alguns timers, registra suas rotas e injeta um serviço. E então o plugin é desabilitado ou atualizado em tempo real.
O que acontece depois? Isso mesmo, vazamentos de memória. Os listeners continuam anexados, os timers continuam contando em segundo plano, referências de contexto impedem o garbage collector de limpar a memória. No Node.js, gerenciar o ciclo de vida das dependências frequentemente se torna um trabalho manual tedioso.
Há algum tempo, os desenvolvedores do framework de chatbot Koishi enfrentaram exatamente esse problema. Precisavam criar um núcleo onde centenas de plugins de terceiros pudessem iniciar, isolar, substituir uns aos outros e descarregar sem reiniciar o processo. Foi assim que o framework Cordis nasceu.
O Que É Cordis
Seus criadores chamam o projeto de "meta-framework de composabilidade espaço-temporal". Parece inteligente e pretensioso, mas a essência é bastante prática.
Cordis combina um container de injeção de dependência (IoC), um barramento de eventos e uma árvore hierárquica de contextos. Cada plugin ou serviço vive em seu próprio contexto. Se esse contexto for destruído, o Cordis limpa automaticamente absolutamente todos os recursos associados: remove manipuladores de eventos, encerra timers e exclui serviços criados.
Não há mágica aqui, mas há uma disciplina clara: se um plugin usa os métodos [object Object], [object Object] ou [object Object], o framework cuida da limpeza dos efeitos colaterais por conta própria.
Como o Modelo de Contexto Funciona
O conceito central na biblioteca é [object Object]. Não é apenas um objeto plano com configurações, mas uma árvore ramificada.
Quando você chama [object Object], o framework cria um contexto filho (fork). O contexto filho herda os serviços do pai, mas armazena suas próprias referências aos recursos registrados.
Se você desabilitar o Plugin A, seu contexto filho é destruído. O manipulador [object Object] é removido do barramento de eventos compartilhado, enquanto o Serviço de Banco de Dados e o Plugin B continuam funcionando tranquilamente.
Serviços e Tipagem em TypeScript
Serviços no Cordis são declarados através de herança da classe base [object Object]. Isso os torna acessíveis diretamente através de propriedades do contexto, mantendo tipagem rigorosa:
O construct [object Object] resolve o problema da ordem de carregamento de módulos. Se o serviço de banco de dados for inicializado de forma assíncrona ou conectado posteriormente, o plugin dependente aguardará sua preparação e se ativará.
Ajustando Finamente a Visibilidade de Escopo
Em programas reais, módulos frequentemente não deveriam reagir a tudo. Por exemplo, um manipulador é necessário apenas para mensagens de um canal específico ou requisições com um cabeçalho particular.
Cordis introduz o conceito de filtros através da chamada [object Object] e propriedades de contexto. Você pode limitar a visibilidade de um serviço a um branch específico da árvore ou definir um predicado que filtre eventos indesejados:
Para Quais Tarefas Essa Abordagem É Boa
A biblioteca foi criada para uma classe específica de aplicações. Você não deveria arrastá-la para uma API CRUD comum no Fastify ou Express, onde criaria uma camada extra de abstração.
Mas o Cordis se encaixa perfeitamente nos seguintes cenários:
- Utilitários CLI modulares e geradores. Quando usuários podem entregar pacotes npm que estendem comandos ou pipelines de build.
- Aplicações desktop em Electron/Tauri. Para organizar um sistema de addons e temas que podem ser habilitados e desabilitados em tempo real sem recarregar a janela.
- Bots e hubs de integração. Se um serviço se comunica com uma dúzia de plataformas diferentes (Telegram, Discord, Slack), e cada adaptador precisa viver uma vida isolada.
- Ferramentas de automação. Onde processos são configurados por usuários dinamicamente através de uma interface web ou arquivos YAML.
Armadilhas e Desvantagens
Não existem ferramentas perfeitas, e o Cordis tem muitas nuances específicas:
- Curva de aprendizado íngreme. A documentação é escrita em linguagem seca com uma abundância de termos específicos. Para entender os conceitos de mesclagem de escopo e efeitos colaterais, você precisará ler cuidadosamente o código-fonte.
- API unfamiliar. Vincular serviços ao objeto de contexto através do módulo de mesclagem de tipos do TypeScript pode ser confuso no início para quem está acostumado com NestJS clássico ou InversifyJS com seus decoradores.
- Vinculado a um modelo mental. Se a arquitetura do seu projeto não envolve descarregamento dinâmico frequente de código, os benefícios do gerenciador de efeitos integrado são anulados pela complexidade do código.
Vale a Pena Experimentar
Cordis é um projeto de engenharia interessante focado no gerenciamento de ciclo de vida de componentes. Ele resolve elegantemente o problema de vazamentos de recursos ao criar sistemas extensíveis.
Se você está projetando um sistema com um ecossistema desenvolvido de plugins plugáveis e quer um mecanismo confiável para rastrear efeitos colaterais pronto para uso, faça um fork do repositório [object Object] e estude os exemplos nos testes. É um ótimo exemplo de como você pode construir uma arquitetura de microkernel em TypeScript puro.
Projetos relacionados