React Native — Introdução a Bundles e Ambientes de Execução
Ao se deparar com com o React Native, um desenvolvedor iniciante, web ou mobile nativo pode obter uma impressão como:
…ah, React Native é como React JS, só que pra smartphones…
Isso é algo bom na medida que novas ferramentas deixam o desenvolvimento mais transparente e agnóstico à plataforma de execução.
Isto é, podemos utilizar linguagens e ferramentas semelhantes para trabalhar com ambientes semelhantes.
Porém, ao contar sempre com essa facilidade, ficamos inaptos a resolver problemas mais complexos ou cometemos mais equívocos ao trabalhar com base em suposições que podem não ser verdade.
Este texto tem o intuito de introduzir alguns dos tópicos de interesse para quem está entrando no mundo do React Native ou que ainda não se aprofundou em suas minúcias.
Bundle e o moedor de carne
Um fato é que: desenvolver em React Native está intrinsecamente relacionado a alterar e executar um artefato chamado bundle.
Este artefato é um pouco misterioso, principalmente para quem está iniciando no desenvolvimento em React Native.
Os desenvolvedores trabalham com o bundle a todo momento, mas sempre com o intermédio de ferramentas e linguagens.
Ou seja, o desenvolvedor escreve a aplicação com código JSX. Este código, porém, é uma mera base para a geração de um bundle, que surge sem o trabalho direto do programador, através de scripts e CLIs.
Por conta disso, em alguns momentos pode parecer que o desenvolvimento se resume a empurrar JSX de um lado do processo e esperar que saiam aplicativos prontos do outro.
É exatamente nesse “meio do caminho” onde diversas questões surgem. Como JSX vira um aplicativo? O que realmente é o aplicativo React Native?
O que não é React Native?
Antes de entender o que é React Native, é interessante saber o que ele não é: já existem diversas ferramentas e métodos para criação de apps no mercado. É fácil se deixar levar pelo nome e se equivocar quanto ao que o React Native realmente é.
1. Um app React Native não é “Native”
Esse é o engano mais comum de quem entra nesse universo — pensar que o app será desenvolvido com JavaScript ou Typescript e que este código será automaticamente “transformado” em código nativo Swift/Objective-C ou Kotlin/Java.
Este é o caso para linguagens como Flutter, mas não é o que acontece no React Native.
2. React Native não é apenas uma nova forma de gerar apps híbridos
Este é um possível engano onde alguém conhece ferramentas de desenvolvimento híbrido pode cometer.
afirmar que o React Native é similar a plataformas mais antigas, como Cordova, Ionic ou Xamarin — apesar da mesma finalidade, são paradigmas diferentes.
As plataformas de desenvolvimento de apps híbridos clássicas utilizam WebViews
, ou seja, também é feito o uso de técnicas e linguagens que surgiram para o desenvolvimento web, porém, em plataformas como Cordova e Ionic, o app é renderizado e executado como um site, o que aumenta consideravelmente a dificuldade de se utilizar recursos de hardware.
Então o que é React Native?
Um app React Native pode ser dividido em duas entidades: parte nativa do app e a parte react native do app.
A primeira está próxima das APIs do dispositivo e dos recursos de hardware, enquanto a segunda está próxima do código JSX.
Enquanto a primeira funciona a partir de linguagem nativa, como Java e Kotlin para Android e Swift ou Objective-C para iOS, sendo responsável por renderizar os componentes na tela.
A parte react native do app lida com a lógica da aplicação relacionada a estes componentes, isto é, armazena e processa o que deve ser mostrado na tela, mas não renderiza os componentes em si.
Fica evidente que estes dois universos precisam trocar informações. Por exemplo, a parte react native do app descreve um botão com uma determinada cor aparecendo na tela com uma certa animação, estes dados dever ser enviados à parte nativa, que fará sua interpretação e renderização. Quando o usuário pressionar o botão, o caminho oposto é percorrido: a parte nativa informa a parte react native que o botão foi pressionado.
Essa troca de dados é feita através do React Native Bridge, que gerencia o tráfego de mensagens, geralmente em JSON, entre as partes nativa e react native do app.
Um paralelo para o React Native Bridge no back-end são os message brokers, que permitem a comunicação entre diferentes serviços, rodando em ambientes de execução diferentes.
Ou seja:
- As
Views
são renderizadas de forma nativa a partir de código não nativo; - As instruções de renderização passam pelo React Native Bridge, que permite a comunicação de código JS com código nativo;
O uso de do Bridge, ainda na analogia do broker, possibilita que dois ambientes de execução distintos e assíncronos troquem informações e reajam um ao outro.
Bundle e Ambientes de execução
Que código é executado na parte React Native do app?
A parte JavaScript deste universo é o bundle. Note que a parte nativa não se importa com onde o bundle está ou como é executado, ela apenas se preocupa em receber e enviar mensagens.
Mais informações sobre React Native Bridge: https://hackernoon.com/understanding-react-native-bridge-concept-e9526066ddb8.
Isso possibilita que:
Durante o desenvolvimento, para evitar transferência constante dos arquivos do bundle e tornar alterações mais reativas, o bundle não precisa ser otimizado nem minificado e pode ser servido diretamente da máquina do desenvolvedor.
Alguns erros incluem a URL, linha e coluna do bundle que o gerou, a URL será semelhante a:
http://localhost:8081/index.bundle?platform=android&dev=true&minify=false
Ao acessar esse link, o código JavaScript é retornado. Ele possui inúmeras linhas e lembra vagamente o código JSX.
Este é o Bundle de desenvolvimento, o código JSX foi transpilado para JavaScript e foi concatenado em um único arquivo.
O computador de desenvolvido está, efetivamente, agindo como um servidor, onde o aplicativo, no celular ou emulador acessa e executa o código transpilado usando alguma engine JavaScript.
Em aplicativos que usam Expo, os desenvolvedores precisam instalar um aplicativo específico para auxiliar nessa comunicação.
Em projetos com React Native puro, um CLI é utilizado para instalar a parte nativa do aplicativo, que, por padrão, requisitará o bundle em uma porta específica em localhost.
Um cenário diferente ocorre ao debugar o APP — o código JavaScript não é executado no dispositivo, mas sim, no navegador, onde você pode utilizar as ferramentas de debugging do desenvolvimento web para depurar o aplicativo.
Já em projetos “buildados”, o bundle é minificado e otimizado. Pode ser armazenado no próprio APK ou ser acessado a partir de um servidor remoto, permitindo deploys OTA (Over The Air).
Explorando builds
A primeira vista, um .apk
pode parecer um arquivo misterioso. De alguma forma ele possui todo o código desenvolvido e pode rodar em inúmeros dispositivos.
O mistério acaba ao abrir o .apk
com um programa de compactação de arquivos. Um APK não é diferente de um ZIP, eles tem o mesmo propósito, criar um único arquivo capaz de carregar inúmeros arquivos menores, inclusive os arquivos de um APP inteiro.
Analisando uma build de um projeto React Native, é possível encontrar o arquivo.bundle
em no diretório assets
.
Abrindo o arquivo, vê-se um código que lembra o desenvolvido, mas, sem qualquer quebra de linha ou indentação, com nomes de variáveis minificados e o JSX representado como uma série de funções. Este é o bundle de produção, otimizado para poupar espaço e facilitar a execução.
Em resumo
Apps em React Native mantém os arquivos JSX em todas as etapas do processo de desenvolvimento como um artefato chamado Bundle.
O bundle pode ser acessado de diversas formas e executado em diversos ambientes.