Lynx: Uma Nova Ferramenta para o Desenvolvimento de Aplicativos

Foto por beavertrust.org Nos últimos dias, uma novidade no ecossistema mobile está em alta o Lynx: uma nova ferramenta no cenário de desenvolvimento de aplicativos móveis, que utiliza TypeScript e React inicialmente com o ReactLynx, o que a torna familiar para muitos desenvolvedores, especialmente para aqueles que já têm experiência com React Native. E um de seus diferenciais em relação a outras tecnologias, é que voce pode utilizar com outras libs e frameworks como Vue, Angular e Svelte mas inicialmente o pacote consolidado é o de React. Porém gostaria de trazer uma análise mais aprofundada sobre as engines utilizadas pelo Lynx e um pouco do under the hoods dessa nova opção para aplicativos Cross Platform. Embora seja uma opção interessante, ela parece menos polida em comparação com alternativas mais consolidadas, como React Native (RN), Kotlin Multiplatform (KMP) ou Flutter. Então vamos analisar o Lynx em mais detalhes e discutir suas características, desafios e pontos fortes. Lembrando que alguém com maior conhecimento em Javascript engines e C++ pode fazer essa análise melhor do que eu e isso é apenas a minha opinião, e o que percebi com o conteúdo disponível na internet até esse momento. Arquitetura e Execução Uma das características mais singulares do Lynx é sua arquitetura, que utiliza dois motores JavaScript distintos para processar diferentes aspectos da aplicação. Ele utiliza uma versão personalizada do QuickJS, um pequeno interpretador JavaScript desenvolvido por Fabrice Bellard (criador do QEmu, FFMpeg e TCC), para executar o compositor de UI na principal thread de interface do usuário. Além disso, o Lynx também utiliza o JavaScriptCore da Apple em uma segunda thread, a chamada "app thread", que lida com a execução da lógica da aplicação. O uso dessas duas engines JS é necessário para garantir um bom desempenho de rolagem, especialmente para aplicativos de alta performance, como os de "doom scrolling", que precisam de uma rolagem suave e eficiente, como o TikTok. No entanto, isso levantou algumas questões sobre a complexidade da comunicação entre essas duas camadas no funcionamento de um aplicativo "nativo". Além disso, existe questão das diferenças nas especificações JavaScript que cada engine está utilizando. No QuickJS, por exemplo, suporta a maioria das funcionalidades do ES2023, enquanto o PrimJS está mais alinhado com versões mais antigas do ES, aqui não entendi o porque do Quick suportar ES2023 e o PrimJS principal engine do Lynx utilizar ES2019 de acordo com repositório no GitHub. Layout e UI Uma outra questão que pode causar confusão aos desenvolvedores é a forma como o Lynx lida com os elementos de interface. O Lynx fornece poucos elementos de interface em cada plataforma por padrão, mas permite criar novos elementos em código nativo de cada plataforma. A documentação sugere que os desenvolvedores podem adicionar novos elementos como campos de texto no código nativo, mas não fica claro se há uma biblioteca de componentes completa disponível ou se isso precisa ser implementado manualmente, acho que existe uma falta de mais elementos padrões pelo menos inicialmente. PrimJS vs Hermes Nesse cenário temos a PrimJS como a principal engine para o Lynx que foi construída exclusivamente para o Lynx, é descrita como sendo baseada no ES2019 e visa ser leve e eficiente para execução em dispositivos móveis. O PrimJS foi projetado para se integrar bem com a arquitetura do Lynx, que utiliza dois motores JavaScript distintos. É importante citar que o PrimJS roda na main thread e o JavaScriptCore (Uma engine também utilizado pelo RN na antiga arquitetura que foi substituída pelo Hermes) para a background thread. E de outro lado temos a única engine utilizado no React Native atualmente, o Hermes que trouxe diversas melhorias em comparação com o JSC, especialmente em termos de desempenho e consumo de recursos. O Hermes acaba tendo um melhor destaque por: Tempo de Inicialização Reduzido: Ao compilar o JavaScript para bytecode antecipadamente (AOT - Ahead of Time), o Hermes reduz significativamente o tempo de carregamento do aplicativo. Menor Uso de Memória: Seu design otimizado para dispositivos móveis consome menos RAM, o que melhora a experiência do usuário, especialmente em dispositivos de entrada. Tamanho de Bundle Menor: O Hermes permite que os aplicativos tenham um APK/IPA menor, já que o código é pré compilado. Garbage Collector Eficiente: Utiliza um coletor de lixo incremental, minimizando pausas na execução e melhorando a fluidez do app. Melhor Performance em Animações: Com menos overhead no processamento do JavaScript, o Hermes melhora a execução de animações e interações, o que é essencial para apps e jogos no React Native. Dessa forma, enquanto o PrimJS foi projetado exclusivamente para o Lynx e sua arquitetura, o Hermes se consolidou como a melhor opção para o React Native, proporcionando maior eficiência e desempenho na execução dos aplicativos. Render Pipeline e Threads

