Usuń nieużywany kod.

W tym laboratorium programistycznym zwiększ wydajność tej aplikacji, usuwając nieużywane i niepotrzebne zależności.

Zrzut ekranu aplikacji

Zmierz odległość

Przed wprowadzeniem optymalizacji warto najpierw sprawdzić, jak działa witryna.

  • Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację. Następnie kliknij Pełny ekran pełny ekran.

Kliknij ulubionego kotka. W tej aplikacji jest używana Baza danych czasu rzeczywistego Firebase, dlatego wynik jest aktualizowany w czasie rzeczywistym i synchronizowany z każdym innym użytkownikiem aplikacji. 🐈

  1. Aby otworzyć Narzędzia dla programistów, naciśnij `Control+Shift+J` (lub `Command+Option+J` na Macu).
  2. Kliknij kartę Sieć.
  3. Zaznacz pole wyboru Disable cache (Wyłącz pamięć podręczną).
  4. Przeładuj aplikację.

Rozmiar oryginalnego pakietu to 992 KB

Ładowanie tej prostej aplikacji wymaga przesyłania prawie 1 MB kodu JavaScriptu.

Sprawdź ostrzeżenia dotyczące projektu w Narzędziach deweloperskich.

  • Kliknij kartę Konsola.
  • Upewnij się, że opcja Warnings jest włączona w menu poziomów obok wejścia Filter.

Filtr ostrzeżeń

  • Sprawdź wyświetlone ostrzeżenie.

Ostrzeżenie w konsoli

Firebase, która jest jedną z bibliotek używanych w tej aplikacji, zachowuje się jak Samarytanin, wyświetlając ostrzeżenie, aby poinformować deweloperów, że nie powinni importować całego pakietu, tylko używane komponenty. Innymi słowy, w tej aplikacji są nieużywane biblioteki, które można usunąć, aby przyspieszyć jej wczytywanie.

Są też przypadki, gdy używana jest dana biblioteka, ale może istnieć prostsza alternatywa. W dalszej części tego samouczka omawiamy usuwanie niepotrzebnych bibliotek.

Analizowanie pakietu

Aplikacja ma 2 główne zależności:

  • Firebase: platforma, która udostępnia wiele przydatnych usług dla aplikacji na iOS, Androida i internet. W tym przypadku Baza danych czasu rzeczywistego służy do przechowywania i synchronizowania informacji o każdym kocie w czasie rzeczywistym.
  • Moment.js: biblioteka narzędziowa ułatwiająca obsługę dat w JavaScript. Data urodzenia każdego kociaka jest przechowywana w bazie danych Firebase, a do obliczenia jego wieku w tygodniach służy parametr moment.

Jak to możliwe, że 2 zależności zajmują prawie 1 MB? Jednym z powodów jest to, że każda zależność może mieć swoje własne zależności, więc jeśli weźmiemy pod uwagę każdą głębokość/gałąź „drzewa” zależności, liczba zależności będzie znacznie większa niż 2. Aplikacja może stosunkowo szybko stać się duża, jeśli zawiera wiele zależności.

Przeanalizuj pakiet, aby lepiej zrozumieć, co się dzieje. Dostępnych jest wiele narzędzi stworzonych przez społeczność, które mogą Ci w tym pomóc, np. webpack-bundle-analyzer.

Pakiet tego narzędzia jest już zawarty w aplikacji jako devDependency.

"devDependencies": {
  //...
  "webpack-bundle-analyzer": "^2.13.1"
},

Oznacza to, że można go używać bezpośrednio w pliku konfiguracji webpacka. Zaimportuj go na samym początku webpack.config.js:

const path = require("path");

//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;

Teraz dodaj go jako wtyczkę na samym końcu pliku w tablicy plugins:

module.exports = {
  //...
  plugins: [
    //...
    new BundleAnalyzerPlugin()
  ]
};

Po ponownym załadowaniu aplikacji zamiast samej aplikacji powinna się wyświetlić wizualizacja całego pakietu.

Webpack Bundle Analyzer

Nie jest to tak urocze jak oglądanie kotków 🐱, ale i tak jest bardzo pomocne. Po najechaniu kursorem na dowolny pakiet możesz zobaczyć jego rozmiar w 3 sposoby:

Rozmiar statystyk Rozmiar przed zminimalizowaniem lub skompresowaniem.
Rozmiar po przeanalizowaniu Rozmiar rzeczywistego pakietu w pakiecie po jego skompilowaniu. Wersja 4 webpacka (która jest używana w tej aplikacji) automatycznie kompresuje skompilowane pliki, dlatego ich rozmiar jest mniejszy niż rozmiar statystyczny.
Rozmiar skompresowany Rozmiar pakietu po skompresowaniu go za pomocą kodowania gzip. Ten temat jest omówiony w osobnym przewodniku.

Narzędzie webpack-bundle-analyzer ułatwia identyfikowanie nieużywanych lub niepotrzebnych pakietów, które stanowią duży odsetek pakietu.

Usuwanie nieużywanych pakietów

Wizualizacja pokazuje, że pakiet firebase składa się z wiele więcej niż tylko z bazy danych. Obejmuje ona dodatkowe pakiety, takie jak:

  • firestore
  • auth
  • storage
  • messaging
  • functions

To świetne usługi oferowane przez Firebase (więcej informacji znajdziesz w dokumentacji), ale żadna z nich nie jest używana w aplikacji, więc nie ma powodu, aby importować je wszystkie.

Aby ponownie zobaczyć aplikację, cofnij zmiany w webpack.config.js:

  • Usuń BundleAnalyzerPlugin z listy wtyczek:
plugins: [
  //...
  new BundleAnalyzerPlugin()
];
  • Teraz usuń nieużywany import z góry pliku:
