メインコンテンツまでスキップ

ビルド最適化

Elftia のメインバンドルは 1,812 KB から 759 KB(-58%)に最適化されています。このドキュメントでは、後退を防ぐための最適化戦略と標準を記録します。


バンドルサイズの制限

ハード制限(必ず遵守)

メトリクス制限現在確認方法
最大単一チャンク< 1 MB759 KBnpm run verify:build
メインバンドル(gzip 圧縮後)< 300 KB221 KBnpm run verify:build
Vite 警告00ビルド出力

推奨目標

メトリクス目標現在優先度
メインバンドル(非圧縮)< 500 KB759 KBP1
総バンドル< 3 MB6.24 MBP2
初回画面読み込み< 2s~2sP0

確認コマンド

# Quick verification (4 key metrics)
npm run verify:build

# Detailed analysis (chunk categorization stats)
npm run analyze:build

# Visual analysis (generate stats.html)
npm run build:renderer
# Open dist/stats.html

コード分割戦略

ルートレベルのコード分割(必須)

すべてのページコンポーネントは、遅延読み込みのために React.lazy を使用する必要があります。lazy/ は用途別に整理されたディレクトリです(pages.tsx / workspaces.tsx / inline.tsx / shell.tsx / skeletons.tsx / with-suspense.tsx / index.ts バレル)。新しいページを追加する場合は、lazy/pages.tsx を変更してください。

// packages/renderer/src/app/lazy/pages.tsx
export const LazySettingsPage = lazy(() => import('../Settings'));
export const SuspenseSettings = withSuspense(LazySettingsPage, PageSkeleton);

// packages/renderer/src/app/App.tsx — old import paths still valid (barrel re-export)
import { SuspenseSettings as Settings } from './components/lazy';
<Route path="/settings" element={<Settings />} />
// Don't do this: direct import of page components
import Settings from './components/Settings';
<Route path="/settings" element={<Settings />} />

大型コンポーネントの遅延読み込み(推奨)

単一コンポーネントが 100 KB を超える場合、または大規模なサードパーティライブラリに依存する場合は、遅延読み込みを使用します。

すでに遅延読み込みされているコンポーネント:

コンポーネントサイズ依存関係
MermaidDiagram451 KBmermaid
HtmlPreviewPanel198 KBiframe sandbox
CodeEditor34 KBCodeMirror
Shell / StandaloneShell9 KBxterm

判断基準:

条件遅延読み込みするか
コンポーネントバンドル > 100 KBはい
大規模なサードパーティライブラリに依存はい
初回画面に不要はい
使用頻度が低いはい
小さな共通コンポーネント(< 10 KB)いいえ
初回画面に必要なコアコンポーネントいいえ
頻繁に切り替えられる UI コンポーネントいいえ

Context の最適化

グローバルに必要でない Context はページレベルのコンポーネントへ移動します。

// Good: page-level Context
export function Settings() {
return (
<SettingsProvider>
<SettingsContent />
</SettingsProvider>
);
}

// Bad: load unnecessary Context globally
<GlobalContext>
<Routes />
</GlobalContext>
警告

Context を移動する前に依存関係を必ず分析し、ページをまたいだ状態共有が壊れないようにしてください。


ベンダーチャンク設定

現在の戦略では、更新頻度と使用頻度に基づいてグループ化しています。

// vite.config.js — manualChunks
{
'vendor-react': ['react', 'react-dom', 'react-router-dom'],
'vendor-ui': ['@radix-ui/react-context-menu', '@radix-ui/react-dialog', ...],
'vendor-icons': ['lucide-react'],
'vendor-utils': ['clsx', 'tailwind-merge', 'class-variance-authority', 'zustand'],
'vendor-markdown': ['react-markdown', 'remark-gfm', 'rehype-highlight'],
'vendor-codemirror': ['@codemirror/state', '@codemirror/view', ...],
'vendor-xterm': ['@xterm/xterm', '@xterm/addon-fit', '@xterm/addon-web-links'],
}

グループ化の原則

種類更新頻度キャッシュ優先度
コアフレームワーク最高React, React DOM
大規模なサードパーティライブラリCodeMirror, xterm
UI コンポーネントライブラリRadix UI, lucide
ユーティリティライブラリclsx, zustand

新しい依存関係の確認

新しいサードパーティ依存関係を追加する場合:

# 1. Check size
npm info <package> dist.unpackedSize

