Перейти к основному содержимому

Оптимизация сборки

Основной bundle Elftia был оптимизирован с 1,812 KB до 759 KB (-58%). В этом документе зафиксированы стратегии и стандарты оптимизации, чтобы предотвратить регрессии.


Ограничения размера bundle

Жесткие ограничения (обязательны к соблюдению)

МетрикаОграничениеСейчасМетод проверки
Максимальный single chunk< 1 MB759 KBnpm run verify:build
Main bundle (gzipped)< 300 KB221 KBnpm run verify:build
Предупреждения Vite00Вывод сборки

Рекомендуемые цели

МетрикаЦельСейчасПриоритет
Main bundle (без сжатия)< 500 KB759 KBP1
Общий bundle< 3 MB6.24 MBP2
Загрузка первого экрана< 2s~2sP0

Команды проверки

# Быстрая проверка (4 ключевые метрики)
npm run verify:build

# Подробный анализ (статистика категоризации chunk)
npm run analyze:build

# Визуальный анализ (сгенерировать stats.html)
npm run build:renderer
# Open dist/stats.html

Стратегия code splitting

Code splitting на уровне маршрутов (обязательно)

Все page components должны использовать React.lazy для lazy loading. lazy/ — это каталог, организованный по назначению (pages.tsx / workspaces.tsx / inline.tsx / shell.tsx / skeletons.tsx / with-suspense.tsx / index.ts barrel); добавляйте новую страницу, изменяя 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 />} />

Lazy loading крупных компонентов (рекомендуется)

Используйте lazy loading, если один компонент > 100 KB или зависит от крупных сторонних библиотек.

Компоненты, уже загружаемые через lazy loading:

ComponentРазмерЗависимость
MermaidDiagram451 KBmermaid
HtmlPreviewPanel198 KBiframe sandbox
CodeEditor34 KBCodeMirror
Shell / StandaloneShell9 KBxterm

Критерии принятия решения:

УсловиеLazy Load?
Component bundle > 100 KBДа
Зависит от крупной сторонней библиотекиДа
Не нужен для первого экранаДа
Низкая частота использованияДа
Небольшой общий компонент (< 10 KB)Нет
Core component, нужный для первого экранаНет
Часто переключаемый UI componentНет

Оптимизация Context

Переносите Context, который не требуется глобально, в компоненты уровня страницы:

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

// Bad: load unnecessary Context globally
<GlobalContext>
<Routes />
</GlobalContext>
warning

Перед переносом Context обязательно проанализируйте зависимости, чтобы не нарушить совместное использование состояния между страницами.


Конфигурация vendor chunks

Текущая стратегия группирует по частоте обновлений и частоте использования:

// 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'],
}

Принципы группировки

ТипЧастота обновленийПриоритет cacheПримеры
Core frameworksНизкаяНаивысшийReact, React DOM
Крупные сторонние libsНизкаяВысокийCodeMirror, xterm
UI component libraryСредняяСреднийRadix UI, lucide
Utility librariesСредняяСредний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

Правильные способы import

// 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';

Проверка неиспользуемых imports

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

Конфигурация production-сборки 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
},
},
}

Распространенные проблемы и решения

Main bundle слишком большой (> 500 KB)

Шаги расследования:

  1. Выполните npm run build:renderer, откройте dist/stats.html
  2. Проверьте состав main bundle, найдите самые крупные modules
  3. Проверьте, не отсутствует ли lazy loading у крупных компонентов
  4. Проверьте наличие ненужных глобальных imports

Решения:

  • Переведите крупные компоненты на lazy loading
  • Удалите неиспользуемые imports
  • Переведите page components на lazy loading уровня маршрутов

Vendor chunks слишком большие (> 500 KB)

Решения:

  • Разделите крупные vendors на меньшие chunks
  • Перегруппируйте по частоте обновлений
  • Проверьте наличие дублирующихся зависимостей

Общий bundle слишком большой (> 5 MB)

Решения:

  • Загружайте библиотеки графиков через lazy loading (Mermaid, Cytoscape и т. д.)
  • Удалите редко используемые функции или зависимости
  • Рассмотрите использование более компактных альтернативных библиотек

Code splitting не сработал

Шаги расследования:

  1. Проверьте конфигурацию lazy loading для соответствующих split-файлов в каталоге lazy/ (уровень страниц в lazy/pages.tsx, тела workspace в lazy/workspaces.tsx, inline chat components в lazy/inline.tsx)
  2. Проверьте, используются ли lazy-loaded components в App.tsx
  3. Проверьте manualChunks в конфигурации Vite

Pre-Commit checklist

При добавлении новых страниц

  • Page component добавлен в lazy/pages.tsx (или соответствующий split-файл)
  • Обернут в withSuspense и имеет fallback
  • В App.tsx используется lazy-loaded версия
  • Выполнен npm run build:renderer для проверки отдельного chunk

При добавлении крупных компонентов

  • Размер компонента > 100 KB → используйте lazy loading
  • Зависит от крупной сторонней библиотеки → используйте lazy loading
  • Предоставлено подходящее состояние загрузки

При добавлении сторонних зависимостей

  • Проверьте размер зависимости
  • Зависимость > 100 KB → добавьте в vendor chunks
  • Высокая частота обновлений → отдельный vendor chunk
  • Поддерживает tree shaking → используйте named imports
  • Выполните npm run analyze:build, чтобы проверить влияние

Рекомендации по непрерывной оптимизации

Перед каждым release

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

Ежеквартально

  • Пересматривайте всю конфигурацию vendor chunks
  • Оценивайте новые стратегии оптимизации
  • Оценивайте, стоит ли удалить редко используемые функции
  • Обновляйте этот документ стандартов

Интеграция CI/CD

Рекомендуется добавить проверки размера bundle в CI:

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

Базовые метрики производительности

МетрикаБазовое значениеЦельМониторинг
Main bundle759 KB< 500 KBverify:build
Загрузка первого экрана~2s< 2sLighthouse
Общий bundle6.24 MB< 3 MBanalyze:build
Количество chunks76-analyze:build

Справочные ресурсы