Yuki Takei 6 месяцев назад
Родитель
Сommit
eb3fca5a04
1 измененных файлов с 159 добавлено и 0 удалено
  1. 159 0
      .serena/memories/apps-app-pagetree-performance-refactor-plan.md

+ 159 - 0
.serena/memories/apps-app-pagetree-performance-refactor-plan.md

@@ -0,0 +1,159 @@
+# PageTree パフォーマンス改善リファクタ計画
+
+## 🎯 目標
+現在のパフォーマンス問題を解決:
+- **問題**: 5000件の兄弟ページで初期レンダリングが重い
+- **目標**: 表示速度を10-20倍改善、UX維持
+
+## 🚀 実装戦略: 2本立て
+
+### 戦略1: レンダリング最適化(react-window + SpeedTree)
+
+#### 現状分析
+- **ファイル**: `src/client/components/TreeItem/TreeItemLayout.tsx`
+- **問題**: 階層すべてを一度にレンダリング(5000項目 × DOM要素)
+- **影響**: メモリ/CPU消費が深刻
+
+#### 実装計画 - 既存ファイル活用方式
+**新規ファイル乱造を避け、既存構造を最大限活用**
+
+##### 主要変更ファイル:
+
+1. **ItemsTree.tsx** - react-window統合
+   ```typescript
+   // Before: 再帰的レンダリング
+   const renderTreeItems = () => currentNodes.map(...);
+   
+   // After: react-window統合
+   import { FixedSizeList } from 'react-window';
+   import { flattenTree } from './utils/flatten-tree';
+   
+   const flattenedItems = useMemo(() => 
+     flattenTree(rootNodes, expandedStates), [rootNodes, expandedStates]
+   );
+   
+   return (
+     <FixedSizeList
+       itemCount={flattenedItems.length}
+       itemSize={40}
+       itemData={{ items: flattenedItems, ...otherProps }}
+     >
+       {renderTreeItem}
+     </FixedSizeList>
+   );
+   ```
+
+2. **TreeItemLayout.tsx** - 子要素レンダリング部分修正
+   ```typescript
+   // Before: 再帰的な子要素レンダリング
+   { isOpen && (
+     <div className="tree-item-layout-children">
+       { hasChildren() && currentChildren.map((node) => {
+         return <ItemClassFixed key={node.page._id} {...itemProps} />; // ← 削除
+       })}
+     </div>
+   )}
+   
+   // After: 子要素は上位で管理(react-windowが担当)
+   { isOpen && hasChildren() && (
+     <div className="tree-item-layout-children">
+       {children} {/* ← react-windowから渡される */}
+     </div>
+   )}
+   ```
+
+3. **utils/flatten-tree.ts** - 新規作成(唯一の新規ファイル)
+   ```typescript
+   export const flattenTree = (nodes: ItemNode[], expandedStates: Record<string, boolean>) => {
+     const result = [];
+     // SpeedTreeのロジック適用 (参考: https://codesandbox.io/p/sandbox/8psp0)
+     return result;
+   };
+   ```
+
+##### TreeItemRenderer実装
+**既存コンポーネントをそのまま活用**:
+```typescript
+// react-windowのitemRenderer
+const renderTreeItem = ({ index, style, data }) => {
+  const { items, ...props } = data;
+  const item = items[index];
+  
+  return (
+    <div style={style}>
+      <PageTreeItem  // ← 既存コンポーネントをそのまま使用
+        {...props}
+        itemNode={item.node}
+        itemLevel={item.level}
+      />
+    </div>
+  );
+};
+```
+
+##### 期待効果
+- **レンダリング項目**: 5000 → 表示される10-20項目のみ
+- **初期表示速度**: 10-20倍改善
+- **メモリ使用量**: 99%削減
+
+---
+
+### 戦略2: API軽量化
+
+#### 現状分析
+- **ファイル**: `src/server/service/page/index.ts:findChildrenByParentPathOrIdAndViewer`
+- **問題**: PageDocument全フィールドを返送(~500バイト/ページ)
+- **影響**: 5000ページ × 500バイト = 2.5MB転送
+
+#### 実装計画
+
+1. **必要最小限フィールドの特定**
+   ```typescript
+   // 現在: 全フィールド返送
+   // 変更後: ツリー表示に必要な最小限のみ
+   .select('_id path parent descendantCount grant isEmpty createdAt updatedAt')
+   ```
+
+2. **対象ファイル**
+   - `src/server/service/page/index.ts` - selectクエリ追加
+   - `src/interfaces/page-listing-results.ts` - 型定義更新
+
+#### 期待効果
+- **データサイズ**: 500バイト → 100バイト(5倍軽量化)
+- **ネットワーク転送**: 2.5MB → 500KB
+
+---
+
+## 📁 最終的なファイル変更まとめ
+
+| ファイル | 変更内容 | 理由 |
+|---------|---------|------|
+| **ItemsTree.tsx** | react-window統合 | ツリー全体の管理箇所 |
+| **TreeItemLayout.tsx** | 子要素レンダリング部分修正 | 既存ロジック活用 |
+| **utils/flatten-tree.ts** | 新規作成 | フラット化ロジック分離 |
+| **src/server/service/page/index.ts** | selectクエリ追加 | API軽量化 |
+| **src/interfaces/page-listing-results.ts** | 型定義更新 | API軽量化対応 |
+
+**新規ファイル**: 1個のみ(ユーティリティ関数)  
+**既存ファイル活用**: 最大限活用
+
+---
+
+## 🎯 実装優先順位
+
+**Phase 1**: API軽量化(低リスク・即効性)
+- **工数**: 1-2日
+- **リスク**: 低(表示に影響なし)
+
+**Phase 2**: react-window実装(高効果)  
+- **工数**: 3-5日
+- **リスク**: 中(UI構造の大幅変更)
+
+**合計効果**: 初期表示速度 50-100倍改善予想
+
+---
+
+## 技術的参考資料
+- **SpeedTree参考実装**: https://codesandbox.io/p/sandbox/8psp0
+- **react-window**: FixedSizeListを使用
+- **フラット化アプローチ**: 展開状態に応じて動的配列変換