Comparação de Frameworks
Se você está lendo esta página, provavelmente já usou outros frameworks para construir aplicações e quer saber se o Mithril.js pode te ajudar a resolver seus problemas de forma mais eficaz.
Por que não [inserir framework favorito aqui]?
A realidade é que a maioria dos frameworks modernos é rápida, adequada para construir aplicações complexas e fáceis de manter, desde que você saiba como usá-los de forma eficaz. Existem exemplos de aplicações altamente complexas em produção usando praticamente todos os frameworks populares: Udemy usa Angular, AirBnB usa React, Gitlab usa Vue, Guild Wars 2 usa Mithril.js (sim, dentro do jogo!). Claramente, todos esses são frameworks de qualidade para produção.
Como regra geral, se sua equipe já investiu muito em outro framework/biblioteca/stack, faz mais sentido continuar com ele, a menos que sua equipe concorde que há uma razão muito forte para justificar uma reescrita custosa.
No entanto, se você está começando algo novo, considere experimentar o Mithril.js, nem que seja para ver o quanto os adeptos do Mithril.js têm obtido de valor com menos de 10kb (compactado com gzip) de código. O Mithril.js é utilizado por muitas empresas conhecidas (por exemplo, Vimeo, Nike, Fitbit) e também alimenta grandes plataformas de código aberto (por exemplo, Lichess, Flarum).
Por que usar Mithril.js?
Em uma frase: porque Mithril.js é pragmático. Este guia de 10 minutos é um bom exemplo: é o tempo que leva para aprender componentes, XHR e roteamento - e essa é praticamente a quantidade certa de conhecimento necessária para construir aplicações úteis.
Mithril.js se concentra em realizar trabalho significativo de forma eficiente. Fazendo uploads de arquivos? A documentação mostra como. Autenticação? Documentado também. Animações de saída? Você conseguiu. Sem bibliotecas extras, sem mágica.
Comparações
React
React é uma biblioteca de visualização mantida pelo Facebook.
React e Mithril.js compartilham muitas semelhanças. Se você já aprendeu React, já sabe quase tudo o que precisa para construir aplicativos com Mithril.
- Ambos usam DOM virtual, métodos de ciclo de vida e reconciliação baseada em chaves.
- Ambos organizam as visualizações por meio de componentes.
- Ambos usam JavaScript como um mecanismo de controle de fluxo dentro das visualizações.
A diferença mais evidente entre React e Mithril.js é seu escopo. React é uma biblioteca de visualização, então uma aplicação típica baseada em React depende de bibliotecas de terceiros para roteamento, XHR e gerenciamento de estado. Usar uma abordagem orientada a biblioteca permite que os desenvolvedores personalizem seu stack para corresponder precisamente às suas necessidades. Para dizer de forma menos elegante, as arquiteturas baseadas em React podem variar muito de projeto para projeto, e esses projetos têm muito mais probabilidade de ultrapassar a linha de tamanho de 1 MB.
Mithril.js possui módulos integrados para necessidades comuns, como roteamento e XHR, e o guia demonstra seu uso idiomático. Essa abordagem é preferível para equipes que valorizam a consistência e a facilidade de integração.
Desempenho
Tanto React quanto Mithril.js se preocupam muito com o desempenho da renderização, mas o fazem de maneiras diferentes. No passado, o React tinha duas implementações de renderização DOM (uma usando a API DOM e outra usando innerHTML
). Sua arquitetura de fiber introduz agendamento e priorização de unidades de trabalho. O React também possui um sistema de build sofisticado que desativa várias verificações e mensagens de erro para implantações de produção, e várias otimizações específicas do navegador. Além disso, também existem várias bibliotecas orientadas ao desempenho que aproveitam o gancho shouldComponentUpdate
do React e as propriedades de verificação rápida de igualdade de objetos das bibliotecas de estrutura de dados imutáveis para reduzir os tempos de reconciliação do DOM virtual. De modo geral, a abordagem do React para o desempenho é projetar soluções relativamente complexas.
Mithril.js segue a escola de pensamento do menos é mais. Ele tem um código-fonte substancialmente menor e otimizado de forma agressiva. A lógica é que um código-fonte pequeno é mais fácil de auditar e otimizar, resultando, em última análise, em menos código sendo executado.
Aqui está uma comparação dos tempos de carregamento da biblioteca, ou seja, o tempo que leva para analisar e executar o código JavaScript para cada framework, adicionando uma chamada console.time()
na primeira linha e uma chamada console.timeEnd()
na última de um script composto exclusivamente de código de framework. Para sua conveniência de leitura, aqui estão os melhores resultados de 20 execuções com código de logging adicionado manualmente aos scripts agrupados, executados a partir do sistema de arquivos, no Chrome em um PC desktop modesto de 2010:
React | Mithril.js |
---|---|
55.8 ms | 4.5 ms |
Os tempos de carregamento da biblioteca são importantes em aplicações que não ficam abertas por longos períodos (por exemplo, em dispositivos móveis) e não podem ser melhorados por meio de caching ou outras técnicas de otimização.
Como este é um micro-benchmark, você é encorajado a replicar esses testes você mesmo, já que o hardware pode afetar muito os números. Observe que os frameworks de bundler como o Webpack podem mover as dependências para fora antes das chamadas do temporizador para emular a resolução estática do módulo, então você deve copiar o código dos arquivos CDN compilados ou abrir o arquivo de saída da biblioteca do bundler e adicionar manualmente as chamadas do temporizador de alta resolução console.time
e console.timeEnd
ao script agrupado. Evite usar new Date
e performance.now
, pois esses mecanismos não são tão estatisticamente precisos.
Para sua conveniência de leitura, aqui está um benchmark adaptado para usar CDNs na web: o benchmark para React está aqui e o benchmark para Mithril.js está aqui. Observe que estamos fazendo o benchmark de todo o Mithril.js em vez de fazer o benchmark apenas do módulo de renderização (que seria equivalente em escopo ao React). Observe também que esta configuração baseada em CDN incorre em alguns overheads devido à busca de recursos do cache de disco (~2ms por recurso). Devido a esses motivos, os números aqui não são totalmente precisos, mas devem ser suficientes para observar que a velocidade de inicialização do Mithril.js é visivelmente melhor do que a do React.
Aqui está um benchmark um pouco mais significativo: medindo o tempo de scripting para criar 10.000 divs (e 10.000 nós de texto). Novamente, aqui está o código de benchmark para React e Mithril.js. Seus melhores resultados são mostrados abaixo:
React | Mithril.js |
---|---|
99.7 ms | 42.8 ms |
O que esses números mostram é que não apenas o Mithril.js inicializa significativamente mais rápido, mas ele pode processar mais de 20.000 nós DOM virtuais antes que o React esteja pronto para uso.
Desempenho de atualização
O desempenho da atualização pode ser ainda mais importante do que o desempenho da primeira renderização, já que as atualizações podem acontecer muitas vezes enquanto uma Single Page Application está em execução.
Uma ferramenta útil para avaliar o desempenho da atualização é uma ferramenta desenvolvida pela equipe do Ember chamada DbMonster. Ele atualiza uma tabela o mais rápido que pode e mede quadros por segundo (FPS) e tempos de JavaScript (mínimo, máximo e médio). A contagem de FPS pode ser difícil de avaliar, pois inclui tempos de repintura do navegador e atrasos de setTimeout
, portanto, o número mais significativo a ser observado é o tempo médio de renderização. Você pode comparar uma implementação React e uma implementação Mithril.js. Os resultados da amostra são mostrados abaixo:
React | Mithril.js |
---|---|
12.1 ms | 6.4 ms |
Desempenho de desenvolvimento
Outra coisa a ter em mente é que, como o React adiciona verificações extras e mensagens de erro úteis no modo de desenvolvimento, ele é mais lento no desenvolvimento do que a versão de produção usada para os benchmarks acima. Para ilustrar, aqui está o benchmark de 10.000 nós acima usando a versão de desenvolvimento do React.
Substituições diretas
Existem vários projetos que afirmam paridade de API com o React (alguns por meio de bibliotecas de camada de compatibilidade), mas eles não são totalmente compatíveis (por exemplo, o suporte a PropType geralmente é removido, os eventos sintéticos às vezes não são suportados e algumas APIs têm semânticas diferentes). Observe que essas bibliotecas normalmente também incluem recursos adicionais próprios que não fazem parte da API oficial do React, o que pode se tornar problemático no futuro se alguém decidir voltar para o React Fiber.
As alegações sobre o pequeno tamanho de download (em comparação com o React) são precisas, mas a maioria dessas bibliotecas são ligeiramente maiores do que o módulo de renderização do Mithril.js. Preact é a única exceção.
Tenha cuidado com alegações de desempenho agressivas, pois os benchmarks usados por alguns desses projetos são conhecidos por estarem desatualizados e com falhas (no sentido de que podem ser - e são - explorados). Boris Kaul (autor de alguns dos benchmarks) escreveu em detalhes sobre como os benchmarks são manipulados. Outra coisa a ter em mente é que alguns benchmarks usam agressivamente recursos avançados de otimização e, portanto, demonstram o desempenho potencial, ou seja, o desempenho que é possível, dadas algumas ressalvas, mas realisticamente improvável, a menos que você gaste ativamente tempo para revisar todo o seu código-fonte identificando candidatos à otimização e avaliando os riscos de regressão trazidos pelas ressalvas de otimização.
No espírito de demonstrar características de desempenho típicas, os benchmarks apresentados nesta página de comparação são implementados de forma ingênua, idiomática e comparável (ou seja, a maneira como você normalmente escreveria 99% do seu código) e não empregam truques ou otimizações avançadas para fazer com que um ou outro framework pareça artificialmente melhor. Você é encorajado a contribuir com um PR se achar que qualquer implementação do DbMonster aqui poderia ser escrita de forma mais idiomática.
Complexidade
Tanto o React quanto o Mithril.js têm superfícies de API relativamente pequenas em comparação com outros frameworks, o que ajuda a facilitar a curva de aprendizado. No entanto, enquanto o Mithril.js idiomático pode ser escrito sem perda de legibilidade usando ES5 puro e sem outras dependências, o React idiomático depende fortemente de ferramentas complexas (por exemplo, Babel, extensão JSX, etc.), e esse nível de complexidade frequentemente se estende a partes populares de seu ecossistema, seja na forma de extensões de sintaxe (por exemplo, sintaxe de propagação de objeto não padrão no Redux), arquiteturas (por exemplo, aquelas que usam bibliotecas de dados imutáveis) ou enfeites (por exemplo, recarregamento automático de módulos).
Embora toolchains complexas também sejam possíveis com Mithril.js e outros frameworks, é fortemente recomendado que você siga os princípios KISS e YAGNI ao usar Mithril.
Curva de aprendizado
Tanto o React quanto o Mithril.js têm curvas de aprendizado relativamente pequenas. A curva de aprendizado do React envolve principalmente a compreensão dos componentes e seu ciclo de vida. A curva de aprendizado para os componentes do Mithril.js é quase idêntica. Obviamente, há mais APIs para aprender no Mithril.js, já que o Mithril.js também inclui roteamento e XHR, mas a curva de aprendizado seria bastante semelhante a aprender React, React Router e uma biblioteca XHR como superagent ou axios.
O React idiomático requer conhecimento prático de JSX e suas ressalvas e, portanto, também há uma pequena curva de aprendizado relacionada ao Babel.
Documentação
A documentação do React é clara e bem escrita e inclui uma boa referência de API, tutoriais para começar, bem como páginas que cobrem vários conceitos avançados. Infelizmente, como o React se limita a ser apenas uma biblioteca de visualização, sua documentação não explora como usar o React idiomaticamente no contexto de uma aplicação da vida real. Como resultado, existem muitas bibliotecas populares de gerenciamento de estado e, portanto, as arquiteturas que usam React podem diferir drasticamente de empresa para empresa (ou mesmo entre projetos).
A documentação do Mithril.js também inclui tutoriais introdutórios, páginas sobre conceitos avançados e uma extensa seção de referência de API, que inclui informações sobre o tipo de entrada/saída, exemplos para vários casos de uso comuns e conselhos contra uso indevido e anti-padrões. Ele também inclui um guia de consulta rápida para referência rápida.
A documentação do Mithril.js tende a ser excessivamente completa quando um tópico envolve aspectos fora do escopo do Mithril. A documentação do Mithril.js também demonstra soluções de baixo nível para casos de uso comuns em aplicações da vida real, onde é apropriado informar um desenvolvedor de que os padrões da web podem agora estar em pé de igualdade com bibliotecas estabelecidas maiores.
Angular
Angular é um framework de aplicação web mantido pelo Google.
Angular e Mithril.js são bastante diferentes, mas compartilham algumas semelhanças:
- Ambos suportam a criação de componentes.
- Ambos têm uma variedade de ferramentas para vários aspectos de aplicações web (por exemplo, roteamento, XHR).
A diferença mais óbvia entre Angular e Mithril.js está em sua complexidade. Isso pode ser visto mais facilmente em como as visualizações são implementadas. As visualizações do Mithril.js são JavaScript puro e o controle de fluxo é feito com mecanismos integrados do JavaScript, como operadores ternários ou Array.prototype.map
. Angular, por outro lado, implementa um sistema de diretivas para estender as visualizações HTML para que seja possível avaliar expressões semelhantes a JavaScript dentro de atributos HTML e interpolações. Angular realmente vem com um parser e um compiler escritos em JavaScript para conseguir isso. Se isso não parece complexo o suficiente, existem realmente dois modos de compilação (um modo padrão que gera funções JavaScript dinamicamente para desempenho e um modo mais lento para lidar com restrições de Política de Segurança de Conteúdo).
Desempenho
Angular fez muito progresso em termos de desempenho ao longo dos anos. Angular 1 usava uma verificação dirty, que tendia a ficar lenta devido à necessidade de diferenciar constantemente grandes estruturas $scope
. Angular 2 usa um mecanismo de detecção de mudança de modelo que é muito mais performático. No entanto, mesmo apesar das melhorias do Angular, Mithril.js é frequentemente mais rápido que Angular, devido à facilidade de auditoria que o pequeno tamanho do código-fonte do Mithril.js oferece.
É difícil fazer uma comparação dos tempos de carregamento entre Angular e Mithril.js por alguns motivos. O primeiro é que Angular 1 e 2 são, na verdade, códigos-fonte completamente diferentes, e ambas as versões são oficialmente suportadas e mantidas (e a grande maioria dos códigos-fonte Angular em produção atualmente ainda usa a versão 1). A segunda razão é que tanto Angular quanto Mithril.js são modulares. Em ambos os casos, é possível remover uma parte significativa do framework que não é usada em uma determinada aplicação.
Dito isso, o menor bundle Angular 2 conhecido é um hello world de 29kb compactado com o algoritmo Brotli (são 35kb usando gzip padrão) e com a maior parte da funcionalidade útil do Angular removida. Em comparação, um hello world do Mithril.js - incluindo todo o núcleo do Mithril.js com batteries included - teria cerca de 10kb compactado com gzip.
Além disso, lembre-se de que frameworks como Angular e Mithril.js são projetados para aplicações não triviais, então uma aplicação que conseguiu usar toda a superfície da API do Angular precisaria baixar várias centenas de kb de código de framework, em vez de apenas 29kb.
Desempenho de atualização
Uma ferramenta útil para avaliar o desempenho da atualização é uma ferramenta desenvolvida pela equipe do Ember chamada DbMonster. Ele atualiza uma tabela o mais rápido que pode e mede quadros por segundo (FPS) e tempos de JavaScript (mínimo, máximo e médio). A contagem de FPS pode ser difícil de avaliar, pois inclui tempos de repintura do navegador e atrasos de setTimeout
, portanto, o número mais significativo a ser observado é o tempo médio de renderização. Você pode comparar uma implementação Angular e uma implementação Mithril.js. Os resultados da amostra são mostrados abaixo:
Angular | Mithril.js |
---|---|
11.5 ms | 6.4 ms |
Complexidade
Angular é superior ao Mithril.js na quantidade de ferramentas que oferece (na forma de várias diretivas e serviços), mas também é muito mais complexo. Compare a superfície da API do Angular com a do Mithril.js. Você pode fazer seu próprio julgamento sobre qual API é mais auto-descritiva e mais relevante para suas necessidades.
Angular 2 tem muito mais conceitos para entender: no nível da linguagem, Typescript é a linguagem recomendada e, além disso, também existe a sintaxe de modelo específica do Angular, como bindings, pipes, "operador de navegador seguro". Você também precisa aprender sobre conceitos arquitetônicos como módulos, componentes, serviços, diretivas, etc., e onde é apropriado usar o quê.
Curva de aprendizado
Se compararmos maçãs com maçãs, Angular 2 e Mithril.js têm curvas de aprendizado semelhantes: em ambos, os componentes são um aspecto central da arquitetura e ambos têm ferramentas razoáveis de roteamento e XHR.
Dito isso, Angular tem muito mais conceitos para aprender do que Mithril. Ele oferece APIs específicas do Angular para muitas coisas que geralmente podem ser implementadas trivialmente (por exemplo, a pluralização é basicamente uma instrução switch, a validação "obrigatória" é simplesmente uma verificação de igualdade, etc.). Os modelos Angular também têm várias camadas de abstrações para emular o que o JavaScript faz nativamente no Mithril.js - ng-if
/ngIf
do Angular é uma diretiva, que usa um parser e compiler personalizados para avaliar uma string de expressão e emular o escopo léxico... e assim por diante. Mithril.js tende a ser muito mais transparente e, portanto, mais fácil de entender.
Documentação
A documentação do Angular 2 fornece um extenso tutorial introdutório e outro tutorial que implementa uma aplicação. Ele também tem vários guias para conceitos avançados, um guia de consulta rápida e um guia de estilo. Infelizmente, no momento, a referência da API deixa muito a desejar. Várias APIs não estão documentadas ou não fornecem contexto para o que a API pode ser usada.
A documentação do Mithril.js inclui tutoriais introdutórios, páginas sobre conceitos avançados e uma extensa seção de referência de API, que inclui informações sobre o tipo de entrada/saída, exemplos para vários casos de uso comuns e conselhos contra uso indevido e anti-padrões. Ele também inclui um guia de consulta rápida para referência rápida.
A documentação do Mithril.js também demonstra soluções de baixo nível para casos de uso comuns em aplicações da vida real, onde é apropriado informar um desenvolvedor de que os padrões da web podem agora estar em pé de igualdade com bibliotecas estabelecidas maiores.
Vue
Vue é uma biblioteca de visualização semelhante ao Angular.
Vue e Mithril.js têm muitas diferenças, mas também compartilham algumas semelhanças:
- Ambos usam DOM virtual e métodos de ciclo de vida.
- Ambos organizam as visualizações por meio de componentes.
Vue 2 usa um fork do Snabbdom como seu sistema DOM virtual. Além disso, Vue também fornece ferramentas para roteamento e gerenciamento de estado como módulos separados. Vue parece muito semelhante ao Angular e fornece um sistema de diretivas semelhante, modelos baseados em HTML e diretivas de fluxo lógico. Ele difere do Angular porque implementa um sistema reativo de modificação dinâmica que sobrescreve métodos nativos na árvore de dados de um componente (enquanto Angular 1 usa verificação dirty e ciclos de digest/aplicação para obter resultados semelhantes). Semelhante ao Angular 2, Vue compila modelos HTML em funções, mas as funções compiladas se parecem mais com visualizações Mithril.js ou React, em vez de funções de renderização compiladas do Angular.
Vue é significativamente menor que Angular ao comparar maçãs com maçãs, mas não tão pequeno quanto Mithril.js (o núcleo do Vue tem cerca de 23kb compactado com gzip, enquanto o módulo de renderização equivalente no Mithril.js tem cerca de 4kb compactado com gzip). Ambos têm características de desempenho semelhantes, mas os benchmarks geralmente sugerem que Mithril.js é ligeiramente mais rápido.
Desempenho
Aqui está uma comparação dos tempos de carregamento da biblioteca, ou seja, o tempo que leva para analisar e executar o código JavaScript para cada framework, adicionando uma chamada console.time()
na primeira linha e uma chamada console.timeEnd()
na última de um script composto exclusivamente de código de framework. Para sua conveniência de leitura, aqui estão os melhores resultados de 20 execuções com código de logging adicionado manualmente aos scripts agrupados, executados a partir do sistema de arquivos, no Chrome em um PC desktop modesto de 2010:
Vue | Mithril.js |
---|---|
21.8 ms | 4.5 ms |
Os tempos de carregamento da biblioteca são importantes em aplicações que não ficam abertas por longos períodos (por exemplo, em dispositivos móveis) e não podem ser melhorados por meio de caching ou outras técnicas de otimização.
Desempenho de atualização
Uma ferramenta útil para avaliar o desempenho da atualização é uma ferramenta desenvolvida pela equipe do Ember chamada DbMonster. Ele atualiza uma tabela o mais rápido que pode e mede quadros por segundo (FPS) e tempos de JavaScript (mínimo, máximo e médio). A contagem de FPS pode ser difícil de avaliar, pois inclui tempos de repintura do navegador e atrasos de setTimeout
, portanto, o número mais significativo a ser observado é o tempo médio de renderização. Você pode comparar uma implementação Vue e uma implementação Mithril.js. Os resultados da amostra são mostrados abaixo:
Vue | Mithril.js |
---|---|
9.8 ms | 6.4 ms |
Complexidade
Vue é fortemente inspirado no Angular e tem muitas coisas que o Angular faz (por exemplo, diretivas, filtros, bindings bidirecionais, v-cloak
), mas também tem coisas inspiradas no React (por exemplo, componentes). A partir do Vue 2.0, também é possível escrever modelos usando a sintaxe hyperscript/JSX (além de componentes de arquivo único e os vários plugins de transpilação de linguagem baseados em webpack). Vue fornece binding de dados bidirecional e uma biblioteca opcional de gerenciamento de estado semelhante ao Redux, mas, ao contrário do Angular, não fornece um guia de estilo. A abordagem de "muitas maneiras de fazer uma coisa" pode causar fragmentação arquitetônica em projetos de longa duração.
Mithril.js tem muito menos conceitos e normalmente organiza as aplicações em termos de componentes e uma camada de dados. Todos os estilos de criação de componentes no Mithril.js geram a mesma estrutura de vnode (nó virtual) usando apenas recursos nativos do JavaScript. A consequência direta de se apoiar na linguagem é menos ferramentas e uma configuração de projeto mais simples.
Documentação
Tanto Vue quanto Mithril.js têm boa documentação. Ambos incluem uma boa referência de API com exemplos, tutoriais para começar, bem como páginas que cobrem vários conceitos avançados.
No entanto, devido à abordagem de "muitas maneiras de fazer uma coisa" do Vue, algumas coisas podem não estar adequadamente documentadas. Por exemplo, seu hyperscript é fortemente ignorado.
A documentação do Mithril.js também demonstra soluções de baixo nível para casos de uso comuns em aplicações da vida real, onde é apropriado informar um desenvolvedor de que os padrões da web podem agora estar em pé de igualdade com bibliotecas estabelecidas maiores.
Os tutoriais do Mithril.js também abrangem muito mais do que os do Vue: o tutorial do Vue termina com uma simples lista de tarefas local, após passar por várias páginas para cobrir sua extensa API principal. O guia de 10 minutos do Mithril.js cobre a maioria de sua API e até mesmo aborda aspectos chave de aplicações da vida real, como buscar dados de um servidor e roteamento. Se isso não for suficiente, há também um tutorial mais longo e completo.