PythonのWebフレームワークReflexを使ってみた

Jun 23, 2024 19:10 · 4859 words · 10 minute read python docker

同僚にReflexを紹介してもらったので、ドキュメントを読んで少し触ってみました。 内容をまとめてブログに残しておきます。

2024年6月時点、Reflex0.5.4時点の情報です。

目次

Reflexとは

PythonでWebアプリを開発できるフレームワークです。

公式URL: Reflex · Web apps in Pure Python

Pythonで書いたコードをビルドすると、ReactのfrontendとFastAPIのbackendを出力します。 フロント側はReactに変換されることもあり、ReactっぽいComponentの書き方で画面を組み立ててreturnします。

1つのファイルでバックエンド部分とフロントエンド部分を記載できるのも面白い点です。 久しくフロントエンドの動向を追いかけていませんでしたが、他のフレームワークでもこのような実装をできるというのを見た覚えがあるので、最近の流行りなのかもしれません。

code image

ORMやUIを調整するツールも組み込まれているので、一通り必要な機能は揃っていそうです。

Reflexの良さそうなところ

ドキュメントをざっと読んで「なるほど良さそうだ」と感じたポイントを列挙します。

フロントエンドもPythonで実装できる

ReflexはフロントエンドもPythonで実装します。

「使い勝手のいいUIを作りたい」

「でもフロントエンド開発のためにReactなどの環境を別途作り、バックエンドと別々に開発運用するのは面倒。。。」

という人にとって、それなりに使いやすいWebアプリをPythonだけで開発できるのはありがたいですね。

DjangoやFlaskなどのHTMLと組み合わせたテンプレートエンジンよりもReactに近い印象です。 公式ドキュメントに書いてあるサンプルコードはこんな感じ。

import reflex as rx


class State(rx.State):
    count: int = 0

    def increment(self):
        self.count += 1

    def decrement(self):
        self.count -= 1


def index():
    return rx.hstack(
        rx.button(
            "Decrement",
            color_scheme="ruby",
            on_click=State.decrement,
        ),
        rx.heading(State.count, font_size="2em"),
        rx.button(
            "Increment",
            color_scheme="grass",
            on_click=State.increment,
        ),
        spacing="4",
    )


app = rx.App()
app.add_page(index)

非同期の処理を標準でサポートしている

非同期処理が標準でサポートされていて、「非同期タスクに合わせて画面表示を更新する」といった実装が簡単に実現できそうでした。 例えばFlaskに入っているJinja2やDjangoのテンプレートエンジンだと、何かしら追加でJavaScriptの実装が必要です。

必要そうなComponentが一通り揃っている

標準で多くのComponentが用意されています。

Component Library

Tailwindを使おうか?それともChakra UIにしようか?なんて迷うことなく、既にあるComponentで色々な表現ができそうです。 TailwindとChakra UIも公式にサポートしているので、ライブラリの追加無しに凝った表現もできそうです。

Styling

もちろん一般的なCSSも使えます。

Style and Layout Props

ReactとFastAPIの資産がほぼそのまま使えそう

ReflexはPythonコードをBuildしてReactのフロントエンドコードとFastAPIバックエンドコードを出力します。 というわけで元々Reactとの親和性は高いですし、FastAPIの機能をそのまま使えます。

既存のReactのComponentを読み込む方法も公式ドキュメントでサポートされています。

Wrapping-react Full Guide

また、Reflexでは認証関係の機能はまだサポートしていませんが、FastAPIの既存のライブラリがそのまま使えそうです。 例えばOauthの場合、FastAPIのOauth2 SampleやAuthlibを使って認証処理を実装できると思います。

既存資産を使えるというのは心強いですね。巨人の肩に乗っていきましょう。

コマンドのサポートが手厚い(開発チームの本気を感じる)

reflexコマンドのサポートがかなり手厚そうです。 reflexコマンド1発でデプロイが完了したり、自作ComponentやPython Packageの公開までサポートしてくれます。

Componentの作成までサポートすることでコミュニティを盛り上げたいという戦略なのでしょう。 開発チームが長期的な視点で戦略的に開発していることが伺えます。

無料のホスティング環境を提供している(開発チームの本気を感じる)

コマンドが手厚いだけではなく、無料のホスティング環境まで提供しています。 GitHubかGoogleアカウントでログインするとreflex deployコマンドでWebアプリを公開できます。

Docker Containerが動く環境があればどこでも動く

ReflexはContainerで動かすことを前提にしているらしく、reflex deployを実行すると新しいContainerを作ってアプリをdeployしているようです。 そんなわけで、Containerが動く環境であればどこでもWebアプリを公開できます。

Self Hosting (reflex.dev)

ある程度のセキュリティは担保されていそう

