← Blog
Python14 min czytania

Rio — komponenty w stylu Reacta pisane wyłącznie w Pythonie

Rio pozwala zbudować interfejs webowy bez linijki HTML-a, CSS-a i JavaScriptu — komponentami w stylu Reacta, pisanymi w Pythonie. Wyjaśniamy, co siedzi pod spodem, kiedy to ma sens i czego brakuje.

Programista Pythona, który musi zrobić interfejs, staje przed nieprzyjemnym wyborem. Może nauczyć się osobnego ekosystemu — Reacta, narzędzi budowania, zarządzania stanem, CSS-a — i utrzymywać dwa światy z warstwą API między nimi. Albo znaleźć framework, który pozwoli mu zostać w Pythonie i zapłacić za to inną cenę.

Rio należy do tej drugiej kategorii i deklaruje to bez ogródek: nie napiszesz ani jednej linijki HTML-a, CSS-a czy JavaScriptu. Interfejs składasz z komponentów w Pythonie, w modelu bardzo bliskim Reactowi. Warto zrozumieć, jak to działa pod spodem i za co się faktycznie płaci — bo cena istnieje, tylko leży w innym miejscu, niż się spodziewasz.

Stan projektu

Repozytorium: rio-labs/rio. 3637 gwiazdek, 158 forków, licencja Apache-2.0, start w kwietniu 2024 — projekt ma dwa i pół roku. Otwartych zgłoszeń jest 75.

Paczka na PyPI nazywa się rio-ui i jest wydawana regularnie: wersja 0.12.3 ukazała się 30 sierpnia 2026, wcześniej 0.12.2 i 0.12.1 w maju 2026, a 0.12 pod koniec grudnia 2025. W historii jest 117 wydań, w tym wiele kandydackich — projekt wypuszcza często i małymi krokami.

Dwie rzeczy trzeba powiedzieć uczciwie. Pierwsza: za projektem stoją dwie osoby — obaj autorzy są wymienieni w pliku konfiguracyjnym paczki i obaj widnieją jako czynni w historii commitów. Świeże wpisy w tej historii to w większości podbicia zależności od bota, ale po odfiltrowaniu ich zostaje realna praca: poprawka wczytywania czcionek, usprawnienia odtwarzacza multimediów na urządzeniach mobilnych, poprawka obrazu wychodzącego za obszar rodzica, uniknięcie awarii w trybie okienkowym. To nie jest projekt na autopilocie, ale jest projektem małego zespołu.

Druga: autorzy sami klasyfikują dojrzałość jako Development Status :: 4 - Beta, a wersja to 0.12.x. Przy frameworku interfejsu użytkownika to sygnał uczciwy i warto go potraktować dosłownie — API może się jeszcze ruszać.

Model komponentów

Jeśli pracowałeś z Reactem, zrozumiesz to w dziesięć sekund. Komponent to klasa dziedzicząca po rio.Component, jej atrybuty są stanem, który Rio obserwuje, a metoda build zwraca drzewo komponentów. Zmiana atrybutu powoduje ponowne wywołanie build i odświeżenie interfejsu.

class ButtonClicker(rio.Component):
    clicks: int = 0

    def _on_press(self) -> None:
        self.clicks += 1

    def build(self) -> rio.Component:
        return rio.Column(
            rio.Button('Kliknij mnie', on_press=self._on_press),
            rio.Text(f'Kliknięcia: {self.clicks}'),
        )

app = rio.App(build=ButtonClicker)
app.run_in_browser()

To jest cały mechanizm. Nie ma osobnego wywołania ustawiającego stan, nie ma dekoratorów obserwujących zmienne — przypisanie do atrybutu wystarcza, bo Rio pilnuje atrybutów zadeklarowanych w klasie. Wbudowanych komponentów jest według README ponad pięćdziesiąt, od przycisków i pól tekstowych po układy w rodzaju rio.Column.

