Web 開発は、プログラミングの最も人気のあるユースケースの 1 つです。 Python は、世界で最も人気のあるプログラミング言語の 1 つです。では、なぜ Python で Web アプリを構築できないのでしょうか?
UI の作成は簡単なはずですが、たとえチームに優秀なエンジニアがいたとしても、新しい言語やツールを学習するためのオーバーヘッドは大きな障壁でした。多くの場合、UI の作成は実際に行っている作業よりも難しい場合があります!
内部では、Reflex アプリは React フロントエンド アプリと FastAPI バックエンド アプリにコンパイルされます。 UI のみが Javascript にコンパイルされます。アプリのロジックと状態管理はすべて Python に残り、サーバー上で実行されます。 Reflex は WebSocket を使用して、フロントエンドからバックエンドにイベントを送信し、バックエンドからフロントエンドに状態の更新を送信します。
Python でアプリを構築する方法はすでにいくつかありましたが、どれも私たちのニーズには合いませんでした。
一方で、運用グレードの Web アプリの構築に最適な Django や Flask などのフレームワークがあります。ただし、処理されるのはバックエンドのみです。フロントエンドとバックエンドを接続するための多くの定型コードを記述するだけでなく、依然として JavaScript とフロントエンド フレームワークを使用する必要があります。
一方、Dash や Streamlit などの純粋な Python ライブラリは小規模なプロジェクトには最適ですが、特定のユースケースに限定されており、完全な Web アプリを構築するための機能やパフォーマンスがありません。アプリの機能と複雑さが増すにつれて、フレームワークの限界に達することがあります。その時点で、アイデアをフレームワークに合わせて制限するか、プロジェクトを破棄して「実際の Web フレームワーク」を使用して再構築する必要があります。
私たちは、あらゆるアプリをサポートできる柔軟性と強力さを維持しながら、簡単かつ直感的に使い始めることができるフレームワークを作成することで、このギャップを埋めたいと考えています。
ここで、これらの目標を達成するために Reflex をどのように構築したかを見ていきましょう。
フルスタック Web アプリは、フロントエンドとバックエンドで構成されます。フロントエンドはユーザー インターフェイスであり、ユーザーのブラウザ上で実行される Web ページとして提供されます。バックエンドはロジックと状態管理 (データベースや API など) を処理し、サーバー上で実行されます。
従来の Web 開発では、これらは通常 2 つの別個のアプリであり、異なるフレームワークや言語で記述されることがよくあります。たとえば、Flask バックエンドと React フロントエンドを組み合わせることができます。このアプローチでは、2 つの別々のアプリを保守する必要があり、最終的にフロントエンドとバックエンドを接続するための定型的なコードを大量に記述することになります。
すべてに Python を使用しながら、単一のコードベースでフロントエンドとバックエンドの両方を定義することで、Reflex でこのプロセスを簡素化したいと考えています。開発者は、低レベルの実装の詳細ではなく、アプリのロジックのみを考慮する必要があります。
私たちは、Reflex アプリがエンド ユーザーにとっては従来の Web アプリのように見えると同時に、開発者にとっては構築と保守が簡単であるようにしたいと考えています。これを実現するために、私たちは成熟した人気のある Web テクノロジーを基盤に構築しました。
アプリをリフレックス実行すると、Reflex はフロントエンドを単一ページの Next.js アプリにコンパイルし、ブラウザーでアクセスできるポート (デフォルトでは 3000) で提供します。
フロントエンドの仕事は、アプリの状態を反映し、ユーザーが UI を操作したときにイベントをバックエンドに送信することです。フロントエンドでは実際のロジックは実行されません。
Reflex フロントエンドは、複雑な UI を作成するために一緒に構成できるコンポーネントを使用して構築されます。 HTML と Python を組み合わせたテンプレート言語を使用する代わりに、Python 関数を使用して UI を定義します。
内部では、コンポーネントは React コンポーネントにコンパイルされます。
私たちのコアコンポーネントの多くは、人気のある React コンポーネントライブラリである Radix に基づいています。他にもグラフ作成やデータテーブルなどのコンポーネントが多数あります。
React を選択したのは、巨大なエコシステムを持つ人気のあるライブラリであるためです。私たちの目標は、Web エコシステムを再構築することではなく、Python 開発者が Web エコシステムにアクセスできるようにすることです。
これにより、ユーザーが必要なコンポーネントがない場合に独自のコンポーネントを持ち込むこともできます。ユーザーは独自の React コンポーネントをラップし、他のユーザーが使用できるように公開できます。時間をかけて、ユーザーが他の人が構築したコンポーネントを簡単に見つけて使用できるように、サードパーティ コンポーネントのエコシステムを構築していきます。
私たちは、開発者がアプリの外観を完全に制御できるようにしながら、Reflex アプリがすぐにでも適切に見えるようにしたいと考えました。
アプリ全体にダーク モードやアクセント カラーなどの高レベルのスタイル オプションを設定して、統一された外観と操作性を実現できるコア テーマ システムがあります。
これに加えて、Reflex コンポーネントは CSS のフルパワーを使用してスタイル設定できます。 Emotion ライブラリを活用して「CSS-in-Python」スタイルを可能にするため、任意の CSS プロップをキーワード引数としてコンポーネントに渡すことができます。これには、値のリストを渡すことによる応答性のプロパティが含まれます。
Reflex では、フロントエンドのみが Javascript にコンパイルされ、ユーザーのブラウザ上で実行されますが、すべての状態とロジックは Python に保持され、サーバー上で実行されます。リフレックス実行すると、フロントエンドが WebSocket 経由で接続する FastAPI サーバー (デフォルトではポート 8000) が起動されます。
すべての状態とロジックは State クラス内で定義されます。
状態は、vars と イベント ハンドラー で構成されます。
Var は、時間の経過とともに変化する可能性のあるアプリ内の値です。これらは State クラスのクラス属性として定義され、JSON にシリアル化できる任意の Python タイプにすることができます。
イベント ハンドラーは、ユーザーが UI を操作するときに呼び出される State クラスのメソッドです。これらは Reflex で変数を変更できる唯一の方法であり、ボタンのクリックやテキスト ボックスへの入力などのユーザーのアクションに応じて呼び出すことができます。
イベント ハンドラーはバックエンドで実行されるため、その中で任意の Python ライブラリを使用できます。
通常、Web アプリを作成するときは、フロントエンドとバックエンドを接続するために大量の定型コードを作成する必要があります。 Reflex を使用すると、そのことを心配する必要はありません。フロントエンドとバックエンド間の通信は私たちが処理します。開発者はイベント ハンドラー ロジックを記述するだけで済み、変数が更新されると UI も自動的に更新されます。
ユーザーは、ボタンをクリックする、テキスト ボックスに入力する、要素の上にマウスを置くなど、さまざまな方法で UI を操作できます。 Reflex では、これらを イベント トリガー と呼びます。
フロントエンドでは、すべての保留中のイベントのイベント キューを維持します。イベントは 3 つの主要なデータで構成されます:
イベントがトリガーされると、キューに追加されます。
一度に 1 つのイベントのみが処理されるようにする処理フラグがあります。これにより、状態が常に一貫していることが保証され、同時に状態を変更する 2 つのイベント ハンドラーによる競合状態が発生しません。これには、UI をブロックせずにバックグラウンドでイベントを実行できるバックグラウンド イベントなどの例外があります。
イベントの処理準備が完了すると、WebSocket 接続を通じてバックエンドに送信されます。
イベントが受信されると、バックエンドで処理されます。
Reflex は、クライアント トークンとその状態の間のマッピングを維持する 状態マネージャー を使用します。デフォルトでは、状態マネージャーは単なるメモリー内の辞書ですが、データベースまたはキャッシュを使用するように拡張できます。本番環境では、状態マネージャーとして Redis を使用します。
ユーザーの状態を取得したら、次のステップは引数を指定してイベント ハンドラーを実行することです。
イベント ハンドラーが戻る (または譲る) たびに、状態を状態マネージャーに保存し、状態更新 をフロントエンドに送信して UI を更新します。
状態が増大してもパフォーマンスを維持するために、Reflex は内部的にイベント ハンドラー中に更新された変数 (ダーティ vars) を追跡します。
イベント ハンドラーの処理が完了すると、すべてのダーティ変数を見つけて、フロントエンドに送信する状態更新を作成します。
新しい状態を状態マネージャーに保存し、状態の更新をフロントエンドに送信します。
その後、フロントエンドは UI を更新して新しい状態を反映します。
これが Reflex が内部でどのように機能するかについての概要を理解できることを願っています。状態シャーディングやコンパイラの最適化などの機能を通じて、Reflex をどのようにスケーラブルでパフォーマンスの高いものにしたのかを共有する投稿を今後さらに投稿していく予定です。
以上がPure Python Web フレームワークの設計の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。