Skip to content

Technology Stack

Makoto Horikawa edited this page Jul 9, 2025 · 1 revision

💻 技術スタック

GitHub Power Scouterで使用している技術スタックの詳細解説です。初心者にも分かりやすく、なぜその技術を選択したのかも含めて説明します。

🏗️ アーキテクチャ概要

graph TB
    subgraph "Frontend Layer"
        A[React 19]
        B[TypeScript]
        C[CSS3 + Animations]
    end
    
    subgraph "Build Layer"
        D[Vite]
        E[ESLint]
        F[Prettier]
    end
    
    subgraph "Data Layer"
        G[GitHub REST API v3]
        H[Local Storage]
    end
    
    subgraph "Deployment Layer"
        I[Static Hosting]
        J[GitHub Pages]
        K[Cloudflare Pages]
    end
    
    A --> D
    B --> D
    C --> D
    D --> I
    I --> J
    I --> K
    A --> G
    A --> H
Loading

🎯 コア技術スタック

React 19 📘

なぜReactを選んだのか?

理由 詳細 メリット
コンポーネント指向 UIを再利用可能なコンポーネントに分割 保守性・可読性の向上
宣言的UI 状態に基づいてUIが自動更新 バグの少ないコード
豊富なエコシステム 多数のライブラリ・ツール 開発効率の向上
React 19の新機能 Server Components、新しいコンパイラ パフォーマンス向上

プロジェクトでの使用方法

// 関数コンポーネント + Hooks
import { useState, useEffect } from 'react';

const ScouterDisplay: React.FC<Props> = ({ username }) => {
  const [powerLevel, setPowerLevel] = useState(0);
  
  useEffect(() => {
    // 副作用の処理
    fetchUserData(username);
  }, [username]);
  
  return (
    <div className="scouter-display">
      {/* JSXでUIを記述 */}
    </div>
  );
};

React 19の特徴

mindmap
  root((React 19))
    新機能
      Server Components
      React Compiler
      Actions
      use Hook
    パフォーマンス
      自動最適化
      メモ化改善
      バンドルサイズ削減
    開発体験
      型安全性向上
      エラーメッセージ改善
      DevTools強化
Loading

TypeScript 5.8 📝

TypeScriptを選ぶ理由

機能 JavaScript TypeScript 影響
型安全性 ❌ 実行時エラー ✅ コンパイル時検出 バグ削減
IntelliSense ⚠️ 限定的 ✅ 完全サポート 開発効率
リファクタリング ⚠️ 危険 ✅ 安全 保守性
チーム開発 ⚠️ 属人化 ✅ ドキュメント化 品質向上

型定義の例

// GitHub API のレスポンス型
export interface GitHubUser {
  login: string;
  id: number;
  avatar_url: string;
  name: string | null;
  public_repos: number;
  followers: number;
  created_at: string;
}

// コンポーネントのProps型
interface UserInputProps {
  onScan: (username: string) => void;
  isScanning: boolean;
  hasDetailedData: boolean;
}

// 関数の型注釈
const calculatePowerLevel = (
  userData: GitHubUser,
  repoData: GitHubRepo[]
): PowerLevelResult => {
  // 型安全な実装
};

TypeScript設定

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  }
}

Vite 7.0 ⚡

Viteの革新性

comparison
    title Vite vs Traditional Bundlers
    section Build Speed
        Vite: 95
        Webpack: 60
        Parcel: 70
    section HMR Speed
        Vite: 98
        Webpack: 65
        Parcel: 75
    section Bundle Size
        Vite: 85
        Webpack: 90
        Parcel: 80
Loading

Viteの特徴

機能 説明 メリット
ES Modules ネイティブESMサポート 高速な開発サーバー
esbuild Go製の超高速トランスパイラ 10-100倍高速なビルド
Tree Shaking 未使用コードの自動削除 小さなバンドルサイズ
HMR 高速なホットリロード 快適な開発体験

Vite設定例

// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  base: './', // 静的ホスティング用
  build: {
    outDir: 'dist',
    sourcemap: false,
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'], // ベンダーチャンク分離
        },
      },
    },
  },
  server: {
    port: 5173,
    open: true, // 自動ブラウザ起動
  },
})

🎨 フロントエンド技術

CSS3 + Animations

なぜピュアCSSを選んだのか?

CSS-in-JS vs CSS CSS-in-JS Pure CSS 選択理由
バンドルサイズ 大きい 小さい ✅ パフォーマンス重視
実行時処理 あり なし ✅ ランタイム負荷なし
キャッシュ 困難 簡単 ✅ CDN活用可能
SSR対応 複雑 シンプル ✅ 静的サイト前提

アニメーション設計