Najmocniejszym argumentem praktycznym jest tu jednak pełne typowanie. Skoro komponenty są zwykłymi klasami Pythona z adnotacjami typów, edytor podpowiada nazwy właściwości i podświetla błędy od razu — bez wtyczek do JSX-a, bez osobnego serwera języka dla szablonów. Dla zespołu pracującego w PyCharmie albo w edytorze z serwerem języka Pythona to zysk, którego nie da się osiągnąć w układzie z osobnym frontendem.

Co faktycznie dostajesz w pakiecie

README mówi o „ponad pięćdziesięciu" komponentach, ale przeliczenie katalogu ze źródłami daje siedemdziesiąt pięć plików komponentów. Warto zobaczyć zakres, bo kilka pozycji zmienia ocenę tego, do czego framework się nadaje.

  • Wejścia — pole tekstowe jedno- i wieloliniowe, liczbowe, data, przełącznik, pole wyboru, suwak, lista rozwijana, wybór koloru oraz obszar wgrywania plików.
  • Układy — siatka, stos, kontener przepływowy, kontener przewijany, szuflada, okno wyskakujące, nakładka, element rozwijany, przełącznik widoków, zakładki i pasek przełączania.
  • Prezentacja danych — tabela, widok listy, widok drzewa, wykres, paski i okręgi postępu, kalendarz oraz pokaz slajdów.
  • Treść bogata — Markdown, blok kodu, przeglądarka PDF, odtwarzacz multimediów, obraz, ikona oraz komponenty do wstawiania surowego HTML-a i osadzania stron.
  • Zdarzenia — nasłuchiwacze zdarzeń myszy, wskaźnika i klawiatury, wraz z obsługą elementów mogących przyjąć fokus klawiatury.

Trzy pozycje z tej listy zasługują na osobne zdanie, bo to nie są rzeczy, które spotyka się w zestawach komponentów. Automatyczny formularz i towarzyszący mu budowniczy formularzy generują interfejs z definicji danych — dokładnie to, czego chce się przy narzędziu wewnętrznym opartym o istniejące modele. Edytor grafu wraz z komponentami wejść i wyjść węzłów pozwala zbudować interfejs w stylu edytora przepływów, a to jest zwykle powód, dla którego ludzie rezygnują z frameworków tej klasy. A przeglądarka PDF i odtwarzacz multimediów usuwają dwa najczęstsze powody sięgania po biblioteki JavaScriptu.

Co siedzi pod spodem

Deklaracja „zero JavaScriptu" jest prawdziwa, ale wymaga precyzji, więc sprawdziłem, co jest w repozytorium. Otóż jest tam katalog frontend, plik konfiguracyjny Vite, konfiguracja TypeScriptu, konfiguracja Sassa i plik package.json.

Innymi słowy: JavaScript jest, tylko nie twój. Rio ma własny frontend napisany w TypeScripcie, budowany Vitem, który renderuje komponenty opisane po stronie Pythona. Ty go nie pisujesz i nie musisz o nim wiedzieć — dopóki coś nie zadziała inaczej niż oczekujesz, i wtedy diagnoza przechodzi przez granicę między dwoma językami.

Po stronie serwera lista zależności jest równie pouczająca: FastAPI i uvicorn. Aplikacja Rio jest więc zwyczajną aplikacją ASGI. To bardzo dobra wiadomość dla wdrożenia, bo znaczy, że obowiązują tu wszystkie normalne praktyki: odwrotne proxy, terminowanie TLS, zarządzanie procesami, monitorowanie. Nie trzeba wymyślać nowego sposobu uruchamiania czegokolwiek.

W zależnościach jest jeszcze jeden ciekawy szczegół: biblioteka do wykrywania robotów indeksujących. Sugeruje to, że framework rozróżnia żądania od przeglądarek i od wyszukiwarek — co przy interfejsie budowanym dynamicznie jest właściwym podejściem, jeśli strona ma być widoczna w wyszukiwarce.

Dwa tryby uruchomienia

Rzecz, która wyróżnia Rio na tle frameworków webowych: ta sama aplikacja może działać jako strona albo jako program okienkowy. Decyduje o tym jedno wywołanie — app.run_in_browser() albo app.run_in_window().

