Пошук уроків, статей та іншого контенту
Проаналізуєте склад і розмір бандлів за допомогою інструментів Next.js та знайдете важкі залежності.
Бандл — це набір JavaScript-файлів, які Next.js створює під час production-збірки. Для клієнтського коду він містить компоненти, бібліотеки та інші модулі, потрібні браузеру.
Великий бандл може:
збільшувати час завантаження сторінки;
сповільнювати виконання JavaScript у браузері;
погіршувати показники продуктивності;
передавати користувачу код, який фактично не використовується.
Аналіз бандла допомагає відповісти на запитання:
які залежності займають найбільше місця;
у які маршрути потрапляє певна бібліотека;
чи дублюються пакети;
чи потрапив серверний код у клієнтський бандл;
які модулі варто завантажувати відкладено.
Важливо аналізувати саме production-збірку. У режимі розробки структура та розмір файлів відрізняються від production.
Для Next.js з Webpack використовується пакет @next/bundle-analyzer.
Встановіть його як залежність для розробки:
npm install --save-dev @next/bundle-analyzerПакет додає до проєкту HTML-звіти з інтерактивними treemap-діаграмами. Розмір прямокутника на такій діаграмі відповідає розміру модуля або залежності в бандлі.
next.config.jsСтворіть або змініть файл next.config.js у корені проєкту:
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
};
module.exports = withBundleAnalyzer(nextConfig);Параметр enabled вмикає аналізатор лише тоді, коли змінна середовища ANALYZE має значення 'true'.
Це важливо: звичайна збірка не повинна щоразу створювати додаткові звіти.
На macOS і Linux можна запустити аналіз так:
ANALYZE=true npm run buildЩоб команда однаково працювала в macOS, Linux і Windows, встановіть cross-env:
npm install --save-dev cross-envДодайте окремий скрипт до package.json:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"analyze": "cross-env ANALYZE=true next build"
}
}Тепер запустіть:
npm run analyzeПісля завершення збірки аналізатор створить звіти в каталозі .next/analyze.
Зазвичай там можна знайти окремі звіти для:
клієнтського бандла;
Node.js-бандла;
Edge-бандла, якщо він використовується у проєкті.
Відкрийте HTML-файл клієнтського звіту у браузері. Саме цей бандл найчастіше має найбільший вплив на час завантаження сторінки.
У звіті кожен прямокутник відповідає модулю або групі модулів.
Під час аналізу звертайте увагу на:
Якщо значну частину бандла займає одна бібліотека, перевірте:
чи справді вона потрібна на клієнті;
чи використовується лише невелика частина її API;
чи можна завантажити її лише на певній сторінці;
чи існує легша альтернатива.
Наприклад, компонент вибору дат може використовувати велику бібліотеку, хоча на більшості сторінок цей компонент не потрібен.
Іноді різні пакети включають різні версії тієї самої залежності. Це може збільшити загальний розмір бандла.
Потрібно перевірити:
версії залежностей у package.json;
дерево залежностей за допомогою npm ls;
чи можна оновити пакети до сумісних версій.
Код, який використовується лише на сервері, не повинен потрапляти до клієнтського бандла.
Особливо уважно перевіряйте компоненти з директивою 'use client'. Усі імпорти з такого компонента можуть стати частиною клієнтського дерева залежностей.
Наприклад, якщо клієнтський компонент імпортує велику бібліотеку для обробки даних, ця бібліотека може бути завантажена браузером навіть тоді, коли вона потрібна лише для окремої дії.
Припустімо, у проєкті є компонент із бібліотекою для побудови графіків:
'use client';
import { Chart } from 'some-chart-library';
export default function SalesChart({ data }) {
return <Chart data={data} />;
}Після запуску аналізатора у звіті видно, що some-chart-library займає значну частину клієнтського бандла.
Спочатку варто перевірити, чи потрібен цей компонент на кожній сторінці. Якщо графік показується лише після відкриття окремої панелі, його можна завантажувати динамічно:
'use client';
import dynamic from 'next/dynamic';
const SalesChart = dynamic(() => import('./SalesChart'), {
ssr: false,
loading: () => <p>Завантаження графіка...</p>,
});
export default function Dashboard() {
return (
<main>
<h1>Панель керування</h1>
<SalesChart />
</main>
);
}Сам компонент графіка залишається в окремому чанку та не завантажується разом із початковим JavaScript-кодом сторінки.
Файл SalesChart.js може містити важку залежність:
'use client';
import { Chart } from 'some-chart-library';
export default function SalesChart({ data }) {
return <Chart data={data} />;
}Після зміни потрібно знову запустити:
npm run analyzeПорівняйте звіти до і після змін. Важливо перевіряти не лише загальний розмір усіх файлів, а й розмір початкового бандла конкретного маршруту.
Розмір серверного бандла та клієнтського бандла має різне значення.
Впливає на:
кількість даних, які завантажує браузер;
час виконання JavaScript;
інтерактивність сторінки.
Саме його зазвичай оптимізують у першу чергу.
Використовується під час виконання коду на сервері. Великий серверний бандл може впливати на:
час запуску функції;
розмір serverless-функції;
час холодного старту.
Бібліотека може бути великою на сервері, але не створювати проблеми для браузера. Тому не слід оцінювати всі звіти однаково.
Treemap показує склад бандла, але не завжди відображає точний обсяг даних, який користувач завантажує мережею.
Потрібно розрізняти:
розмір JavaScript до стиснення;
розмір після gzip або Brotli;
розмір початкового завантаження;
розмір чанків, які завантажуються пізніше.
Великий модуль не обов’язково є проблемою, якщо він:
завантажується лише на рідкісному маршруті;
не входить до початкового чанка;
добре стискається;
потрібен для важливої функціональності.
Тому після аналізу бандла перевіряйте результат у production-режимі та порівнюйте розмір початкового JavaScript-коду.
Запустіть npm run analyze.
Відкрийте звіт клієнтського бандла.
Знайдіть найбільші прямокутники.
Визначте, який маршрут або компонент імпортує відповідний модуль.
Перевірте, чи потрібна залежність у початковому бандлі.
Розгляньте динамічний імпорт або заміну бібліотеки.
Повторно запустіть аналіз.
Порівняйте результат із попередньою версією.
Не варто намагатися зменшити кожну залежність. Насамперед оптимізуйте модулі, які:
великі;
завантажуються на часто відвідуваних сторінках;
входять до початкового клієнтського бандла;
використовуються лише в окремих сценаріях.
Запуск аналізатора для next dev не дає коректної картини production-бандла.
Правильно аналізувати результат команди:
npm run analyzeде analyze виконує next build.
Не залишайте enabled: true без потреби. Це створює звіти під час кожної збірки та може ускладнювати робочий процес.
Краще вмикати аналізатор через змінну середовища:
enabled: process.env.ANALYZE === 'true'Кількість залежностей сама по собі не визначає розмір бандла. Важливі фактично імпортовані модулі та те, як Webpack об’єднує їх після tree shaking.
Порівнюйте саме розмір сформованих чанків.
Додавання dynamic() не гарантує автоматичного покращення початкового завантаження в кожному випадку. Після зміни потрібно повторно відкрити звіт і переконатися, що залежність справді перемістилася до окремого чанка.
Не робіть висновки тільки за серверним або тільки за клієнтським звітом. Визначте, де саме виникла проблема: у коді браузера чи на сервері.
Параметр ssr: false означає, що компонент не буде рендеритися на сервері. Це підходить для бібліотек, які потребують браузерних API, але не повинно використовуватися без причини.
Якщо компонент може коректно працювати під час серверного рендерингу, не вимикайте SSR лише заради розподілу бандла.
Для аналізу production-бандла Next.js можна використовувати @next/bundle-analyzer.
Аналізатор вмикають через змінну ANALYZE.
Treemap показує, які модулі займають найбільше місця.
Клієнтський бандл має найбільший вплив на завантаження сторінки.
Великі компоненти, потрібні лише в окремих сценаріях, можна завантажувати через dynamic().
Після кожної оптимізації потрібно повторно аналізувати бандл і порівнювати результати.
Розмір модуля у звіті не дорівнює точному розміру даних, переданих мережею: також мають значення стиснення та момент завантаження чанка.