# 2. If > 100 KB, add to vendor chunks
# 3. If high update frequency, create separate vendor chunk
# 4. Verify tree shaking support
# 5. Run npm run analyze:build to check impact

Tree Shaking

正しいインポート方法

// Good: named imports (supports tree shaking)
import { Button, Input, Select } from '@/components/ui';
import { Home, Settings, User } from 'lucide-react';

// Good: Radix UI namespace imports (official recommendation)
import * as Dialog from '@radix-ui/react-dialog';

// Bad: import entire library
import * as UI from '@/components/ui';
import * as Icons from 'lucide-react';

未使用インポートの確認

npm run typecheck # TypeScript detects unused imports
npm run lint:eslint # ESLint warns about unused variables

Vite 本番ビルド設定

// vite.config.js — key configuration
build: {
minify: 'terser', // terser has better compression than esbuild
sourcemap: false, // disable sourcemap in production
chunkSizeWarningLimit: 500, // chunk size warning threshold (KB)
terserOptions: {
compress: {
drop_console: true, // remove console.log (keep warn/error)
drop_debugger: true, // remove debugger
},
},
}

よくある問題と解決策

メインバンドルが大きすぎる(> 500 KB)

調査手順:

  1. npm run build:renderer を実行し、dist/stats.html を開く
  2. メインバンドルの構成を確認し、最も大きなモジュールを見つける
  3. 大型コンポーネントに遅延読み込みが不足していないか確認する
  4. 不要なグローバルインポートがないか確認する

解決策:

  • 大型コンポーネントを遅延読み込みに変換する
  • 未使用インポートを削除する
  • ページコンポーネントをルートレベルの遅延読み込みに変換する

ベンダーチャンクが大きすぎる(> 500 KB)

解決策:

  • 大型ベンダーをより小さなチャンクに分割する
  • 更新頻度に基づいて再グループ化する
  • 重複する依存関係を確認する

総バンドルが大きすぎる(> 5 MB)

解決策:

  • チャートライブラリ(Mermaid、Cytoscape など)を遅延読み込みする
  • 使用頻度の低い機能や依存関係を削除する
  • より小さな代替ライブラリの使用を検討する

コード分割に失敗した

調査手順:

  1. lazy/ ディレクトリ内の関連する分割ファイルで遅延読み込み設定を確認する(ページレベルは lazy/pages.tsx、ワークスペース本体は lazy/workspaces.tsx、インラインチャットコンポーネントは lazy/inline.tsx
  2. 遅延読み込みされたコンポーネントが App.tsx で使用されているか確認する
  3. Vite 設定の manualChunks を確認する

コミット前チェックリスト

新しいページを追加する場合

  • ページコンポーネントを lazy/pages.tsx(または対応する分割ファイル)に追加した
  • withSuspense でラップし、fallback を指定した
  • App.tsx で遅延読み込み版を使用している
  • npm run build:renderer を実行して個別チャンクを確認した

大型コンポーネントを追加する場合

  • コンポーネントサイズ > 100 KB → 遅延読み込みを使用する
  • 大規模なサードパーティライブラリに依存 → 遅延読み込みを使用する
  • 適切なローディング状態を提供する

サードパーティ依存関係を追加する場合

  • 依存関係のサイズを確認する
  • 依存関係 > 100 KB → ベンダーチャンクに追加する
  • 更新頻度が高い → 個別のベンダーチャンクにする
  • Tree Shaking をサポート → 名前付きインポートを使用する
  • npm run analyze:build を実行して影響を確認する

継続的な最適化の提案

各リリース前

npm run verify:build
npm run build:renderer | grep -i "warning"
# If main bundle increased > 50 KB, investigate reason

毎月

npm run build:renderer
# Open dist/stats.html to check optimizable modules
npm outdated
npm update

四半期ごと

  • すべてのベンダーチャンク設定を見直す
  • 新しい最適化戦略を評価する
  • 使用頻度の低い機能を削除するかどうかを評価する
  • この標準ドキュメントを更新する

CI/CD 統合

CI にバンドルサイズチェックを追加することを推奨します。

- name: Build and verify
run: |
npm run build:renderer
npm run verify:build || echo "Warning: Bundle size check failed"

パフォーマンスメトリクスのベースライン

メトリクスベースライン目標監視
メインバンドル759 KB< 500 KBverify:build
初回画面読み込み~2s< 2sLighthouse
総バンドル6.24 MB< 3 MBanalyze:build
チャンク数76-analyze:build

参考リソース