Reflectは内部でReactやSQL Archemyを使っています。 そのため、通常の使い方をしていれば、それらに組み込まれたセキュリティ機能の恩恵を受けることができそうです。

Reflexの気になるところ

細かな設定をいじれない

reflexコマンドがかなり手厚いので、「reflex run」をすればWebアプリが起動し、「reflex deploy」や「reflex run –env prod」を実行するだけでProduction buildができます。 これはとても便利な半面、細かな設定を自分で変更できなさそうな点が気になりました。

セキュリティ面

良さそうなところで「ある程度のセキュリティが担保されていそう」と書いたのですが、気になる部分もあります。 reflexコマンドがbuildやdeployを実行してくれているのでWebアプリのセキュリティに関わる設定を自分で調整することができなさそうです。 今はまだReflexのversionは0.5.4なので、将来version1.0になる頃には設定できる範囲が増えているかもしれません。

アクセス数や負荷が高い環境で耐えられるのか?

ReflexはReactフロントエンドとFastAPIバックエンドを組み合わせて使うフレームワークです。 そのためフレームワークレベルでフロントエンドとバックエンドの通信や、バックエンド側でのState管理などを実現しています。

Stateの実装具合によってはそれなりに負荷がかかりそうな気がするので、アクセス数が多い場合にどのくらい性能が出せるのか疑問です。 Containerで動く前提なので、k8s的な環境で自動でスケールしたら負荷の問題はコントロールできるだろうなとは思いますが。

Reflexの使いどころ

上記のいい点と気になる点を踏まえて、下記のような時にReflexを使うと良さそうかなと感じました。

寿命が長くないWebアプリ

Reflexはまだversion1になっていないですし、今後がどうなるかわかりません。 reflexコマンドのサポート内容やホスティングサービスまで提供している点から推測するに、かなり開発に力が入っていそうです。 そのため、すぐに開発が終了することはないと思いますが、とはいえまだ安定版ではないという前提で使うべきです。

急いで作りたい or あまり工数をかけられないWebアプリ

プロトタイピングや社内で限定的に使う前提のWebアプリなど、時間や工数が掛けられない場合に向いていそうです。 デフォルトで組み込まれたComponentやORM、外部のReact ComponentやFastAPI向けの資産を使うことで、短期間で実装できると思います。

動かしてみた

Dockerで動かしてみました。 フロントエンドのReactとバックエンドのFastAPIが動作するので、下記のようにそれぞれが使うポートを指定してContainerを動かします。

docker container run -it --name reflex --mount type=bind,source="$(pwd)"/src/,target=/mnt -p 8000:8000 -p 3000:3000 --rm python:3.10.8-slim-bullseye bash

プロジェクトの作成と実行はこんな感じ。 Reflexはunzipとcurlを使っているので、手動で追加しました。

pip install reflex
apt update
apt insatall unzip
apt install curl
reflex init

実行してみます。

reflex run
───────────────────────────────────────────────── Starting Reflex App ──────────────────────────────────────────────────
Compiling: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 15/15 0:00:00
───────────────────────────────────────────────────── App Running ──────────────────────────────────────────────────────
App running at: http://localhost:3000

問題なく動きました。

8000ポートのバックエンドも問題なく動いています。

動作速度はどうだったのか?

以前Next.jsやReactをDockerで動かした時、開発環境の動作速度に難がありました。

React系のアプリを開発するときには、頻繁にファイルアクセスが発生します。 WSL2やDockerからHost PCにあるプロジェクトをmountした場合、Host PCとのファイルのやり取りが遅いことで、ファイルを保存してからWebアプリが実行するまでの速度が非常に遅くなりました。

Reflexの場合は、決して早いとは言えないまでも、ありえないレベルの遅さではなかったかなと思います。 動作状況から推察するに、ReflexはPythonからBuildしたReactとFastAPIはContainer上のファイルシステム(※)で動いているっぽいです。 そのため、下記の2パターンでそれほど動作速度の違いはありませんでした。

  • Containerのファイルシステム(※)にコードを置いて実行した場合
  • Host PCのファイルシステムにあるコードをContainerでmountして実行した場合

※正確な表現ではないと思いますが、イメージを伝えるために便宜的にファイルシステムという言葉を使っています。

ソースコードがどちらのファイルシステムにある場合でも動作する時間に大差はなく、PythonのReflexコードをReactなりFastAPIにBuildする時間が2-3秒かかるという印象でした。

Build済みのフロントエンドはReactなので、ブラウザへの読み込みが終わったら、後は普通のReactアプリの速度という印象でした。

最後に

Reflexのドキュメントをざっと読み、実際に動かしてみました。 Webアプリ開発に必要な機能は一通り揃っており、なかなか便利そうなので、「今後に期待のフレームワーク」という印象でした。

社内で限定的に公開するアプリの開発などで試してみたいですね。

tweet Share