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):
| Metryka | Przed | Po | Różnica |
|---|---|---|---|
Łączny rozmiar static/chunks | 9108 kB | 9052 kB | −56 kB |
| First Load JS shared by all | 104 kB | 104 kB | 0 |
/dashboard/activity-types | 462 kB | 449 kB | −13 kB |
/dashboard/activity-types/[activityTypeId] | 410 kB | 397 kB | −13 kB |
/dashboard/reservations-settings | 414 kB | 401 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