Mar 10, 2025 - 05:01
 0
Lynx: Uma Nova Ferramenta para o Desenvolvimento de Aplicativos

Lynx

Foto por beavertrust.org

Nos últimos dias, uma novidade no ecossistema mobile está em alta o Lynx: uma nova ferramenta no cenário de desenvolvimento de aplicativos móveis, que utiliza TypeScript e React inicialmente com o ReactLynx, o que a torna familiar para muitos desenvolvedores, especialmente para aqueles que já têm experiência com React Native. E um de seus diferenciais em relação a outras tecnologias, é que voce pode utilizar com outras libs e frameworks como Vue, Angular e Svelte mas inicialmente o pacote consolidado é o de React.

Porém gostaria de trazer uma análise mais aprofundada sobre as engines utilizadas pelo Lynx e um pouco do under the hoods dessa nova opção para aplicativos Cross Platform.

Embora seja uma opção interessante, ela parece menos polida em comparação com alternativas mais consolidadas, como React Native (RN), Kotlin Multiplatform (KMP) ou Flutter. Então vamos analisar o Lynx em mais detalhes e discutir suas características, desafios e pontos fortes. Lembrando que alguém com maior conhecimento em Javascript engines e C++ pode fazer essa análise melhor do que eu e isso é apenas a minha opinião, e o que percebi com o conteúdo disponível na internet até esse momento.

Arquitetura e Execução

Uma das características mais singulares do Lynx é sua arquitetura, que utiliza dois motores JavaScript distintos para processar diferentes aspectos da aplicação. Ele utiliza uma versão personalizada do QuickJS, um pequeno interpretador JavaScript desenvolvido por Fabrice Bellard (criador do QEmu, FFMpeg e TCC), para executar o compositor de UI na principal thread de interface do usuário. Além disso, o Lynx também utiliza o JavaScriptCore da Apple em uma segunda thread, a chamada "app thread", que lida com a execução da lógica da aplicação.

O uso dessas duas engines JS é necessário para garantir um bom desempenho de rolagem, especialmente para aplicativos de alta performance, como os de "doom scrolling", que precisam de uma rolagem suave e eficiente, como o TikTok. No entanto, isso levantou algumas questões sobre a complexidade da comunicação entre essas duas camadas no funcionamento de um aplicativo "nativo". Além disso, existe questão das diferenças nas especificações JavaScript que cada engine está utilizando. No QuickJS, por exemplo, suporta a maioria das funcionalidades do ES2023, enquanto o PrimJS está mais alinhado com versões mais antigas do ES, aqui não entendi o porque do Quick suportar ES2023 e o PrimJS principal engine do Lynx utilizar ES2019 de acordo com repositório no GitHub.

Layout e UI

Uma outra questão que pode causar confusão aos desenvolvedores é a forma como o Lynx lida com os elementos de interface. O Lynx fornece poucos elementos de interface em cada plataforma por padrão, mas permite criar novos elementos em código nativo de cada plataforma. A documentação sugere que os desenvolvedores podem adicionar novos elementos como campos de texto no código nativo, mas não fica claro se há uma biblioteca de componentes completa disponível ou se isso precisa ser implementado manualmente, acho que existe uma falta de mais elementos padrões pelo menos inicialmente.

PrimJS vs Hermes

Nesse cenário temos a PrimJS como a principal engine para o Lynx que foi construída exclusivamente para o Lynx, é descrita como sendo baseada no ES2019 e visa ser leve e eficiente para execução em dispositivos móveis. O PrimJS foi projetado para se integrar bem com a arquitetura do Lynx, que utiliza dois motores JavaScript distintos. É importante citar que o PrimJS roda na main thread e o JavaScriptCore (Uma engine também utilizado pelo RN na antiga arquitetura que foi substituída pelo Hermes) para a background thread.

E de outro lado temos a única engine utilizado no React Native atualmente, o Hermes que trouxe diversas melhorias em comparação com o JSC, especialmente em termos de desempenho e consumo de recursos. O Hermes acaba tendo um melhor destaque por:

Tempo de Inicialização Reduzido: Ao compilar o JavaScript para bytecode antecipadamente (AOT - Ahead of Time), o Hermes reduz significativamente o tempo de carregamento do aplicativo.

