Skip to content

perf(file-panel): add line-range API + virtualization + size guard for large files (#723)#724

Merged
Kewton merged 2 commits into
developfrom
feature/723-worktree
May 27, 2026
Merged

perf(file-panel): add line-range API + virtualization + size guard for large files (#723)#724
Kewton merged 2 commits into
developfrom
feature/723-worktree

Conversation

@Kewton
Copy link
Copy Markdown
Owner

@Kewton Kewton commented May 27, 2026

Summary

Issue #723 対応。PC版で数MB以上の大規模ファイルを開くとUIがハングする問題に対し、閲覧専用ファイル(行ベースAPI + 仮想スクロール)と編集系ファイル(GET事前2MBサイズ上限)のハイブリッド方式で根本対応する。

  • 閲覧専用ファイル: GET /api/worktrees/:id/files/:path?startLine=N&endLine=M で行範囲取得 + @tanstack/react-virtual で可視範囲のみマウント
  • 編集系ファイル(.md / .yaml / .yml 等): GET時にサイズ上限2MB事前ガード (FILE_TOO_LARGE / HTTP 413)
  • ポーリング: 大ファイル時自動無効化(POLLING_DISABLED_THRESHOLD_BYTES
  • 検索: debounce 300ms + 最小2文字

変更内容

新規ファイル

  • src/config/file-viewer-config.ts — チャンクサイズ・オーバースキャン・閾値定数
  • tests/unit/config/file-viewer-config.test.ts

既存ファイル変更

  • src/lib/file-operations.tsreadFileLineRange 追加(createReadStream + readline、メモリ O(チャンク))
  • src/app/api/worktrees/[id]/files/[...path]/route.ts — 行範囲分岐 + 編集系2MB事前ガード
  • src/components/worktree/FilePanelContent.tsxCodeViewer を仮想化対応に書き換え
  • src/hooks/useFileContentPolling.ts — 大ファイル時無効化条件追加
  • src/hooks/useFileContentSearch.ts — debounce + 最小2文字
  • src/config/editable-extensions.ts — 編集系拡張子サイズ上限定数
  • src/types/models.tsFileContenttotalLines / totalBytes メタ追加
  • package.json@tanstack/react-virtual 追加
  • CLAUDE.md — モジュールリファレンス更新
  • CHANGELOG.md — [Unreleased] 追記

破壊的変更

拡張子 旧挙動 新挙動
.md / .yaml / .yml 等 編集系 サイズ無制限読み込み GET 2MB上限(超過時 HTTP 413 FILE_TOO_LARGE
.html / .htm 既存5MB上限(Issue #490)維持 変更なし

詳細は CHANGELOG.md 参照。

品質チェック

項目 結果
npm run lint ✅ No ESLint warnings or errors
npx tsc --noEmit ✅ Pass
npm run test:unit ✅ 348 files / 6588 tests pass, 7 skipped
npm run build ✅ Build success
関連integration test ✅ Pass (api-file-operations / yaml-file-operations / security)

実行フロー

/orchestrate 723/pm-auto-issue2dev 723:

  1. ✅ Phase 1: Multi-stage Issue Review (Stage 1-4)
    • Must Fix 4+4 / Should Fix 6+6 / Nice to Have 3+3 → 全件Issue本文反映
  2. ⏭ Phase 2-3: 設計レビュー(メモリ指示によりスキップ)
  3. ✅ Phase 4: Work Plan(14タスク / 6フェーズ)
  4. ✅ Phase 5: TDD実装 + Acceptance Test + Refactoring + Docs
  5. ⏭ Phase 6: UAT スキップ(orchestrate --full 未指定)
  6. ✅ Phase 7: 進捗報告

関連

Test plan

  • 100MB級ログファイルを開いてUIブロックが発生しない(最初の数百行が1秒以内に表示)
  • スクロール時に追加チャンクが遅延ロードされ、スクロールバーが総行数ベースで正しく表示
  • 2MB超 .md ファイルを開くとエラー「ファイルが大きすぎます」が表示される (HTTP 413)
  • 既存の小さい .md / .yaml ファイルの編集・保存に影響なし
  • 大ファイル時の検索でブラウザがフリーズしない(debounce適用)
  • CI(lint/tsc/test/build)全パス

🤖 Generated with Claude Code

Kewton and others added 2 commits May 28, 2026 05:42
…r large files (#723)

Hybrid approach to fix UI hang when opening large files on PC:

Viewer-only (code/log files):
- Add line-range mode (`?startLine=N&endLine=M`) to GET /api/worktrees/:id/files/:path
- Server-side streaming via createReadStream + readline (memory O(chunk))
- New `readFileLineRange` helper in src/lib/file-operations.ts
- CodeViewer rewritten with @tanstack/react-virtual for visible-range + overscan
- Per-chunk hljs highlighting with Map cache
- Line-range mode skips If-Modified-Since and always returns 200
- Disable polling when content >= POLLING_DISABLED_THRESHOLD_BYTES (1MB)

Editable files (.md, .yaml, .yml):
- New 2MB GET pre-guard returning FILE_TOO_LARGE (HTTP 413)
- TEXT_MAX_SIZE_BYTES raised from 1MB to 2MB as single PUT/GET constant
- HTML (.html/.htm) excluded; existing 5MB guard (Issue #490) preserved
- New i18n keys: fileTooLarge.editableLimit / fileTooLarge.viewerLimit

Hooks / shared:
- useFileContentSearch: debounce 300ms + min 2 chars via SEARCH_DEBOUNCE_MS / SEARCH_MIN_QUERY_LENGTH (shared with useTerminalSearch)
- useFileContentPolling: large-file disable with POLLING_DISABLED_THRESHOLD_BYTES boundary (undefined keeps polling enabled)
- FileViewer inline search replaced by useFileContentSearch

Type / config:
- FileContent extended with optional totalLines / totalBytes / encoding / range (backward compatible)
- New src/config/file-viewer-config.ts (VIEWER_CHUNK_LINE_SIZE=500, VIEWER_OVERSCAN_LINES=100, POLLING_DISABLED_THRESHOLD_BYTES=1MB)

Breaking change:
- .md/.yaml/.yml > 2MB now return 413 on GET (previously opened but failed on PUT). HTML > 5MB behaviour unchanged.

Tests:
- 6588 unit / 76 issue-related integration tests pass
- New readFileLineRange suite with 100MB streaming RSS verification (<50MB increment)
- New line-range API + 2MB pre-guard integration suites

Docs:
- CHANGELOG.md [Unreleased] entries (Performance / Added / Changed / Breaking Changes)
- CLAUDE.md module reference updates (editable-extensions, file-viewer-config, file-operations, FilePanelContent, FileViewer, useFileContentPolling, useFileContentSearch)
- dev-reports/issue/723/ multi-stage Issue review (Stage 1-4), work plan, TDD/acceptance/refactor results

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Kewton Kewton merged commit e82be9f into develop May 27, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant