paint-brush
純粋な Python Web フレームワークの設計@reflexdev
277 測定値

純粋な Python Web フレームワークの設計

Reflex.dev7m2024/09/23
Read on Terminal Reader

長すぎる; 読むには

Reflex は、Python 開発者が Web アプリをより速く構築できるようにするオープンソース フレームワークです。フロントエンドとバックエンドの両方を単一の言語である Python (pip install reflex) で構築できます。JavaScript や Web 開発の経験は必要ありません。
featured image - 純粋な Python Web フレームワークの設計
Reflex.dev HackerNoon profile picture
0-item


Web 開発は、プログラミングの最も一般的な使用例の 1 つです。Python は、世界で最も人気のあるプログラミング言語の 1 つです。では、なぜ Python で Web アプリを構築できないのでしょうか?


UI の作成は簡単なはずですが、チームに優秀なエンジニアがいても、新しい言語やツールを学習するオーバーヘッドが大きな障壁となっていました。多くの場合、UI の作成は実際の作業よりも難しいことがあります。私たちはまさにこの問題を解決するために、オープンソースの Python Web フレームワークである Reflex を構築しました。

要約

内部的には、Reflex アプリはReactフロントエンド アプリとFastAPIバックエンド アプリにコンパイルされます。UI のみが Javascript にコンパイルされ、アプリのロジックと状態管理はすべて Python のままで、サーバー上で実行されます。Reflex はWebSocket を使用して、フロントエンドからバックエンドにイベントを送信し、バックエンドからフロントエンドに状態の更新を送信します。

既存のPythonソリューション

Python でアプリを構築する方法はすでにいくつかありましたが、どれも私たちのニーズに合っていませんでした。


一方では、 DjangoFlaskのような、製品レベルの Web アプリを構築するのに最適なフレームワークがあります。ただし、これらのフレームワークはバックエンドのみを処理します。フロントエンドとバックエンドを接続するには、JavaScript とフロントエンド フレームワークを使用する必要があり、大量の定型コードを記述する必要があります。


一方、 DashStreamlitなどの純粋な Python ライブラリは、小規模なプロジェクトには最適ですが、特定のユースケースに限定されており、完全な Web アプリを構築するための機能とパフォーマンスがありません。アプリの機能と複雑さが増すにつれて、フレームワークの限界に達することがあります。その時点で、フレームワークに合わせてアイデアを制限するか、プロジェクトを破棄して「実際の Web フレームワーク」を使用して再構築する必要があります。


私たちは、あらゆるアプリをサポートできる柔軟性と強力さを保ちながら、使い始めるのが簡単で直感的なフレームワークを作成することで、このギャップを埋めたいと考えています。

反射の目標

  • Pure Python : すべてに 1 つの言語を使用します。
  • 簡単に始められます: Web 開発の経験を必要とせずにアイデアを簡単に構築できます。
  • 完全な柔軟性: Web アプリは、従来の Web フレームワークのカスタマイズ性とパフォーマンスに一致する必要があります。
  • バッテリー付属: フロントエンドからバックエンド、デプロイメントまで、フルスタックを処理します。


それでは、これらの目標を達成するために Reflex をどのように構築したかを詳しく見ていきましょう。

リフレックスアーキテクチャ

フルスタック Web アプリは、フロントエンドとバックエンドで構成されています。フロントエンドはユーザー インターフェイスであり、ユーザーのブラウザーで実行される Web ページとして提供されます。バックエンドはロジックと状態管理 (データベースや API など) を処理し、サーバー上で実行されます。従来の Web 開発では、これらは通常 2 つの別々のアプリであり、異なるフレームワークまたは言語で記述されることがよくあります。たとえば、Flask バックエンドと React フロントエンドを組み合わせることができます。このアプローチでは、2 つの別々のアプリを維持する必要があり、フロントエンドとバックエンドを接続するために大量の定型コードを記述することになります。


Reflex では、フロントエンドとバックエンドの両方を単一のコードベースで定義し、すべてに Python を使用することで、このプロセスを簡素化したいと考えています。開発者は、低レベルの実装の詳細ではなく、アプリのロジックのみを気にする必要があります。




フロントエンド

Reflex アプリは、エンド ユーザーにとっては従来の Web アプリのように見え、使いやすく、開発者にとっては簡単に構築および保守できるものであってほしいと考えています。これを実現するために、成熟した人気の Web テクノロジーを基盤として構築しました。


アプリをreflex runと、Reflex はフロントエンドを単一ページのNext.jsアプリにコンパイルし、ブラウザーでアクセスできるポート (デフォルトでは3000 ) で提供します。


フロントエンドの役割は、アプリの状態を反映し、ユーザーが UI を操作したときにバックエンドにイベントを送信することです。フロントエンドでは実際のロジックは実行されません。

コンポーネント

Reflex フロントエンドは、複雑な UI を作成するために組み合わせることができるコンポーネントを使用して構築されます。HTML と Python を組み合わせたテンプレート言語を使用する代わりに、Python 関数を使用して UI を定義します。


内部的には、コンポーネントは React コンポーネントにコンパイルされます。コア コンポーネントの多くは、人気の React コンポーネント ライブラリであるRadixに基づいています。グラフ作成やデータ テーブルなどのコンポーネントも多数あります。React を選んだのは、巨大なエコシステムを持つ人気のライブラリだからです。私たちの目標は、Web エコシステムを再現することではなく、Python 開発者がアクセスできるようにすることです。