const path = require("path");

//...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

Aplikacja powinna się teraz wczytać normalnie. Zmień src/index.js, aby zaktualizować importy z Firebase.

import firebase from 'firebase';
import firebase from 'firebase/app';
import 'firebase/database';

Gdy aplikacja zostanie ponownie załadowana, ostrzeżenie w narzędziach deweloperskich nie będzie się już wyświetlać. W panelu Sieć w DevTools widać też znaczne zmniejszenie rozmiaru pakietu:

Rozmiar pakietu został zmniejszony do 480 KB.

Usunięto ponad połowę rozmiaru pakietu. Firebase udostępnia wiele różnych usług i daje deweloperom możliwość uwzględnienia tylko tych, których rzeczywiście potrzebują. W tej aplikacji do przechowywania i synchronizowania wszystkich danych używana była tylko usługa firebase/database. Import firebase/app, który konfiguruje interfejs API dla każdej z usług, jest zawsze wymagany.

Wiele innych popularnych bibliotek, np. lodash, pozwala deweloperom selektywnie importować różne części pakietów. Bez większego wysiłku możesz zaktualizować importowane w aplikacji biblioteki, aby zawierały tylko te, których używasz. Może to znacznie poprawić wydajność.

Chociaż rozmiar pakietu został znacznie zmniejszony, nadal jest jeszcze wiele do zrobienia. 😈

Usuwanie niepotrzebnych pakietów

W odróżnieniu od Firebase importowanie części biblioteki moment nie jest tak łatwe, ale może da się ją całkowicie usunąć?

Data urodzin każdego uroczego kociaka jest przechowywana w formie Unix (w milisekundach) w bazie danych Firebase.

daty urodzenia zapisane w formacie Unix;

To sygnatura czasowa określonej daty i godziny wyrażona jako liczba milisekund, które upłynęły od 1 stycznia 1970 r., godz. 00:00 czasu UTC. Jeśli bieżąca data i godzina mogą być obliczane w tym samym formacie, można stworzyć małą funkcję, która pozwoli znaleźć wiek każdego kociaka w tygodniach.

Jak zawsze, podczas wykonywania tych czynności nie kopiuj i wklej tekstu. Najpierw usuń moment z importowanych danych w src/index.js.

import firebase from 'firebase/app';
import 'firebase/database';
import * as moment from 'moment';

W naszej bazie danych jest odbiorca zdarzeń Firebase, który obsługuje zmiany wartości:

favoritesRef.on("value", (snapshot) => { ... })

Powyżej tego zdefiniuj małą funkcję, która oblicza liczbę tygodni od danej daty:

const ageInWeeks = birthDate => {
  const WEEK_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 7;
  const diff = Math.abs((new Date).getTime() - birthDate);
  return Math.floor(diff / WEEK_IN_MILLISECONDS);
}

W tej funkcji różnica w milisekundach między bieżącą datą i czasem (new Date).getTime() a datą urodzenia (argument birthDate, podany już w milisekundach) jest obliczana i dzielona przez liczbę milisekund w jednym tygodniu.

W reszcie wszystkie wystąpienia funkcji moment można usunąć w słuchaczu zdarzeń, korzystając z tej funkcji:

favoritesRef.on("value", (snapshot) => {
  const { kitties, favorites, names, birthDates } = snapshot.val();
  favoritesScores = favorites;

  kittiesList.innerHTML = kitties.map((kittiePic, index) => {
    const birthday = moment(birthDates[index]);

    return `
      <li>
        <img src=${kittiePic} onclick="favKittie(${index})">
        <div class="extra">
          <div class="details">
            <p class="name">${names[index]}</p>
            <p class="age">${moment().diff(birthday, 'weeks')} weeks old</p>
            <p class="age">${ageInWeeks(birthDates[index])} weeks old</p>
          </div>
          <p class="score">${favorites[index]} ❤</p>
        </div>
      </li>
    `})
});

Ponownie załaduj aplikację i jeszcze raz spójrz na panel Sieć.

Rozmiar pakietu został zmniejszony do 225 KB.

Rozmiar naszego pakietu zmniejszył się o ponad połowę.

Podsumowanie

Po wykonaniu tego ćwiczenia powinieneś/powinnaś już wiedzieć, jak analizować konkretne pakiety i dlaczego warto usuwać nieużywane lub niepotrzebne pakiety. Zanim zaczniesz optymalizować aplikację za pomocą tej metody, warto wiedzieć, że w przypadku większych aplikacji może to być znacznie bardziej skomplikowane.

Jeśli chodzi o usuwanie nieużywanych bibliotek, spróbuj się dowiedzieć, które części pakietu są używane, a które nie. Jeśli jakiś pakiet wygląda tajemniczo i wygląda na to, że nigdzie nie jest używany, cofnij się i sprawdź, których zależności najwyższego poziomu mogą go potrzebować. Spróbuj znaleźć sposób na ich rozdzielenie.

Jeśli chodzi o usuwanie zbędących bibliotek, sprawa może być nieco bardziej skomplikowana. Ważne jest, aby ściśle współpracować z zespołem i sprawdzać, czy można uprościć niektóre części kodu źródłowego. Usunięcie moment w tym założeniu może wydawać się właściwym rozwiązaniem, ale co, jeśli trzeba uwzględnić strefy czasowe i różne lokalizacje? A co, jeśli manipulacja datą jest bardziej skomplikowana? Podczas manipulowania i analizowania dat i godzin mogą pojawić się problemy, ale biblioteki takie jak momentdate-fns znacznie to upraszczają.

Wszystko ma swoje wady i zalety, dlatego warto ocenić, czy wdrożenie niestandardowego rozwiązania jest warte wysiłku i skomplikowania, zamiast polegania na bibliotece innej firmy.