未分類
サービス高速立ち上げの技術選定ガイド
TL;DR(結論を先に)
| サービス特性 | 推奨スタック |
|---|---|
| AI/MLデモ、データ分析ダッシュボード | Streamlit |
| AI + カスタムUI、業務アプリ | FastAPI + htmx |
| コンテンツサイト、SEO重要、長期運用 | Nuxt |
| リアルタイム性、複雑なUI状態 | Nuxt or React |
3つのスタック概要
1. Streamlit
pip install streamlit
streamlit run app.py
特徴:
- Pythonだけで完結(HTML/CSS/JS不要)
- ウィジェット(スライダー、ボタン等)が組み込み
- 状態管理が自動(再実行ベース)
- Streamlit Cloud で無料デプロイ
コード例:
import streamlit as st
import pandas as pd
st.title("売上ダッシュボード")
uploaded = st.file_uploader("CSVをアップロード")
if uploaded:
df = pd.read_csv(uploaded)
st.line_chart(df["revenue"])
2. FastAPI + htmx
pip install fastapi uvicorn jinja2
特徴:
- Python統一だがHTML/CSSは書く
- htmxでJS不要の非同期通信
- API設計が残るので本番移行しやすい
- UIの自由度が高い
コード例:
@app.get("/search")
async def search(q: str):
results = await db.search(q)
return templates.TemplateResponse(
"partials/results.html",
{"results": results}
)
<input hx-get="/search" hx-target="#results"
hx-trigger="keyup changed delay:300ms">
<div id="results"></div>
3. Nuxt (Vue)
pnpm create nuxt-app
pnpm dev
特徴:
- フルスタックフレームワーク
- SSR/SSG対応でSEO強い
- Vue エコシステム(コンポーネント、状態管理)
- TypeScript完全サポート
比較表
| 観点 | Streamlit | FastAPI + htmx | Nuxt |
|---|---|---|---|
| 学習コスト | 最小(Pythonのみ) | 中(HTML/CSS必要) | 高(Vue/TS/SSR) |
| 立ち上げ速度 | 最速(数時間) | 速い(1-2日) | 普通(数日) |
| UIカスタマイズ | 限定的 | 自由 | 完全に自由 |
| 本番移行 | 難しい | しやすい | そのまま使える |
| SEO | × | △(SSR可能) | ◎ |
| リアルタイム更新 | △(再実行ベース) | ○(SSE/WebSocket) | ◎ |
| 複雑な状態管理 | △ | △ | ◎ |
| AI/ML連携 | ◎(Python直接) | ◎(Python直接) | △(API経由) |
サービス特性別の選定フローチャート
図を読み込み中...
ユースケース別の推奨
Streamlit が最適なケース
- AI/MLモデルのデモ
- 画像認識、テキスト生成のプロトタイプ
- モデルのパラメータ調整UI
- データ分析ダッシュボード
- CSVアップロード → 可視化
- 社内向けBIツール
- PoC(概念実証)
- 投資家向けデモ
- 1日で動くものを見せたい
向いていないケース:
- ユーザー認証が複雑
- 一般公開でSEOが必要
- 見た目の差別化が重要
FastAPI + htmx が最適なケース
- AI搭載の業務アプリ
- LLMチャットアプリ(カスタムUI)
- AIアシスタント付きの管理画面
- 社内ツール・管理画面
- CRUD操作メイン
- フォーム入力 → DB保存
- Streamlitからのステップアップ
- PoCが通って本番化したい
- UIをブランドに合わせたい
向いていないケース:
- SEOが最重要
- 複雑なクライアント状態(ドラッグ&ドロップ、リアルタイム協調編集)
- TypeScript必須の要件
Nuxt が最適なケース
- コンテンツサイト・ブログ
- SEO重要
- マークダウンベースのコンテンツ
- 長期運用するWebアプリ
- チーム開発
- 型安全性が重要
- 複雑なインタラクション
- リアルタイムチャート
- ドラッグ&ドロップUI
- 複数コンポーネント間の状態同期
- エコシステム活用
- 既存のVueコンポーネントを使いたい
- Chart.js, D3.js などの統合
向いていないケース:
- Pythonエンジニアしかいない
- 数時間で動くものが必要
- AI/MLと密結合
htmx vs Vue/Nuxt: 状態管理の観点から
htmxとVue/Nuxtは同じレイヤー(フロントエンド)の選択肢である。どちらを選ぶかは「状態をどこに持つか」で決まる。
思想の違い
| 観点 | htmx | Vue/Nuxt |
|---|---|---|
| 状態の置き場所 | サーバー | クライアント |
| 更新の仕組み | サーバーがHTML返却 | クライアントでリアクティブ更新 |
| 通信頻度 | 操作ごとにサーバー往復 | 必要時のみAPI呼び出し |
htmx を選ぶべきケース
- 表示がメインで操作が少ない
- ユーザープロフィール表示
- 履歴・ログ一覧
- 検索結果表示
- フォーム送信が中心
- お問い合わせフォーム
- 設定変更画面
- 管理画面のCRUD
- チームがPythonのみ
- フロントエンド専門家がいない
- Vue/React の学習コストを避けたい
- SEOが不要な社内ツール
- 管理画面
- 社内ダッシュボード
- バックオフィスツール
- シンプルさを優先
- ビルドプロセスなし
- node_modules 不要
- デバッグが直感的
htmx の具体例:
<!-- 検索: サーバーが結果HTMLを返す -->
<input hx-get="/search" hx-target="#results"
hx-trigger="keyup changed delay:300ms">
<!-- 削除: サーバーが空HTMLを返して消える -->
<button hx-delete="/items/123" hx-target="closest tr"
hx-swap="outerHTML">削除</button>
<!-- 無限スクロール -->
<div hx-get="/items?page=2" hx-trigger="revealed"
hx-swap="afterend">Loading...</div>
Vue/Nuxt を選ぶべきケース
- 複数コンポーネント間の状態共有
- ヘッダーのカート数 + 商品一覧 + サイドバー
- 一箇所の変更が複数箇所に反映
- 楽観的UI更新(Optimistic UI)
- ボタン押下で即座に見た目変更
- バックグラウンドでサーバー同期
- 失敗時にロールバック
- リアルタイム・高頻度更新
- 株価チャート
- チャットアプリ
- 通知バッジ
- 複雑なフォーム
- マルチステップウィザード
- 条件分岐するバリデーション
- 動的にフィールド追加/削除
- ドラッグ&ドロップ、アニメーション
- タスク並び替え
- ファイルアップロードUI
- スムーズなトランジション
- オフライン対応・PWA
- Service Worker連携
- ローカルキャッシュ
Vue/Nuxt の具体例:
<script setup>
const cart = useCart() // 複数コンポーネントで共有
const { addToCart, isAdding } = useAddToCart()
// 楽観的更新: 即座にUIに反映、後でサーバー同期
async function handleAdd(product) {
cart.items.push(product) // 即座に追加
try {
await addToCart(product.id)
} catch {
cart.items.pop() // 失敗したら戻す
}
}
</script>
<template>
<!-- ヘッダーのカート数も自動更新 -->
<Header :cart-count="cart.items.length" />
<button @click="handleAdd(product)" :disabled="isAdding">
カートに追加
</button>
</template>
機能別の判断表
| 機能 | htmx | Vue | Nuxt | 推奨 |
|---|---|---|---|---|
| 一覧表示 | ◎ | ◎ | ◎ | どれでもOK |
| 検索・フィルター(単純) | ◎ | ◎ | ◎ | どれでもOK |
| 検索・フィルター(複数条件組み合わせ) | △ | ◎ | ◎ | Vue/Nuxt |
| フォーム送信 | ◎ | ◎ | ◎ | どれでもOK |
| マルチステップフォーム | △ | ◎ | ◎ | Vue/Nuxt |
| ユーザー認証(基本) | ○ | ◎ | ◎ | Vue/Nuxt がやや楽 |
| カート・お気に入り(即時反映) | △ | ◎ | ◎ | Vue/Nuxt |
| リアルタイム通知 | △ | ◎ | ◎ | Vue/Nuxt |
| ドラッグ&ドロップ | × | ◎ | ◎ | Vue/Nuxt |
| オフライン対応 | × | ○ | ◎ | Nuxt(PWA対応) |
| 複雑なチャート連動 | △ | ◎ | ◎ | Vue/Nuxt |
| アニメーション | △ | ◎ | ◎ | Vue/Nuxt |
| SEO(検索エンジン対策) | △ | × | ◎ | Nuxt(SSR/SSG) |
| OGP・SNSシェア | △ | × | ◎ | Nuxt |
| 静的サイト生成 | × | × | ◎ | Nuxt |
| ルーティング自動生成 | × | × | ◎ | Nuxt |
Vue vs Nuxt の使い分け
| 観点 | Vue (SPA) | Nuxt |
|---|---|---|
| SEO | ×(クライアントレンダリング) | ◎(SSR/SSG) |
| 初期表示速度 | △(JS読み込み後に描画) | ◎(サーバーでHTML生成) |
| 構成の自由度 | ◎(自分で決める) | ○(規約あり) |
| セットアップ | 自分で構成 | 自動で揃う |
| 学習コスト | 中 | 高(Vue + Nuxt両方) |
判断:
- SEOが必要 → Nuxt 一択
- 社内ツール・管理画面(SEO不要) → Vue で十分
- ファイルベースルーティングが欲しい → Nuxt
- 既存APIに繋ぐだけのフロント → Vue で十分
Nuxt で得られるもの(SEO以外)
SEO以外にも Nuxt を選ぶメリットは多い。
1. 初期表示速度(Core Web Vitals)
| 指標 | Vue SPA | Nuxt SSR/SSG |
|---|---|---|
| FCP (First Contentful Paint) | 遅い(JS実行後) | 速い(HTML即表示) |
| LCP (Largest Contentful Paint) | 遅い | 速い |
| CLS (Cumulative Layout Shift) | 発生しやすい | 制御しやすい |
→ ユーザー体験とGoogle検索順位の両方に影響
2. ファイルベースルーティング
pages/
├── index.vue → /
├── about.vue → /about
├── blog/
│ ├── index.vue → /blog
│ └── [slug].vue → /blog/:slug
→ ルーター設定を書く必要なし、ディレクトリ構造がそのままURL
3. 自動インポート
<script setup>
// import { ref, computed } from 'vue' ← 不要
// import { useRoute } from 'vue-router' ← 不要
const count = ref(0)
const route = useRoute()
</script>
→ import文の管理が不要、コードがすっきり
4. サーバーAPI(Nitro)
server/
├── api/
│ └── users.ts → /api/users
→ 別途バックエンドを立てなくてもAPIが書ける(フルスタック)
5. ビルド時データフェッチ(SSG)
<script setup>
// ビルド時に実行、静的HTMLに埋め込み
const { data } = await useAsyncData('posts', () =>
queryContent('/blog').find()
)
</script>
→ CDNから静的配信、サーバー負荷ゼロ、爆速
6. エコシステム(Nuxt Modules)
| モジュール | 機能 |
|---|---|
| @nuxt/content | Markdown/MDXでコンテンツ管理 |
| @nuxt/image | 画像最適化、自動WebP変換 |
| @nuxtjs/i18n | 多言語対応 |
| @vueuse/nuxt | 便利なComposables集 |
→ nuxt.config.ts に1行追加で機能追加
SEO以外で Nuxt を選ぶ理由まとめ
| 理由 | 説明 |
|---|---|
| 表示速度重視 | SSR/SSGで初期表示が速い |
| 規約による生産性 | ルーティング・インポート自動化 |
| フルスタック | API + フロント + コンテンツを一箇所で |
| モジュールエコシステム | 機能追加が楽 |
| 長期運用 | 構成が標準化されチーム開発しやすい |
Vue SPA で十分なケース(条件をすべて満たす場合)
Vue SPA を選ぶには以下の条件をすべて満たす必要がある:
| 条件 | 説明 |
|---|---|
| SEOが不要 | 社内ツール、管理画面、ログイン後のみ使うアプリ |
| 初期表示速度が重要でない | 多少の待ち時間が許容される |
| Nuxtの便利機能が不要 | ファイルベースルーティング、自動インポートなど |
| 構成を自由に決めたい | Nuxtの規約に縛られたくない |
具体例:
┌─────────────────────────────────────────────────────┐
│ ケース: 社内管理画面(既存APIに接続) │
├─────────────────────────────────────────────────────┤
│ ・SEO不要(ログイン必須) ✓ │
│ ・初期表示速度は許容範囲 ✓ │
│ ・シンプルな構成で十分 ✓ │
│ → Vue SPA で十分 │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ ケース: 一般公開サービス(既存APIに接続) │
├─────────────────────────────────────────────────────┤
│ ・SEO必要(検索流入が欲しい) ✗ │
│ → バックエンドが別でも Nuxt を使うべき │
└─────────────────────────────────────────────────────┘
重要: 「バックエンドが別にある」だけでは Vue SPA で十分とは言えない
| バックエンドが別 + | 選択 |
|---|---|
| SEO不要 | Vue SPA で十分 |
| SEO必要 | Nuxt |
| 初期表示速度重視 | Nuxt |
| 長期運用・チーム開発 | Nuxt(規約で統一) |
判断フローチャート(状態管理観点)
Q: ユーザー操作後、即座にUIを更新したい?
├─ No(サーバー応答待ちでOK) → htmx で十分
└─ Yes → Q2へ
Q2: 複数の場所が同時に更新される?
├─ No(1箇所だけ更新) → htmx で十分
└─ Yes(ヘッダー + 本文 + サイドバーなど) → Vue/Nuxt
Q3: オフラインでも動作させたい?
├─ No → 上記の判断に従う
└─ Yes → Vue/Nuxt 一択
実際の判断例
例1: LLMを使ったテキスト要約サービス
要件:
- ユーザーがテキストを入力 → LLMで要約
- 社内利用から開始、将来は一般公開
判断:
- 初期: Streamlit で爆速PoC
- 本番化: FastAPI + htmx でカスタムUI
- 一般公開時: フロントを Nuxt に置き換え(APIはそのまま)
例2: 株価分析ダッシュボード
要件:
- 複数チャートの連動
- 指標の選択・軸の切り替え
- 一般公開でSEOも欲しい
判断:
- Nuxt 一択
- Chart.js/ECharts のVue連携が活きる
- SSRでSEO対応
例3: 画像認識AIのデモ
要件:
- 画像アップロード → 認識結果表示
- 投資家プレゼン用
判断:
- Streamlit 一択
st.file_uploader()+ モデル推論- 30分で動くものが作れる
移行パス
Streamlit → FastAPI + htmx → Nuxt (フロント) + FastAPI (API)
↓ ↓ ↓
数時間 1-2日 1週間〜
PoC MVP/社内利用 本番・一般公開
ポイント:
- FastAPI で作った API は Nuxt からも呼べる
- 段階的に移行できる設計にしておく
まとめ
| 状況 | 選択 |
|---|---|
| 「とにかく今日動くものを見せたい」 | Streamlit |
| 「Pythonで完結させたい + UIもこだわりたい」 | FastAPI + htmx |
| 「長期運用・SEO・複雑なUI」 | Nuxt |
| 「AI + 一般公開」 | FastAPI (API) + Nuxt (フロント) |
現プロジェクト(mdx-playground)の立ち位置:
- コンテンツサイト + 財務チャート → Nuxt は正解
- AI機能を追加する場合 → FastAPI を別途立てて API 連携が現実的