これにより、必要なコンポーネントがない場合でも、ユーザーは独自のコンポーネントを持ち込むことができます。ユーザーは独自の React コンポーネントをラップし、他のユーザーが使用できるように公開できます。時間の経過とともに、サードパーティ コンポーネント エコシステムを構築し、ユーザーが他のユーザーが構築したコンポーネントを簡単に見つけて使用できるようにします。

スタイリング

私たちは、Reflex アプリがすぐに美しく表示されるようにしつつ、開発者がアプリの外観を完全に制御できるようにしたいと考えました。


当社には、アプリ全体にダーク モードやアクセント カラーなどの高度なスタイル オプションを設定して、統一された外観と操作感を実現できるコア テーマ システムがあります。


さらに、 Reflexコンポーネントは CSS のフルパワーを使用してスタイル設定できます。Emotion ライブラリを活用して「CSS-in-Python」スタイル設定を可能にしたので、任意の CSS プロパティをキーワード引数としてコンポーネントに渡すことができます。これには、値のリストを渡すレスポンシブ プロパティも含まれます。

バックエンド

Reflex では、フロントエンドのみが Javascript にコンパイルされ、ユーザーのブラウザ上で実行されますが、すべての状態とロジックは Python のままで、サーバー上で実行されます。 reflex runすると、フロントエンドが Websocket 経由で接続する FastAPI サーバー (デフォルトではポート8000 ) が起動します。


すべての状態とロジックはStateクラス内で定義されます。状態はvarイベント ハンドラーで構成されます。var は、時間の経過とともに変化する可能性のあるアプリ内の任意の値です。これらはStateクラスのクラス属性として定義され、JSON にシリアル化できる任意の Python 型にすることができます。


イベント ハンドラーは、ユーザーが UI を操作するときに呼び出されるStateクラスのメソッドです。イベント ハンドラーは、Reflex で変数を変更できる唯一の方法であり、ボタンのクリックやテキスト ボックスへの入力などのユーザー アクションに応じて呼び出すことができます。

イベント ハンドラーはバックエンドで実行されるため、イベント ハンドラー内で任意の Python ライブラリを使用できます。


イベント処理

通常、Web アプリを作成する場合、フロントエンドとバックエンドを接続するために、大量の定型コードを記述する必要があります。Reflex を使用すると、その心配は不要です。フロントエンドとバックエンド間の通信は Reflex が処理します。開発者はイベント ハンドラー ロジックを記述するだけで、変数が更新されると UI が自動的に更新されます。

イベントトリガー

ユーザーは、ボタンをクリックしたり、テキスト ボックスに入力したり、要素の上にマウスを移動したりするなど、さまざまな方法で UI を操作できます。Reflex では、これらをイベント トリガーと呼びます。

イベントキュー

フロントエンドでは、保留中のすべてのイベントのイベント キューを維持します。イベントは、次の 3 つの主要なデータで構成されます。

  • クライアント トークン: 各クライアント (ブラウザー タブ) には、それを識別するための一意のトークンがあります。これにより、バックエンドはどの状態を更新するかを知ることができます。
  • イベント ハンドラー: 状態に対して実行するイベント ハンドラー。
  • arguments : イベント ハンドラーに渡す引数。


イベントがトリガーされると、キューに追加されます。一度に 1 つのイベントのみが処理されるようにするためのprocessingフラグがあります。これにより、状態が常に一貫しており、2 つのイベント ハンドラーが同時に状態を変更する競合状態が発生しないことが保証されます。これには例外があり、UI をブロックせずにバックグラウンドでイベントを実行できるバックグラウンド イベントなどがあります。


イベントの処理準備が完了すると、WebSocket 接続を介してバックエンドに送信されます。

州マネージャー

イベントが受信されると、バックエンドで処理されます。Reflex は、クライアント トークンとその状態間のマッピングを維持する状態マネージャーを使用します。デフォルトでは、状態マネージャーは単なるメモリ内辞書ですが、データベースまたはキャッシュを使用するように拡張できます。本番環境では、状態マネージャーとして Redis を使用します。

イベント処理

ユーザーの状態を取得したら、次のステップは引数を使用してイベント ハンドラーを実行することです。

州の最新情報

イベント ハンドラーが戻る (または実行する) たびに、状態マネージャーに状態を保存し、状態の更新をフロントエンドに送信して UI を更新します。状態が拡大してもパフォーマンスを維持するために、Reflex は内部的にイベント ハンドラーの実行中に更新された変数 (ダーティ変数) を追跡します。


イベント ハンドラーの処理が完了すると、すべてのダーティ変数が検索され、フロントエンドに送信する状態更新が作成されます。

新しい状態を状態マネージャーに保存し、状態の更新をフロントエンドに送信します。フロントエンドは UI を更新して新しい状態を反映します。

結論

この記事が、Reflex が内部でどのように動作するかについてのよい概要を提供してくれたことを願っています。今後、状態シャーディングやコンパイラーの最適化などの機能を通じて、Reflex をスケーラブルかつ高性能にする方法を紹介する記事をさらに公開する予定です。