Menor Uso de Memória: Seu design otimizado para dispositivos móveis consome menos RAM, o que melhora a experiência do usuário, especialmente em dispositivos de entrada.

Tamanho de Bundle Menor: O Hermes permite que os aplicativos tenham um APK/IPA menor, já que o código é pré compilado.
Garbage Collector Eficiente: Utiliza um coletor de lixo incremental, minimizando pausas na execução e melhorando a fluidez do app.

Melhor Performance em Animações: Com menos overhead no processamento do JavaScript, o Hermes melhora a execução de animações e interações, o que é essencial para apps e jogos no React Native.

Dessa forma, enquanto o PrimJS foi projetado exclusivamente para o Lynx e sua arquitetura, o Hermes se consolidou como a melhor opção para o React Native, proporcionando maior eficiência e desempenho na execução dos aplicativos.

Render Pipeline e Threads

Para entrarmos mais a fundo ao processo do Render Pipeline do Lynx primeiro precisamos entender, o que é isso e também o conceito de threads, em uma definição breve o render pipeline é uma sequência de etapas que o sistema segue para renderizar a interface do usuário na tela. Em sistemas gráficos, essa pipeline envolve a transformação dos dados de entrada (como a descrição da interface, as interações do usuário, os recursos gráficos) em uma imagem final que será exibida no monitor ou na tela do dispositivo. E as threads são unidades de execução que permitem que um programa seja dividido em diferentes tarefas, as quais podem ser realizadas ao mesmo tempo. Com isso vou fazer uma breve comparação entre o render pipeline do React Native e Lynx.

No React Native o render pipeline pode ser feito na thread de UI e Javascript, e quando necessário ser feito apenas na UI temos um processo de renderização mais flexível entre as threads além de o novo renderer do React Native, o Fabric ter sido feito com base no conceito do Virtual Dom, isso quer dizer que a cada atualização de elementos na tela no React, o sistema cria ou copia novos objetos no renderizador, ao invés de modificar as estruturas de dados já existentes. Isso torna possível que o framework ofereça APIs que funcionam de forma segura e sincronizada com as threads no React.

Enquanto isso de acordo com os terms and specs, do Lynx afirma que o render pipeline do Lynx utiliza em maior parte a main thread ou seja equivalente a UI thread do React Native, para renderizar a tela no First screen Rendering que é o momento onde a tela é construída pela primeira vez quando é carregada, e só após disso em casos de re-rendering a renderização da tela poderá ser feita na background thread que seria a Javascript thread no React Native. De acordo com as specs do Lynx e o funcionamento que temos com o Fabric, é perceptível que o processo de renderização no React Native tem uma melhor performance utilizando a nova arquitetura.

React

Mas para mim o principal problema do Lynx é que voce pode ter alguns problemas utilizando o React da mesma forma que usa em aplicações React Native e Web, porque mesmo essa sendo uma grande vantagem do Lynx ser uma ferramenta que pode ser usada com outras libs e frameworks, é uma desvantagem para quem busca utilizar com o React pelo menos até o momento, mas com certeza vai ter melhorias.

Como descrito no terms and specs do Lynx

6.3.1. ReactLynx
A framework featuring React-like DSL adapted to Lynx’s dual-threaded model.

Isso significa que o ReactLynx é um framework utilizando uma DSL uma Domain-Specific Language, o Lynx usa uma linguagem de domínio específico que é parecida com o React. Isso significa que, se você já está familiarizado com o React, vai achar a sintaxe e os conceitos do ReactLynx bastante familiares. No entanto, a diferença é que o ReactLynx foi projetado para se integrar com o Lynx, que possui características e funcionalidades próprias.

Ele foi adaptado no modelo dual thread model utilizado pelo Lynx, o problema é que o React não foi feito para rodar nesse padrão, apesar da adaptação feita pelo time do Lynx ser muito boa temos alguns problemas, principalmente quando precisamos executar algo sincronamente logo após a renderização da UI e antes da tela ser atualizada, ou seja o Lynx não tem suporte ao useLayoutEffect do React e nesses cenários voce deverá executar o código diretamente na main thread.

Na prática, isso pode afetar bibliotecas e componentes que dependem do useLayoutEffect para realizar medições ou ajustes imediatamente após uma renderização. Por exemplo, muitas libs de UI (como bibliotecas de animação, tooltip, carrosséis, etc) usam useLayoutEffect para medir o tamanho de um elemento logo que ele monta e então calcular posicionamentos, evitando “flash” visual. No ReactLynx, esses códigos serão tratados como um useEffect normal (assíncrono) ou podem nem ser incluídos na thread principal. O efeito disso é que pode ocorrer um pequeno delay no elemento por exemplo, um tooltip inicialmente renderiza na posição padrão e somente numa próxima atualização (depois do efeito rodar na thread de fundo) reposiciona corretamente, possivelmente causando um pequeno piscar ou mudança tardia. Esse é um contra importante, bibliotecas concebidas para um ambiente onde podiam interferir na renderização de forma síncrona precisam ser ajustadas ou correm o risco de perder alguma funcionalidade.

