Moduły Nitro: Jak statyczne powiązania przewyższają React Native TurboModules
Wyjaśnia, w jaki sposób Nitro Modules wykorzystują uprzednio skompilowane statyczne powiązania zamiast dynamicznego wyszukiwania, dzięki czemu znacznie przewyższają TurboModules i Expo Modules w React Native.
TurboModules miały być rozwiązaniem. Zastąpiły przestarzałą architekturę mostkową, usunęły niepotrzebny nadmiar zasobów i stały się przyjętym podejściem do pisania kodu natywnego, który komunikuje się z JavaScript. Następnie pojawiła się nowsza biblioteka o nazwie Nitro Modules, która sprawiła, że to „ostateczne rozwiązanie” wydało się przestarzałe.
Opublikowane testy pokazują, że przy testowaniu identycznych synchronicznych wywołań funkcji, Nitro Modules mogą przewyższać Expo Modules aż 59 razy, a TurboModules – około 15 razy. Nawet gdy chodzi o łańcuchy znaków, które zwykle powodują dodatkowe obciążenie przy przenoszeniu danych między JavaScript a kodem natywnym, Nitro nadal ma przewagę 5 do 13 razy. Przy przenoszeniu większych obiektów, takich jak zdjęcia lub surowe bufory, Nitro osiąga dodatkowe ulepszenie na poziomie 8 do 40 procent, dzięki podejściu bez kopiowania, które unika duplikowania danych w pamięci.
Tak duże różnice wymagają wyjaśnienia. Co dokładnie robi Nitro w tle i dlaczego ten projekt nie pojawił się wcześniej?
Problem, którego nikt inny nie rozwiązał
Nitro nie zostało stworzone jako narzędzie do testowania wydajności. Powstało w wyniku pracy Marc Rousavy’ego, twórcy VisionCamera, w odpowiedzi na bardzo konkretną ograniczność: ani TurboModules, ani Expo Modules nie były w stanie prawidłowo obsłużyć przetwarzania klatek.
W VisionCamera pojedyncza klatka kamery można porównać do bufora o pojemności 10 megabajtów. Ten bufor nie może zostać skopiowany za pomocą TurboModules, a także nie mieści się w zwykłej strukturze przypominającej JSON. Rousavy potrzebował sposobu na bezpośrednie przekazanie do JavaScripta złożonego, stanowego obiektu natively napisanego w C++ lub Swift, wraz z funkcjami i właściwościami. TurboModules nie posiadały mechanizmu do obsługi takich obiektów.
Nitro zostało stworzone specjalnie po to, aby to umożliwić, a znaczące wzrosty szybkości okazały się dodatkową zaletą, która przyciągnęła o wiele większą uwagę niż pierwotny problem, który rozwiązywało.
Jedna decyzja architektoniczna
Prawdziwa różnica pomiędzy TurboModules a Nitro sprowadza się do jednej decyzji projektowej: do tego, w jaki sposób każdy system reprezentuje obiekt natywny po znalezieniu się w silniku JavaScript.
TurboModules opierają się na jsi::HostObject. Za każdym razem, gdy kod JavaScript uzyskuje dostęp do właściwości lub wywołuje metodę w jednym z tych obiektów, silnik musi dynamicznie i natychmiast rozwiązać ten dostęp. To wyszukiwanie odbywa się przy każdym wywołaniu, a ten powtarzający się koszt szybko się kumuluje w przypadku modułów, które są często wywoływane.
Nitro obiera inną drogę, wykorzystując jsi::NativeState. W połączeniu z narzędziem do generowania kodu o nazwie Nitrogen tworzy wszystkie niezbędne powiązania typów w językach C++, Swift lub Kotlin z góry, jeszcze przed uruchomieniem aplikacji. Nic nie jest rozstrzygane dynamicznie w czasie wykonywania. Konwersja między JavaScript a typami natywnymi jest kompilowana statycznie z wyprzedzeniem, co oznacza, że wywołanie modułu Nitro zachowuje się bardziej jak wezwanie zwykłej funkcji niż przechodzenie przez most w czasie wykonywania.
To właśnie ta zmiana – uprzednio skompilowane statyczne powiązania zamiast dynamicznego wyszukiwania w czasie wykonywania – tłumaczy większość różnicy w wydajności widocznej w testach.
W środowisku Nitro każdy obiekt natywny, niezależnie od tego, czy został napisany w C++, Swift czy Kotlin, określany jest jako Hybrid Object. Nitrogen analizuje definicję interfejsu w TypeScript i automatycznie generuje kod niezbędny do przeniesienia tego obiektu za granicę środowiska JS, w tym rozwiązuje problemy związane z typami enum, union oraz strukturami. To właśnie te narzędzia umożliwiły Rousavy’emu udostępnienie czegoś tak nietypowego jak żywy kadr z kamery, bez konieczności ręcznego pisania oddzielnego kodu łączącego dla każdej z trzech platform.
Dlaczego to wykracza poza zwykłą bibliotekę
VisionCamera stała się początkowym dowodem na skuteczność tego podejścia, ale projekt Nitro nigdy nie miał być rozwiązaniem jednorazowym przeznaczonym wyłącznie do jednego przypadku użycia. Jego architektura zapewnia każdemu modułowi natywnemu wbudowaną obsługę buforów tablicowych, obiektów natywnych z stanem oraz bezpośredniego interfejsu z C++, co w poprzednich podejściach było co najwyżej niewygodne lub wręcz niemożliwe do zrealizowania.
Szerzej pojęty ekosystem React Native zaczyna zwracać na to uwagę. Projekty takie jak react-native-nitro-cache, wraz z narzędziami przeznaczonymi do przechowywania obrazów, zadań opartych na sztucznej inteligencji oraz silników gier, są przeprojektowywane w oparciu o Nitro właśnie po to, by zmniejszyć obciążenie wynikające z przekształcania kodu JavaScript w kod natywny w tych obszarach, gdzie wydajność ma największe znaczenie. Odzwierciedla to szerszy trend obserwowany w React Native, polegający na restrukturyzacji podstawowych bibliotek wokół Nowej Architektury, zamiast traktowania jej jako czegoś opcjonalnego do wdrożenia później. Wykorzystanie Nitro wciąż znacznie ustępuje TurboModules, które pozostaje standardowym wyborem dla większości bibliotek, ale kierunek rozwoju jest niepodważalny. Tam, gdzie priorytetem jest surowa wydajność, Nitro coraz częściej staje się pierwszym narzędziem, do którego uciekają się deweloperzy.
Co to oznacza dla autorów modułów natywnych
Jeśli obecnie utrzymujesz moduł natywny, ta zmiana zasługuje na twoją uwagę. TurboModules nie znikną w najbliższym czasie, a w przypadku prostych modułów różnica wydajności prawdopodobnie nie będzie widoczna dla użytkowników końcowych. Jednak jeśli twój moduł wymaga dużej wydajności, częstych wywołań, dużych obciążeń danych lub obejmuje obiekty, które nie mapują się łatwo na JSON, Nitro jest obecnie z dużym prawdopodobieństwem lepszą bazą do budowania.
Decyzja o rozpoczęciu tworzenia zupełnie nowego modułu natywnego w TurboModules w 2026 roku oznacza w praktyce budowanie na architekturze, którą już prześcignęła szybsza, nadal rozwijająca się alternatywa. Generator kodu Nitro automatycznie zajmuje się znacznie większą ilością powtarzalnych zadań na wszystkich trzech platformach jednocześnie, dzięki czemu otrzymywany kod działa szybciej i wymaga mniej ręcznie pisanego kodu natywnego do utrzymania. Dla zespołów posiadających już TurboModule migracja nie jest prostym przełączeniem, ale te same wyniki testów, które czynią Nitro atrakcyjnym rozwiązaniem, stanowią mocny argument za przeprowadzeniem tej migracji jak najszybciej.
React Native przeszedł już przez kilka prawdziwych punktów zwrotnych w swojej architekturze: wycofanie starego podejścia, wprowadzenie Nowej Architektury oraz ten obecny. Nitro nie pojawiło się dzięki oficjalnemu poleceniu od Meta – powstało, ponieważ jeden programista potrzebował funkcjonalności, której TurboModules po prostu nie mogły zapewnić, stworzył rozwiązanie publicznie i pozwolił uzyskanym wynikom badań mówić same za siebie.
Literatura pokrewna
- React Native, Flutter i inne: aplikacje mobilne wieloplatformowe w 2026 roku — Porównawcze analizy React Native, Flutter, Kotlin Multiplatform, Ionic, NativeScript oraz PWA pod kątem wydajności, doświadczenia programisty i dojrzałości ekosystemu.