Przejdź do głównej zawartości

Optymalizacja bundla — importy pakietów

Dokument opisuje, jak ograniczamy rozmiar kodu JavaScript wysyłanego do przeglądarki przez kontrolę importów z bibliotek zewnętrznych. Powstał w ramach AP-787.

👤 Dla zespołu — co to zmienia w praktyce

  • Aplikacja pobiera mniej kodu przy pierwszym wejściu na stronę. Największa różnica jest widoczna na ekranach z wyborem koloru (typy zajęć, ustawienia rezerwacji) — o ok. 13 kB mniej na wejście.
  • Zachowanie ekranów się nie zmienia. Wyszukiwarki graczy i filtry płatności działają tak samo — nadal czekają ok. 300 ms po zakończeniu pisania, zanim wyślą zapytanie.
  • Zmiana jest wyłącznie techniczna, nie wymaga żadnych działań od użytkowników.

🛠️ Dokumentacja techniczna

experimental.optimizePackageImports

W next.config.mjs włączamy optymalizację importów dla pakietów z barrel entry point, które nie znajdują się na wbudowanej liście Next.js (ta obejmuje m.in. lucide-react, date-fns i recharts):

experimental: {
optimizePackageImports: [
'@radix-ui/react-icons',
'@tanstack/react-table',
'react-color'
];
}

Dodawaj do tej listy tylko pakiety, z których importujemy nazwane eksporty w czasie wykonania. Pakiety używane wyłącznie jako typy (np. react-big-calendar, z którego bierzemy View, ToolbarProps, EventProps) nie dają żadnego zysku — typy i tak znikają przy kompilacji.

debounce bez lodash

lodash został usunięty z zależności. Cztery komponenty importowały z niego wyłącznie debounce, zaciągając przy tym całą bibliotekę (lodash nie obsługuje tree-shakingu przy imporcie nazwanym i nie jest objęty optimizePackageImports).

Zamiast tego używamy lib/debounce.ts — implementacja obsługuje wywołanie z dowolnymi argumentami oraz metodę cancel() do czyszczenia w useEffect:

import { debounce } from '@/lib/debounce';

const debouncedSearch = useRef(
debounce(async (query: string) => {
/* ... */
}, 300)
).current;

useEffect(() => () => debouncedSearch.cancel(), [debouncedSearch]);

Implementacja celowo nie odwzorowuje pełnego API lodash.debounce (brak leading, trailing, maxWait, flush) — żadne z tych zachowań nie było w projekcie używane.

Poza debounce nie ma innych zależności produkcyjnych importowanych w całości z barrel entry pointu bez pokrycia w optimizePackageImports. W package.json pozostaje wpis resolutions dla lodash-es — to pin bezpieczeństwa dla zależności przechodnich, niezwiązany z kodem aplikacji.

Pomiar

Porównanie next build przed i po zmianie (yarn build, ten sam commit bazowy):

MetrykaPrzedPoRóżnica
Łączny rozmiar static/chunks9108 kB9052 kB−56 kB
First Load JS shared by all104 kB104 kB0
/dashboard/activity-types462 kB449 kB−13 kB
/dashboard/activity-types/[activityTypeId]410 kB397 kB−13 kB
/dashboard/reservations-settings414 kB401 kB−13 kB

Zysk −13 kB na trzech trasach pochodzi z optimizePackageImports dla react-color. Pozostałe trasy zyskują 1–3 kB dzięki usunięciu lodash.

Aby powtórzyć pomiar bez nadpisywania katalogu .next:

NEXT_DIST_DIR=.next-baseline yarn build
find .next-baseline/static/chunks -name "*.js" -exec du -ck {} + | tail -1