Conforme os termos e especificações do Lynx.

In ReactLynx, all lifecycle hooks execute asynchronously in the background thread, so they do not have synchronous blocking render characteristics. This means ReactLynx does not support useLayoutEffect. As a current alternative, you can use the element's main-thread:bindlayoutchange event to obtain layout results and set corresponding properties.

Também de acordo com esse paragrafo da documentação do ReactLynx em que diz que todos os hooks de lifecycle são executados de forma assíncrona na background thread, existem alguns possíveis impactos nisso. Embora o offloading de trabalho melhore a taxa de frames e evite travamentos na UI, existe um pequeno custo de comunicação entre threads e de coordenação de estado. Em geral, o ReactLynx gerencia essa coordenação internamente, é possível observar que algumas atualizações de interface acontecem com um delay maior do que aconteceria no React tradicional. Por exemplo, uma mudança de estado disparada em um hook useEffect não reflete instantaneamente na UI – ela precisa atravessar da background thread para a main thread. Normalmente isso é imperceptível, mas em cenários extremamente sensíveis ao tempo de execução (como animações que dependem de sincronismo), essa latência um pouco maior pode atrapalhar um pouco.

No geral acho que o saldo é positivo em desempenho: os ganhos em evitar bloqueios na renderização geralmente superam a pequena latência na aplicação de efeitos.

Comparação com outras ferramentas

Em um mercado com várias opções Cross Platform para desenvolvimento de aplicativos, o Lynx é uma opção com grande potencial para desenvolvimento cross platform, focado em alta performance e facilidade de uso, mas ainda não tem a maturidade e adoção de alternativas como React Native, Flutter e Kotlin Multiplatform. O React Native se destaca pela grande comunidade, integração com o ecossistema JavaScript/TypeScript e facilidade de compartilhamento de código principalmente com aplicações React já existentes, mas ainda tem alguns desafios relacionados a bugs em atualizações de versões e também a adesão da nova arquitetura na maioria dos aplicativos. O Flutter, com seu motor antigo motor Skia que já era bom e o novo Impeller oferece UI altamente customizável e desempenho próximo ao nativo, sendo ideal para apps gráficos intensivos, porem a falta de uma maior comunidade ao entorno, o uso do Dart, e suporte ainda em evolução para Web e Desktop são pontos de melhoria. Já o Kotlin Multiplatform é a melhor opção para quem busca compartilhamento de lógica de negócios sem comprometer a UI nativa, sendo forte no ecossistema Android e Back End, mas também por ser uma ferramenta nova, ainda não temos uma grande comunidade, um menor suporte para o IOS, dependendo de alguns fatores pode ser difícil fazer a integração em aplicativos já existentes, e o principal problema anterior seria de não ter uma UI compartilhada, como as outras opções mas hoje temos a opção do Compose Multiplatform, que tem como objetivo resolver isso. Em comparação com o Lynx, ele promete ser leve e rápido mas de todas essas opções que temos atualmente, precisa consolidar seu suporte a múltiplas plataformas e ferramentas para competir com as outras soluções existentes no mercado, e que já tem vários problemas resolvidos.

Conclusão

O Lynx é uma ferramenta interessante, mas ainda parece estar em um estágio inicial de desenvolvimento, com algumas limitações e desafios a serem superados. Alguns pontos ainda podem ser considerados ultrapassados. No entanto, para aqueles que já estão familiarizados com React e procuram construir um aplicativo com performance de um nativo, com apenas seu conhecimento em React ou uma maneira de integrar facilmente componentes React em aplicativos nativos, o Lynx oferece uma solução promissora, embora ainda longe de ser uma alternativa completa quando comparada com o React Native, Flutter ou Kotlin Multiplatform.

Também não esqueça de me acompanhar nas redes sociais, para a gente trocar aquela ideia

matheustadeu.com

www.linkedin.com/in/matheus-tadeu/

Fontes

https://reactnative.dev/docs/getting-started
https://docs.flutter.dev
https://kotlinlang.org/docs/multiplatform.html
https://lynxjs.org/guide/start/quick-start.html
https://lynxjs.org/react/lifecycle.html
https://reactnative.dev/architecture/threading-model
https://lynxjs.org/guide/spec.html
https://lynxjs.org/react/main-thread-script.html