To otwiera zastosowanie, o którym łatwo nie pomyśleć: narzędzia wewnętrzne dostarczane jako aplikacja desktopowa. Zamiast tłumaczyć zespołowi niesprzedażowemu, jak wejść na adres w intranecie i się zalogować, dajesz im program z ikoną. A gdy ten sam program ma być dostępny zdalnie, zmieniasz jedną linijkę i stawiasz go za proxy.

Start

Instalacja i pierwszy projekt zajmują dwie minuty, bo framework dowozi własne narzędzie wiersza poleceń wraz z szablonami:

pip install rio-ui

rio new my-project --type website --template "Tic-Tac-Toe"
cd my-project
rio run

Polecenie rio new bez argumentów pyta o typ projektu i szablon. Wybór szablonów jest istotny bardziej, niż się wydaje, bo przy frameworku o autorskim modelu komponentów działający przykład jest szybszą drogą niż dokumentacja. W pakiecie są też narzędzia deweloperskie, a wymagany Python to 3.10 lub nowszy.

Zależności warte odnotowania

To sekcja, którą dopisuję po przejrzeniu pliku konfiguracyjnego paczki, bo wynika z niej coś, o czym warto wiedzieć przed wdrożeniem firmowym.

Rio ma dwadzieścia sześć zależności produkcyjnych. Sporo z nich to biblioteki znane i stabilne — FastAPI, uvicorn, Pillow, Jinja-podobne narzędzia, watchfiles, tomlkit. Ale kilka pozycji to biblioteki tych samych autorów, wydzielone z projektu i utrzymywane osobno, przy czym wszystkie one są w wersjach przed jedynką — narzędzie do introspekcji, warstwa serializacji, warstwa wywołań, biblioteka pomocnicza do dokumentacji i kilka mniejszych.

Nie jest to wada sama w sobie — wydzielanie kawałków do osobnych paczek jest dobrą praktyką. Ale przy ocenie ryzyka trzeba to policzyć uczciwie: istotna część drzewa zależności tego frameworka jest utrzymywana przez te same dwie osoby, które utrzymują framework. Jeśli w waszej organizacji obowiązuje polityka wobec zależności o niskiej liczbie opiekunów, ten projekt trafi w nią kilkukrotnie, nie raz.

Drobna ciekawostka z tej samej listy: wśród zależności produkcyjnych jest isort, czyli narzędzie do porządkowania importów, zwykle spotykane wyłącznie w zależnościach deweloperskich. Sugeruje to, że framework generuje kod Pythona — co przy narzędziu tworzącym projekty z szablonów ma sens.

Czego uczy lista zmian

Plik z historią zmian jest tu najlepszym źródłem oceny, bo pokazuje zarówno tempo, jak i charakter pracy — a przy okazji trzy rzeczy, których nie ma w README.

Pierwsza to furtka do JavaScriptu. Wydanie 0.12.3 dodało do komponentu osadzającego stronę obsługę wiadomości, umożliwiającą komunikację między JavaScriptem a Pythonem. Deklaracja „zero JavaScriptu" nie oznacza więc ściany: jeśli potrzebujesz biblioteki, której framework nie ma, możesz ją osadzić i porozumieć się z nią. To istotna informacja przy ocenie ryzyka wyboru — nie zamykasz sobie drogi.

Druga to dwie poprawki bezpieczeństwa w wydaniu 0.12.1, wymienione wśród innych: ograniczenie dopuszczalnych schematów adresów URL do http i https oraz poprawa bezpieczeństwa ścieżek w rejestrze ikon. Pierwsza to zamknięcie drogi dla adresów wykonujących skrypt, druga — utwardzenie przeciw wychodzeniu z katalogu. Obie są dokładnie tym, czego trzeba w tej klasie oprogramowania, i obie znaczą, że wcześniejsze wersje ich nie miały. Kto ma gdzieś instalację starszą niż 0.12.1, powinien ją podnieść.

Trzecia to dowód, że API jeszcze się rusza — i to potwierdza uczciwość deklarowanego statusu „beta". Wydanie 0.12 wprowadziło zmiany semantyki: komponenty zależne od atrybutów sesji są teraz automatycznie przebudowywane przy ich zmianie, a przebudowa następuje natychmiast po zmianie stanu, nie dopiero po zakończeniu obsługi zdarzenia. W tym samym wydaniu styl tekstu przestał mieć wartości domyślne — pominięte pola są teraz pozostawiane bez zmian. Każda z tych trzech zmian może wpłynąć na działający kod.

Warto też odnotować pozycję, która świadczy o dbałości: wśród poprawek 0.12.3 jest naprawienie sytuacji, w której tekst przycisku nie był używany jako etykieta dostępności. Przy interfejsie generowanym z Pythona to właśnie framework odpowiada za dostępność, bo autor aplikacji nie ma bezpośredniego dostępu do znaczników — więc każda taka poprawka jest po jego stronie, nie po twojej.

Bezpieczeństwo — tu jest luka

Muszę to powiedzieć wprost, bo w tej serii chwaliłem projekty za staranne polityki bezpieczeństwa i uczciwość wymaga tej samej miary w drugą stronę. Plik SECURITY.md tego projektu ma osiemdziesiąt osiem bajtów i zawiera dokładnie jedno zdanie: prośbę o zgłaszanie podatności na adres poczty w domenie Outlooka.

Dla biblioteki narzędziowej byłoby to wystarczające. Dla frameworka webowego, który obsługuje ruch HTTP i renderuje treść w przeglądarce, to bardzo mało. Nie ma opisu modelu zagrożeń, nie ma informacji o wspieranych wersjach, nie ma nic o tym, które powierzchnie są przewidziane do przyjmowania niezaufanych danych. A framework interfejsu użytkownika ma takich powierzchni dużo: wejście z formularzy, wgrywanie plików, adresy URL, treść wstrzykiwaną do drzewa dokumentu.

Praktyczne wnioski, jakie z tego wyciągam:

  • Traktuj to jak aplikację FastAPI i stosuj wszystkie normalne środki: odwrotne proxy z limitami rozmiaru żądań, nagłówki bezpieczeństwa, polityka bezpieczeństwa treści, limity częstości.
  • Nie wystawiaj tego na publiczny internet z niezaufanymi użytkownikami, dopóki sam nie zbadasz, jak framework obchodzi się z danymi wejściowymi. Do narzędzi wewnętrznych za uwierzytelnianiem — bez obaw.
  • Trzymaj wersję aktualną. Przy dwuosobowym zespole i braku polityki wspieranych wersji jedynym rozsądnym założeniem jest, że poprawki idą wyłącznie na najnowsze wydanie.

Kiedy to ma sens, a kiedy nie

Uczciwe pozycjonowanie jest tu ważniejsze niż lista funkcji, bo framework tej kategorii bywa wybierany do zadań, do których nie pasuje.

Ma sens przy narzędziach wewnętrznych — panelach administracyjnych, przeglądarkach danych, narzędziach dla działu obsługi, wewnętrznych kalkulatorach. Ma sens przy szybkim prototypie, który trzeba komuś pokazać, a nie ma budżetu na osobny frontend. Ma sens przy aplikacji okienkowej dostarczanej zespołowi. I ma sens szczególnie wtedy, gdy logika w Pythonie już istnieje — bo wtedy alternatywą jest napisanie warstwy API tylko po to, by móc ją wywołać z JavaScriptu.

Nie ma sensu przy publicznej stronie, dla której liczy się pozycja w wyszukiwarce i czas pierwszego wyrenderowania — tam wygrywają rozwiązania z renderowaniem po stronie serwera i generowaniem statycznym. Nie ma sensu, gdy projektant dostarcza gotowe makiety wymagające dokładnego odwzorowania, bo pracujesz w cudzym zestawie komponentów. I nie ma sensu przy zespole, który frontend już ma i umie — wtedy dodanie drugiego modelu programowania interfejsu jest kosztem, nie oszczędnością.

Warto dodać, że w tej niszy Rio nie jest sam. Istnieje kilka pythonowych frameworków obiecujących to samo, o różnym podejściu i różnej dojrzałości. To, co wyróżnia Rio, to model komponentowy najbliższy Reactowi wraz z pełnym typowaniem oraz możliwość uruchomienia tej samej aplikacji jako program okienkowy.

Pułapki w jednym miejscu

  • Wersja 0.12.x i status „beta" zadeklarowany przez autorów — API może się jeszcze zmieniać.
  • Dwuosobowy zespół, a do tego kilka zależności utrzymywanych przez tych samych autorów, wszystkie przed wersją 1.0.
  • Polityka bezpieczeństwa to jedno zdanie. Brak modelu zagrożeń i informacji o wspieranych wersjach — przy frameworku webowym to istotny brak.
  • JavaScript jest, tylko nie twój. Diagnozowanie problemów renderowania przechodzi przez granicę Python–TypeScript.
  • Pracujesz w cudzym zestawie komponentów. Dokładne odwzorowanie makiety projektanta będzie trudniejsze niż w CSS-ie.
  • Nie dla publicznych stron nastawionych na wyszukiwarki. Framework wykrywa roboty, ale to nie to samo co renderowanie po stronie serwera.
  • Aplikacja jest procesem ASGI z sesją. Skalowanie poziome wymaga przemyślenia trwałości stanu, tak jak przy każdym interfejsie sterowanym z serwera.
  • Wersje starsze niż 0.12.1 nie mają dwóch poprawek bezpieczeństwa — ograniczenia schematów URL i bezpieczeństwa ścieżek w rejestrze ikon.
  • Wydanie 0.12 zmieniło semantykę przebudowy komponentów i wartości domyślne stylu tekstu. Przy aktualizacji przeczytaj listę zmian.
  • Wymagany Python 3.10 lub nowszy.

Podsumowanie

Rio jest dobrze zaprojektowaną odpowiedzią na realny problem: dla zespołu pracującego w Pythonie napisanie interfejsu wewnętrznego narzędzia nie powinno wymagać wejścia w cały osobny ekosystem. Model komponentowy jest tu przemyślany, typowanie działa, a możliwość dostarczenia tej samej aplikacji jako programu okienkowego jest realną zaletą.

  • Komponenty w stylu Reacta w czystym Pythonie — atrybuty jako stan, metoda build zwracająca drzewo, bez osobnego mechanizmu ustawiania stanu.
  • Pełne typowanie, dzięki któremu edytor podpowiada i wyłapuje błędy bez dodatkowych narzędzi dla szablonów.
  • Ponad pięćdziesiąt wbudowanych komponentów plus narzędzia deweloperskie w pakiecie.
  • Ta sama aplikacja w przeglądarce i w oknie — różnicą jest jedno wywołanie.
  • Zwyczajna aplikacja ASGI pod spodem — FastAPI i uvicorn, więc wdrożenie idzie normalnymi ścieżkami.
  • Narzędzie wiersza poleceń z szablonami, które daje działający projekt jednym poleceniem.

Projekt jest wydany na licencji Apache-2.0 — permisywnej, z jawnym udzieleniem licencji patentowej i wymogiem odnotowania zmian w modyfikowanych plikach. Możesz go używać komercyjnie i dostarczać klientom bez obowiązku otwierania własnego kodu, a README dodaje wprost, że wkład kontrybutorów również trafia na tę licencję, bez dodatkowych warunków. To czysty układ, bez podwójnego licencjonowania i bez wersji płatnej — z jednym zastrzeżeniem, które przy tej licencji zawsze warto powtórzyć: Apache-2.0 nie daje żadnej gwarancji ani wsparcia, a przy dwuosobowym zespole i wersji przed jedynką to nie jest formalność, a rzeczywisty parametr decyzji.