awesome-everything EN
↑ Обратно к восхождению

Производительность

Code splitting: route-level, component-level, vendor splitting

Суть Code splitting — наиболее высокорычажная оптимизация bundle: каждый route качает только нужное, компоненты грузятся при триггере, vendor-чанки кешируются между деплоями.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 16 min

Dashboard-приложение шлёт 900 КБ JS на каждую страницу, потому что все routes делят один bundle. Homepage нуждается в React, chart-библиотеке, date picker и admin panel — хотя homepage никогда не показывает chart, не использует admin panel и не рендерит date picker. Три route стоимостей лишнего кода едут к юзеру при каждом визите на каждую страницу.

Route-level splitting

Самое ударное изменение. Каждый route — свой JavaScript chunk; навигация на /settings не скачивает bundle /editor. Каждый современный bundler поддерживает это из коробки.

  • Webpack — конфигурация splitChunks, или React Router 6 с lazy().
  • Vite — автоматический per-route splitting при использовании router-плагина.
  • Next.js — автоматические per-page chunks в Pages и App Router. Каждый файл в /pages или /(routes) — отдельный chunk автоматически.
  • Remix — route modules автоматически code-split; параллельная загрузка данных встроена.

Senior pattern: у каждого route — свой chunk. Если bundle analyzer показывает, что 40% homepage bundle — от /admin routes, route splitting не работает.

Component-level splitting

Компоненты не на critical path — модальники, сайдбары, drawers, admin tools, сложные charts — должны грузиться только когда нужны. Примитив — dynamic import().

// React
const DatePicker = React.lazy(() => import('./DatePicker'));
// Рендерить только внутри границы <Suspense>

// Vue
const DatePicker = defineAsyncComponent(() => import('./DatePicker.vue'));

Правило: любой компонент больше 30 КБ, не рендерящийся при первом paint, должен lazy-load. Типичные кандидаты: rich text editors, data visualisation библиотеки, map components, video players, admin panels.

Lazy-loaded компонент откладывает download до первого рендера. Когда юзер триггерит его (открывает modal, переходит на sub-route), chunk скачивается и парсится на месте. Чтобы избежать видимой задержки при первом взаимодействии, prefetch chunk на hover или когда триггер в зоне видимости:

<link rel="prefetch" href="/chunk-datepicker.js" />

Или используй React.lazy с import(/* webpackPrefetch: true */ './DatePicker').

Vendor splitting

Third-party библиотеки (React, React DOM, chart-библиотеки, utility-пакеты) меняются редко по сравнению с кодом самого приложения. Если они bundled с app-кодом, каждый новый деплой инвалидирует кешированную копию обоих у юзера — он перескачивает React, хотя React не изменился.

Vendor splitting помещает third-party библиотеки в отдельный chunk со своим content hash. Юзер кеширует vendor.abc123.js бессрочно. Деплой, изменяющий только app-код, инвалидирует app.def456.js, но vendor chunk остаётся в кеше. При повторных посещениях после деплоя скачивается только небольшой изменившийся chunk.

Как настроить: Webpack splitChunks.cacheGroups, Vite manualChunks, Next.js автоматический framework chunk (framework-*.js в _next/static/chunks/).

СтратегияМеханизмПодходит для
Route-levelКаждый route в своём chunk через bundler или routerSaaS с разными routes, мало общего кода
Component-leveldynamic import() + React.lazy / defineAsyncComponentМодальники, charts, редакторы не на critical path
Vendor splittingThird-party в отдельном content-hashed chunkЧастые деплои app; библиотеки меняются редко

Граница critical path

Не всё lazy loading бесплатно. Откладывая компонент, при первом открытии chunk скачивается и парсится в foreground. Это улучшает LCP (меньший initial bundle), но может ухудшить INP для конкретного взаимодействия.

Правило: держи на critical path всё, что юзер видит в первые 2-3 секунды загрузки страницы. Откладывай всё остальное. Если компонент ниже fold, за кликом или на route, который юзер посещает вторым — он в lazy chunk.

Почему это работает

Почему vendor splitting помогает, даже если vendor chunk большой? Cache headers. Статические ассеты отдаются с Cache-Control: public, max-age=31536000, immutable — имя файла включает content hash. После того как юзер скачал vendor.abc123.js, он больше никогда не скачивается, пока hash не изменится. Только твой app-код меняется при каждом деплое.

Расставь шаги по порядку

Расставь шаги приведения существующего bundle 1,2 МБ под бюджет 200 КБ per route:

  1. 1 Открыть bundle analyzer и отсортировать модули по размеру
  2. 2 Для каждого: не нужен ли он на critical path текущего route?
  3. 3 Настроить route-level splitting через framework router
  4. 4 Lazy-load большие компоненты не на critical first-paint path
  5. 5 Вынести third-party библиотеки в vendor chunk с content hash
  6. 6 Перезапустить bundle analyzer и проверить, что каждый route под бюджетом
  7. 7 Добавить CI size-limit gate для enforce бюджета на будущих PR
Викторина

После lazy-loading chart-компонента 100 КБ LCP улучшился, но юзер сообщает о заметной задержке при первом клике 'Open Chart'. Причина и fix?

Викторина

Next.js приложение с ежедневными деплоями имеет один большой bundle: React, app-код и библиотеки вместе. После vendor splitting юзеры сообщают: при повторном посещении после деплоя страница грузится быстрее. Почему?

Викторина

Product-инженер хочет добавить rich text editor (180 КБ) на homepage. Что рекомендует senior?

Вспомните перед уходом
  1. 01
    Объясни route-level, component-level и vendor splitting. Когда каждый — правильный выбор?
  2. 02
    Lazy-loaded компонент вызывает видимую задержку при первом взаимодействии. Что исправить?
Итог

Code splitting — наиболее ударная bundle-оптимизация: route-level гарантирует, что каждая страница платит только за свой код; component-level откладывает крупные некритичные компоненты; vendor splitting сохраняет кешированные library-чанки при частых деплоях. Примитив для последних двух — dynamic import(), который каждый современный bundler и фреймворк оборачивает в React.lazy, defineAsyncComponent или эквивалент. Все три стратегии суммируются. Следующий урок рассматривает tree shaking и compression — дополнительные техники уменьшения байтов внутри каждого chunk.

Связанные уроки
встречается в159
Продолжить восхождение ↑Tree shaking и compression: удаляем то, что не используем
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.