Как сократить время загрузки React приложения на 70%

1799
Журналы сборки
Журналы сборки

Шаги по уменьшению времени начальной загрузки приложения React с помощью разделения кода.

Мы создаем крупномасштабные приложения с помощью React. При создании таких приложений основной проблемой, с которой мы сталкиваемся, является производительность приложения. Когда приложение становится все больше и больше, производительность может ухудшиться. В частности, время начальной загрузки приложения будет ухудшаться. Начальная загрузка приложения должна быть быстрой, не показывая пользователю пустой экран в течение нескольких секунд. Поскольку загрузка занимает больше времени, это создает плохое впечатление у пользователя.

Основной причиной этой проблемы является добавление слишком большого количества компонентов в один пакетный файл, поэтому загрузка этого пакетного файла может занять больше времени. Чтобы избежать подобной проблемы, нам необходимо оптимизировать структуру наших компонентов. Для решения этой проблемы в react есть собственное решение — разделение кода и ленивая загрузка. Это позволяет разбивать файлы пакета на части меньшего размера.

Лучшее место для внедрения разделения кода — это маршруты. Разделение кода на основе маршрутов решает половину проблем. Но большинство приложений используют только 50% преимуществ разделения кода.
Правильно ли мы структурируем компоненты при использовании разделения кода? Мы можем увидеть, почему и как это исправить, используя некоторые примеры кода. Для этого мы будем использовать пример приложения React с некоторыми компонентами пользовательского интерфейса.

На скриншоте ниже мы видим компонент приборной панели, который имеет несколько вкладок. Каждая вкладка имеет несколько компонентов.

Компонент Dashboard использует разделение кода на основе маршрутов, как показано ниже.
Компонент Dashboard использует разделение кода на основе маршрутов, как показано ниже.
const Dashboard = lazy(() => import('components/Dashboard'));
const Settings = lazy(() => import('components/Settings'));
const Configurations = lazy(() => import('components/Configurations'));

function App() {
  return (
    <Router>
      <Layout>
        <SideBar/>
        <Layout>
          <AppHeader/>
          <Content style={{padding: '20px'}}>
            <Suspense fallback={<div>Loading...</div>}>
              <Switch>
                <Route path="/dashboard">
                  <Dashboard/>
                </Route>
                <Route path="/settings">
                  <Settings/>
                </Route>
                <Route path="/configuration">
                  <Configurations/>
                </Route>
              </Switch>
            </Suspense>
          </Content>
        </Layout>
      </Layout>
    </Router>
  );
}

Компонент Dashboard содержит несколько подкомпонентов, таких как Sales, Profit, Chart, Tiles и Trends, как показано ниже.

function Dashboard() {
    
  return (
    <Tabs defaultActiveKey="1">
      <TabPane tab="Sales" key="1">
        <Sales/>
      </TabPane>
      <TabPane tab="Profit" key="2">
        <Profit/>
      </TabPane>
      <TabPane tab="Chart" key="3">
        <Chart/>
      </TabPane>
      <TabPane tab="Tiles" key="4">
        <Tiles/>
      </TabPane>
      <TabPane tab="Trends" key="5">
        <Trends/>
      </TabPane>
    </Tabs>
  );
}

Мы разделили код на маршруты. Поэтому, когда приложение собирается, мы получаем отдельный файл сборки для каждого маршрута, как показано ниже.

Из приведенного выше изображения видно, что файл размером 405,1 KB — это компонент приборной панели, а остальные файлы предназначены для заголовка, боковой панели, других компонентов и CSS.

Я разместил приложение в Netlify для проверки производительности. Если мы протестируем приложение локально, мы не сможем найти разницу. Когда я тестировал размещенное приложение с помощью GTmetrix, загрузка экрана приборной панели заняла 2,9 секунды, посмотрите на картинку ниже для покадровой загрузки.

Компонент приборной панели является начальной страницей для этого приложения, поэтому, когда мы нажмем на URL App, файл размером 405.1KB будет загружен вместе с заголовком и боковой панелью.
Первоначально пользователь будет просматривать только вкладку «Продажи«, но наш компонент приборной панели имеет несколько вкладок. Браузер загружает код других вкладок тоже, поэтому он задерживает первую закраску для пользователя. Чтобы уменьшить время начальной загрузки, нам нужно внести некоторые изменения в компонент приборной панели, как показано ниже

const Sales = lazy(() => import('components/Sales'));
const Profit = lazy(() => import('components/Profit'));
const Chart = lazy(() => import('components/Chart'));
const Tiles = lazy(() => import('components/Tiles'));
const Trends = lazy(() => import('components/Trends'));

const { TabPane } = Tabs;

function Dashboard() {
  return (
    <Tabs defaultActiveKey="1">
      <TabPane tab="Sales" key="1">
        <Suspense fallback={<div>Loading...</div>}>
          <Sales/>
        </Suspense>
      </TabPane>
      <TabPane tab="Profit" key="2">
        <Suspense fallback={<div>Loading...</div>}>
          <Profit/>
        </Suspense>
      </TabPane>
      <TabPane tab="Chart" key="3">
        <Suspense fallback={<div>Loading...</div>}>
          <Chart/>
        </Suspense>
      </TabPane>
      <TabPane tab="Tiles" key="4">
        <Suspense fallback={<div>Loading...</div>}>
          <Tiles/>
        </Suspense>
      </TabPane>
      <TabPane tab="Trends" key="5">
        <Suspense fallback={<div>Loading...</div>}>
          <Trends/>
        </Suspense>
      </TabPane>
    </Tabs>
  );
}

Здесь я импортировал каждый компонент вкладки с ленивой загрузкой и обернул компонент суспензией. Здесь я добавил несколько suspense для лучшего понимания, но вы можете использовать один suspense для всех компонентов.
Я не делал никаких изменений в разделении кода на уровне маршрута. Когда мы собираем приложение, добавляются некоторые дополнительные файлы, поскольку мы лениво загрузили каждую вкладку в компоненте приборной панели. Разделение файлов сборки показано на рисунке ниже.

Журналы сборки
Журналы сборки

Теперь давайте снова протестируем приложение с помощью GTmetrix с вышеуказанными изменениями. Посмотрите производительность приложения на следующем изображении

Как вы можете видеть, теперь наш компонент приборной панели загружается за 1 секунду. Поскольку код вкладки Sales загружается только сейчас. Внеся некоторые изменения, мы сократили время загрузки почти на 2 секунды. Сравнение разделения кода на основе route-based и route, component-based, основанного на компоненте, показано на следующих изображениях.

Разделение кода на основе маршрута
Разделение кода на основе маршрута
Разделение кода на основе маршрутов и компонентов
Разделение кода на основе маршрутов и компонентов

Как видите, это значительное улучшение начальной загрузки приложения. Теперь мы сократили время начальной загрузки приложения React на 70% с помощью нескольких настроек, эффективно используя разделение кода в компоненте приборной панели.

Заключение
Оптимизированное структурирование компонентов и эффективное использование API React позволит повысить производительность больших приложений.