За замовчуванням збирач кладе весь код застосунку в один файл: користувач, що відкрив головну сторінку, завантажує й код адмінки, редактора, графіків. Розділення коду (code splitting) виносить частини в окремі файли, що завантажуються за потреби.
lazy - компонент, код якого завантажується при першому рендері:
import { lazy, Suspense } from 'react';
const MarkdownEditor = lazy(() => import('./MarkdownEditor'));
function PostForm() {
const [editing, setEditing] = useState(false);
return (
<>
<button onClick={() => setEditing(true)}>Редагувати</button>
{editing && (
<Suspense fallback={<p>Завантаження редактора...</p>}>
<MarkdownEditor />
</Suspense>
)}
</>
);
}
Збирач (Vite) бачить динамічний import() і виносить MarkdownEditor з усіма залежностями в окремий файл.
Suspense показує fallback, поки код завантажується. Одна межа Suspense може охоплювати кілька лінивих компонентів.
Правила:
lazy- на верхньому рівні модуля, не всередині компонента. Інакше на кожен рендер створюється новий компонент - стан губиться, і код завантажується знову;- модуль має експортувати компонент за замовчуванням (
export default). Для іменованого експорту - проміжний модуль чиimport('./x').then((m) => ({ default: m.Editor })); - помилка завантаження (мережа, файл зник після деплою) кидається як виняток - потрібна межа помилок (Error Boundary), щоб показати повідомлення й кнопку «Оновити».
Що варто виносити:
- сторінки й маршрути - найприродніша межа; маршрутизатори (React Router, TanStack Router) мають для цього вбудовану підтримку;
- важкі бібліотеки - редактори, графіки, карти, PDF;
- рідко потрібне - модальні вікна налаштувань, експорт.
Не варто дробити кожен компонент: багато дрібних файлів - багато запитів і затримки «водоспадом». Межі - за сценаріями використання.
Попереднє завантаження: щоб користувач не чекав після кліку, імпорт можна запустити заздалегідь - при наведенні на кнопку: onMouseEnter={() => import('./MarkdownEditor')}. Повторний import() використає вже завантажений модуль.
Inertia розділяє код за сторінками автоматично, якщо в resolve використовується import.meta.glob без eager: true.