Lazy Loading маршрутов

Lazy Loading маршрутов — техника, при которой JavaScript-код страницы загружается только тогда, когда пользователь переходит на соответствующий маршрут, а не при начальной загрузке приложения.

Зачем нужно

SPA с десятками маршрутов может иметь bundle в несколько мегабайт, если весь код загружается сразу. Lazy Loading делит приложение на chunks: пользователь скачивает только код главной страницы, остальные загружаются по требованию. Это сокращает время первой загрузки и TTI (Time to Interactive), что критично для производительности.

Где используется

  • Все крупные React-приложения с react-router
  • Next.js App Router (автоматическое разделение по маршрутам)
  • Vue Router с defineAsyncComponent
  • Angular loadChildren в RouterModule

React.lazy + Suspense

import React, { Suspense, lazy } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

// Обычный статический импорт — попадает в основной bundle
import Home from './pages/Home';

// Lazy импорт — создаёт отдельный chunk
const About = lazy( => import('./pages/About'));
const Dashboard = lazy( => import('./pages/Dashboard'));
const UserProfile = lazy( => import('./pages/UserProfile'));

function App() {
  return (
    <BrowserRouter>
      {/* Suspense отображает fallback пока chunk загружается */}
      <Suspense fallback={<div>Загрузка...</div>}>
        <Routes>
          {/* Home — не lazy, критичный маршрут */}
          <Route path="/" element={<Home />} />

          {/* Эти маршруты загрузятся только при переходе */}
          <Route path="/about" element={<About />} />
          <Route path="/dashboard" element={<Dashboard />} />
          <Route path="/users/:id" element={<UserProfile />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}

Группировка в один chunk (magic comments)

// Webpack magic comment — объединяет несколько модулей в один chunk
const UserProfile = lazy(
   => import(/* webpackChunkName: "user-pages" */ './pages/UserProfile')
);
const UserSettings = lazy(
   => import(/* webpackChunkName: "user-pages" */ './pages/UserSettings')
);
// Оба попадут в chunk user-pages.js

Skeleton вместо спиннера

function PageSkeleton() {
  return (
    <div className="skeleton">
      <div className="skeleton__header" />
      <div className="skeleton__content" />
    </div>
  );
}

function App() {
  return (
    <Suspense fallback={<PageSkeleton />}>
      <Routes>...</Routes>
    </Suspense>
  );
}

Prefetch при наведении (prodвинутый паттерн)

// Загрузить chunk заранее при наведении на ссылку
function NavLink({ to, children }) {
  const handleMouseEnter = () => {
    // Браузер начнёт скачивать chunk до клика
    import(`./pages/${to}`);
  };

  return (
    <Link to={to} onMouseEnter={handleMouseEnter}>
      {children}
    </Link>
  );
}

Частые ошибки

  • Lazy Loading для маленьких компонентов — overhead на HTTP-запрос может превышать выигрыш от разделения; делайте lazy только крупные маршруты (> 20 KB).
  • Отсутствие Suspense-обёрткиReact.lazy без Suspense выбросит ошибку.
  • Нет Error Boundary вокруг Suspense — если chunk не загрузился (нет сети), нужно показать fallback с ошибкой.
  • Lazy Loading для критических маршрутов — главная страница должна загружаться без дополнительных запросов.

Связанные темы

Ресурсы