understanding-streamlit-architecture について
Streamlit のアーキテクチャを把握し、実装箇所を探すための開発者向けドキュメントスキルです。Python バックエンド、React フロントエンド、通信プロトコルを扱います。
主な機能
- 01バックエンドとフロントエンドの構成整理
- 02WebSocket と Protobuf 通信の解説
- 03再実行とセッション状態の説明
- 04機能実装のための案内
活用シーン
- 01Streamlit の実行モデルの把握
- 02UI 要素の前後の実装箇所の特定
- 03Streamlit の機能開発
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ streamlit/ streamlit --skill understanding-streamlit-architectureインストール後、Claude Code で/understanding-streamlit-architectureを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/backend.mdcommunication.mdelement-identity.mdfrontend.mdlayout.md詳細
Streamlit のアーキテクチャを理解する
Streamlit は、Protocol Buffers を使用した双方向 WebSocket 通信を行うクライアントサーバーアプリケーションです。
このファイルは、簡易的なメンタルモデルとナビゲーションインデックスとして使用してください。実装の詳細については、references/backend.md、references/frontend.md、references/communication.md を参照してください。
概念の用語集
| 概念 | 説明 | 主要ファイル |
|---|---|---|
| コマンド | Streamlit の公開 API(st.* 名前空間)で公開されているあらゆる関数です。コマンドは要素/ウィジェットを作成したり、実行フローを制御したり、アプリの動作を設定したりできます。 | lib/streamlit/delta_generator.py、lib/streamlit/elements/、lib/streamlit/commands/ |
| 要素 | Streamlit のすべての UI コンポーネントを総称する用語です。ウィジェット、コンテナ、表示要素を含みます。Element.proto では約 50 以上の型の oneof ユニオンとして表現されます。 | proto/streamlit/proto/Element.proto、lib/streamlit/elements/ |
| ウィジェット | ユーザーの操作によって通常は再実行をトリガーするインタラクティブな要素(button、slider、text_input)です。値は戻り値または st.session_state を介してアクセスできます。on_change="ignore" をサポートするウィジェットは、他の何かが再実行するまで再実行せずにブラウザー内で更新されます。一部の要素は条件付きでウィジェットになります(例: on_select を指定した dataframe/chart)。 | lib/streamlit/elements/widgets/、frontend/lib/src/components/widgets/ |
| 表示要素 | それ自体では再実行をトリガーせずにコンテンツをレンダリングする非インタラクティブな要素(text、markdown、image、chart)です。 | lib/streamlit/elements/、frontend/lib/src/components/elements/ |
| コンテナ | 要素を空間的にグループ化するレイアウトブロックです(sidebar、columns、expander、tabs、form)。要素ツリーでは BlockNode として表現されます。 | lib/streamlit/elements/layouts.py、Block.proto |
| DeltaGenerator | st オブジェクトです。UI デルタをキューに追加する API のエントリーポイントです。mixin パターンを使用してすべての st.* コマンドを構成します。 | lib/streamlit/delta_generator.py |
| セッションステート | 再実行をまたいでデータを永続化するセッションごとの辞書(st.session_state)です。ウィジェットの値とユーザー変数を保存します。 | lib/streamlit/runtime/state/session_state.py |
| 再実行 | 現在のページに対してユーザースクリプトを再実行することです。ウィジェットの操作、st.rerun()、ファイルの変更、またはフラグメントのタイマーによってトリガーされます。セッションステートを保持したまま要素ツリーを再構築します。 | lib/streamlit/runtime/scriptrunner/script_runner.py、lib/streamlit/commands/execution_control.py |
| フォーム | ウィジェットの入力をバッチ処理し、フォームの送信まで再実行を遅延させるコンテナ(st.form)です。 | lib/streamlit/elements/form.py、WidgetStateManager.ts |
| フラグメント | スクリプト全体を再実行せずに、特定の UI セクションの部分的な再実行を可能にするデコレーター(@st.fragment)です。 | lib/streamlit/runtime/fragment.py |
| キャッシュ | 冗長な計算を避けるために関数の結果をメモ化するデコレーター(@st.cache_data、@st.cache_resource)です。 | lib/streamlit/runtime/caching/ |
| ページ | st.navigation() と st.Page() を使用するか、pages/ ディレクトリからの自動検出を使用するマルチページアプリシステムです。 | lib/streamlit/navigation/、lib/streamlit/runtime/pages_manager.py |
| 設定 | サーバー、クライアント、テーマの設定を制御する .streamlit/config.toml によるアプリ設定です。 | lib/streamlit/config.py、lib/streamlit/config_option.py |
| テーマ設定 | 設定またはテーマエディターで定義されるカスタマイズ可能な UI テーマ(Light/Dark/Custom)です。 | lib/streamlit/runtime/theme_util.py、frontend/lib/src/theme/ |
| シークレット | .streamlit/secrets.toml(ローカル)またはプラットフォーム設定(デプロイ済み)による安全な認証情報の保存です。st.secrets を介してアクセスします。 | lib/streamlit/runtime/secrets.py |
| 接続 | キャッシュとシークレットの統合を組み込んだデータベース/サービスの抽象化(st.connection)です。 | lib/streamlit/connections/ |
| カスタムコンポーネント | React/iframe を使用したユーザー構築の拡張機能です。v1(レガシー): declare_component() API。v2(現行): 状態管理が改善された双方向コンポーネント。 | frontend/component-lib/、frontend/component-v2-lib/、lib/streamlit/components/v1/、lib/streamlit/components/v2/ |
| 静的ファイルの配信 | static/ ディレクトリ内のファイルは、/app/static/* を介して直接配信されます(静的配信が有効な場合)。 | lib/streamlit/web/server/server.py、lib/streamlit/web/server/starlette/starlette_routes.py |
| アプリのテスト | ユーザーの操作をシミュレートし、レンダリングされた出力を検査するためのテストフレームワーク(AppTest)です。 | lib/streamlit/testing/ |
コアとなるメンタルモデル
flowchart TB
subgraph Backend["Backend (Python)"]
Script[User Script]
DG[DeltaGenerator]
Runtime[Runtime/AppSession]
end
subgraph Protocol["WebSocket + Protobuf"]
FM[ForwardMsg]
BM[BackMsg]
end
subgraph Frontend["Frontend (React)"]
App[App.tsx]
Tree[AppRoot Tree]
Renderer[ElementNodeRenderer]
WSM[WidgetStateManager]
end
Script --> DG
DG --> FM
FM --> App
App --> Tree
Tree --> Renderer
Renderer --> WSM
WSM -->|User interaction| BM
BM --> Runtime
Runtime -->|Rerun| Script
重要な洞察: スクリプトの実行は再実行駆動です。ほとんどのウィジェット操作が再実行(アプリ全体またはフラグメントスコープ)をトリガーします。状態は st.session_state とキャッシュデコレーターによって永続化されます。
実行モデル
Streamlit の実行モデルは従来の Web フレームワークとは異なります。
再実行のトリガー:
- ウィジェット操作: ユーザーがボタンをクリックする、スライダーを動かすなど(
on_change="ignore"を指定したウィジェットは再実行なしで更新されます) - ソースコードの変更: ファイルウォッチャーがスクリプトの変更を検知
st.rerun(): 明示的なプログラムによる再実行- フラグメントタイマー:
@st.fragment(run_every=...)による定期的な再実行
実行順序のニュアンス:
- スクリプトは再実行のたびに上から下へ実行されます
- コールバックが最初:
on_change/on_clickハンドラーはメインのスクリプト本体の前に実行されます - フラグメントは通常、再実行を分離します:
@st.fragment内のウィジェット操作は通常、そのフラグメントのみを再実行します - キー付きフラグメントの再実行: ウィジェットのコールバックから
st.rerun("<key>")を呼び出すと、指定された@st.fragment(key=...)フラグメントのみが再実行されます - 制御フローの例外:
st.stop()、st.rerun()、st.switch_page()は実行を停止またはリダイレクトするために例外を発生させます
セッションの分離:
- 各ブラウザータブ = それぞれ独自の
SessionStateを持つ別個のAppSession - ページを更新すると新しいセッションが作成されます(TTL 内に再接続した場合を除く)
- セッション間で状態は共有されません(マルチユーザー状態には外部ストレージを使用してください)
再実行をまたいで永続化されるもの(セッション内):
st.session_stateの値- キャッシュされた関数の結果(
@st.cache_data、@st.cache_resource) - アップロードされたファイル
- フラグメントの登録
再実行のたびにリセットされるもの:
- スクリプト内のローカル変数
- ウィジェットの戻り値(
SessionStateから再読み取りされます) - 要素ツリー(ゼロから再構築され、その後差分が適用されます)
アーキテクチャのレイヤー
バックエンド(Python)
| コンポーネント | ファイル | 目的 |
|---|---|---|
| Runtime | lib/streamlit/runtime/runtime.py | アプリのライフサイクルとセッションを管理するシングルトン |
| AppSession | lib/streamlit/runtime/app_session.py | ブラウザータブごと: ScriptRunner + SessionState + ForwardMsgQueue |
| ScriptRunner | lib/streamlit/runtime/scriptrunner/script_runner.py | 別スレッドでユーザースクリプトを実行 |
| DeltaGenerator | lib/streamlit/delta_generator.py | mixin パターンを使用した API のエントリーポイント |
| SessionState | lib/streamlit/runtime/state/session_state.py | ウィジェットの値とユーザー変数 |
| Elements | lib/streamlit/elements/ | st.* コマンドのバックエンド実装 |
バックエンドの詳細: references/backend.md を参照してください
フロントエンド(TypeScript/React)
| コンポーネント | ファイル | 目的 |
|---|---|---|
| App | frontend/app/src/App.tsx | 中心となるオーケストレーター |
| AppRoot | frontend/lib/src/render-tree/AppRoot.ts | 4 つのコンテナーを持つイミュータブルな要素ツリー |
| ElementNodeRenderer | frontend/lib/src/components/core/Block/ElementNodeRenderer.tsx | プロトを React コンポーネントにマッピング |
| WidgetStateManager | frontend/lib/src/WidgetStateManager.ts | ウィジェットの状態、フォーム、クエリパラメーター |
| ConnectionManager | frontend/connection/src/ConnectionManager.ts | WebSocket のステートマシン |
フロントエンドの詳細: references/frontend.md を参照してください
通信(Protobuf)
| Proto | 目的 |
|---|---|
ForwardMsg.proto | サーバーからクライアントへ: デルタ、セッションイベント、ナビゲーション |
BackMsg.proto | クライアントからサーバーへ: ウィジェット状態を伴う再実行リクエスト |
Element.proto | oneof type ユニオン内の約 50 以上の要素タイプ |
WidgetStates.proto | ウィジェットの値: trigger_value、string_value、bool_value など |
場所: proto/streamlit/proto/
プロトコルの詳細: references/communication.md を参照してください
必須コンセプト (クイックマップ)
- レイアウトシステム: 要素の幅/高さパラメータ、flexbox コンテナ、レスポンシブサイジング。
- スクリプト再実行モデル: ウィジェット操作 ->
BackMsg(ClientState) -> バックエンドがSessionStateを更新 -> スクリプト再実行 ->ForwardMsgデルタ。- 詳細:
references/communication.md#widget-interaction-to-script-rerun
- 詳細:
- デルタパスシステム: 要素はデルタパス (例えば
[0, 2, 3]) でアドレス指定され、効率的なツリー更新をサポートします。- 詳細:
references/communication.md#delta-ui-changes
- 詳細:
active_script_hashのセマンティクス:ForwardMsg.metadata.active_script_hashは、マルチページおよびフラグメントの再実行にわたるノードの所有権をスコープします。- 詳細:
references/communication.md#forwardmsg-metadata-active_script_hash
- 詳細:
- 要素ツリー構造: フロントエンドの
AppRootはmain、sidebar、event、bottomコンテナをBlockNode/ElementNodeで維持します。- 詳細:
references/frontend.md#element-tree-frontendlibsrcrender-tree
- 詳細:
- 要素アイデンティティのセマンティクス: デルタパスはノードがどこに存在するかを決定し、要素 ID は再マウント後にステートフルな要素が以前の状態に再接続できるかどうかを決定します。
- 詳細:
references/element-identity.md
- 詳細:
- フラグメント (
@st.fragment): フラグメントの操作は通常、フラグメントスコープの再実行をトリガーし、影響を受ける領域のみを更新します。ウィジェットコールバックは、フラグメントが@st.fragment(key=...)で宣言されている場合、st.rerun("<key>")で名前付きフラグメントをターゲットにすることもできます。
要素アイデンティティ
- デルタパスは、ノードがレンダーツリーのどこに配置されるかを制御します。
- 要素 IDは、再マウント後にステートフルな要素が以前の状態に再接続できるかどうかを制御します。
- ウィジェットは、ID を使用してフロントエンドの
WidgetStateManager状態、BackMsg.WidgetStates、バックエンドのSessionState、コールバック、およびst.session_stateを接続します。 - 一部の非ウィジェットも、フロントエンドのみの再構築 (例えばチャートビュー状態やメディア自動再生ガード) に ID を使用します。
- デルタパスの変更は要素を再マウントする可能性がありますが、安定した
element.idにより、React は同じレンダリング済み親リストの下に残っているリーフを保持できます。
詳細: references/element-identity.md
主要な実装パターン
- バックエンド mixin コンポジション:
DeltaGeneratorは mixin を介してst.*API を構成します。- 詳細:
references/backend.md#deltagenerator-libstreamlitdelta_generatorpy
- 詳細:
- フロントエンドビジターパターン: レンダーツリーの更新/陳腐化クリーンアップはビジターを使用します。
- 詳細:
references/frontend.md#visitor-pattern
- 詳細:
- メッセージ重複排除:
ForwardMsg.hash+ref_hashとフロントエンドのForwardMsgCacheにより帯域幅を削減します。- 詳細:
references/communication.md#message-caching
- 詳細:
クイックリファレンス: 機能の追加
- Proto 定義:
proto/streamlit/proto/<Element>.proto - Element.proto に登録:
oneof typeに追加 - バックエンド mixin:
lib/streamlit/elements/<element>.py - フロントエンドコンポーネント:
frontend/lib/src/components/elements/<Element>/またはfrontend/lib/src/components/widgets/<Element>/(要素かウィジェットかに応じて) - ElementNodeRenderer に登録: switch 文にケースを追加
- Proto をコンパイル:
make protobuf
詳細な実装ガイドについては wiki/new-feature-guide.md を参照してください。
このドキュメントのメンテナンス
ここに記載されているコンセプト (Runtime、AppSession、DeltaGenerator、要素ツリー、通信プロトコル、要素アイデンティティなど) のいずれかに影響する変更を行う場合は、このスキルのファイル (SKILL.md、references/backend.md、references/frontend.md、references/communication.md、references/element-identity.md) の関連セクションを更新して、正確さを保ってください。