/* 某世界的漫画風のグロー効果 */
.scouter-text {
  font-family: 'Orbitron', monospace;
  fill: #00ff00;
  filter: url(#glow);
  animation: pulse 2s ease-in-out infinite;
}

/* SVGフィルター定義 */
.glow-filter {
  filter: drop-shadow(0 0 10px #00ff00);
}

/* パワーレベルカウンターアニメーション */
@keyframes power-count {
  0% { transform: scale(1); }
  50% { transform: scale(1.1); filter: blur(0.5px); }
  100% { transform: scale(1); }
}

レスポンシブデザイン

/* Mobile First アプローチ */
.scouter-container {
  width: 100%;
  max-width: 500px;
}

/* タブレット */
@media (min-width: 768px) {
  .scouter-container {
    max-width: 600px;
  }
}

/* デスクトップ */
@media (min-width: 1024px) {
  .scouter-container {
    max-width: 800px;
  }
}

🔧 開発ツール

ESLint + Prettier

コード品質管理

flowchart LR
    A[Code Write] --> B[ESLint Check]
    B --> C{Errors?}
    C -->|Yes| D[Fix Errors]
    C -->|No| E[Prettier Format]
    E --> F[Git Commit]
    D --> B
Loading

ESLint設定

// eslint.config.js
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'

export default tseslint.config(
  { ignores: ['dist'] },
  {
    extends: [js.configs.recommended, ...tseslint.configs.recommended],
    files: ['**/*.{ts,tsx}'],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
    plugins: {
      'react-hooks': reactHooks,
      'react-refresh': reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      'react-refresh/only-export-components': [
        'warn',
        { allowConstantExport: true },
      ],
    },
  },
)

🌐 API・データ管理

GitHub REST API v3

API設計パターン

sequenceDiagram
    participant U as User
    participant C as Component
    participant A as API Service
    participant G as GitHub API

    U->>C: Enter Username
    C->>A: fetchUserData(username)
    A->>G: GET /users/{username}
    G-->>A: User Data
    A->>G: GET /users/{username}/repos
    G-->>A: Repository Data
    A->>G: GET /repos/{repo}/languages
    G-->>A: Language Stats
    A-->>C: Processed Data
    C-->>U: Display Results
Loading

API使用例

// GitHub API クライアント
class GitHubApiClient {
  private baseUrl = 'https://api.github.com';
  
  constructor(private token?: string) {}
  
  private getHeaders(): HeadersInit {
    return this.token 
      ? { 'Authorization': `token ${this.token}` }
      : {};
  }
  
  async getUser(username: string): Promise<GitHubUser> {
    const response = await fetch(
      `${this.baseUrl}/users/${username}`,
      { headers: this.getHeaders() }
    );
    
    if (!response.ok) {
      throw new Error(`User not found: ${username}`);
    }
    
    return response.json();
  }
  
  async getUserRepos(username: string): Promise<GitHubRepo[]> {
    const response = await fetch(
      `${this.baseUrl}/users/${username}/repos?per_page=100&sort=stars`,
      { headers: this.getHeaders() }
    );
    
    return response.json();
  }
}

Local Storage

データ永続化戦略

// Token管理
class TokenManager {
  private static readonly TOKEN_KEY = 'github_token';
  
  static saveToken(token: string): void {
    localStorage.setItem(this.TOKEN_KEY, token);
  }
  
  static getToken(): string | null {
    return localStorage.getItem(this.TOKEN_KEY);
  }
  
  static clearToken(): void {
    localStorage.removeItem(this.TOKEN_KEY);
  }
  
  static hasToken(): boolean {
    return this.getToken() !== null;
  }
}

🚀 デプロイメント技術

静的サイト生成

なぜ静的サイトなのか?

静的サイト SPA SSR/SSG 選択理由
コスト 無料〜安価 高い ✅ 予算効率
パフォーマンス 高速 中〜高速 ✅ CDN配信
セキュリティ 高い ✅ 攻撃面が少ない
運用コスト 低い 高い ✅ メンテナンス不要

ホスティングオプション

graph LR
    A[Built Assets] --> B{Hosting Choice}
    B --> C[GitHub Pages]
    B --> D[Cloudflare Pages]
    B --> E[Netlify]
    B --> F[Vercel]
    
    C --> G[github.io Domain]
    D --> H[Custom Domain + CDN]
    E --> I[Branch Deploys]
    F --> J[Serverless Functions]
Loading

📊 パフォーマンス最適化

バンドル分析

# バンドルサイズ分析
npm run build
npx vite-bundle-analyzer dist

最適化指標

メトリクス 目標値 現在値 状態
Initial Bundle < 500KB ~205KB
Vendor Chunk < 200KB ~12KB
First Paint < 1.5s ~0.8s
Interactive < 3s ~1.2s

パフォーマンス最適化技法

// 動的インポート(コード分割)
const ResumeModal = lazy(() => import('./ResumeModal'));

// メモ化
const MemoizedComponent = memo(({ data }) => {
  return <div>{data}</div>;
});

// useMemoとuseCallback
const ExpensiveComponent = ({ items }) => {
  const expensiveValue = useMemo(() => 
    items.reduce((sum, item) => sum + item.value, 0), 
    [items]
  );
  
  const handleClick = useCallback((id) => {
    // クリック処理
  }, []);
  
  return <div>{expensiveValue}</div>;
};

🔮 将来の技術選択

技術的負債の管理

quadrant-chart
    title Tech Debt vs Business Value
    x-axis Low Impact --> High Impact
    y-axis Low Effort --> High Effort
    
    React Upgrade: [0.8, 0.3]
    TypeScript 5.9: [0.6, 0.2]
    CSS Modules: [0.4, 0.7]
    Testing Setup: [0.9, 0.8]
Loading

技術ロードマップ

期間 技術 理由 優先度
短期 Jest + Testing Library テストカバレッジ向上
中期 Zustand 状態管理の改善
長期 React Server Components パフォーマンス向上

💡 学習リソース

各技術の学習パス

flowchart TD
    A[JavaScript基礎] --> B[TypeScript]
    B --> C[React基礎]
    C --> D[React Hooks]
    D --> E[Vite]
    E --> F[API連携]
    F --> G[デプロイ]
    
    B --> H[型設計]
    C --> I[コンポーネント設計]
    D --> J[パフォーマンス最適化]
Loading

推奨学習リソース

技術 リソース 難易度
React React公式ドキュメント 初級〜中級
TypeScript TypeScript Handbook 中級
Vite Vite公式ガイド 初級
CSS Animation MDN CSS Animations 中級

次のステップ: 基本文法ガイドで実装の詳細を学びましょう。

Clone this wiki locally