Usuń nieużywany kod.

Dzięki tym ćwiczeniom z programowania możesz zwiększyć wydajność poniższej aplikacji przez usunięcie nieużywanych i niepotrzebnych zależności.

Zrzut ekranu aplikacji

Zmierz odległość

Przed wprowadzeniem optymalizacji zawsze warto zacząć mierzyć skuteczność witryny.

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

Śmiało, kliknij swojego ulubionego kota. W tej aplikacji używana jest baza danych czasu rzeczywistego Firebase, dlatego wynik jest aktualizowany w czasie rzeczywistym i synchronizowany z każdą inną osobą korzystającą z aplikacji. 🐈

  1. Naciśnij „Control + Shift + J” (lub „Command + Option + J” na Macu), aby otworzyć Narzędzia deweloperskie.
  2. Kliknij kartę Sieć.
  3. Zaznacz pole wyboru Wyłącz pamięć podręczną.
  4. Załaduj ponownie aplikację.

Oryginalny rozmiar pakietu: 992 KB

Aby wczytać tę prostą aplikację, wysyłamy prawie 1 MB kodu JavaScript.

Zapoznaj się z ostrzeżeniami dotyczącymi projektów w Narzędziach deweloperskich.

  • Kliknij kartę Console (Konsola).
  • Sprawdź, czy w menu poziomów obok danych wejściowych Filter włączona jest funkcja Warnings.

Filtr ostrzeżeń

  • Przeanalizuj wyświetlone ostrzeżenie.

Ostrzeżenie dotyczące konsoli

Firebase, jedna z bibliotek używanych w tej aplikacji, jest dobrym samrytanem, ponieważ ostrzega programistów, aby nie importowali całego pakietu, a tylko używanych komponentów. Innymi słowy, istnieją nieużywane biblioteki, które można usunąć w tej aplikacji, aby przyspieszyć jej wczytywanie.

Zdarzają się również sytuacje, w których używana jest konkretna biblioteka, ale w których przypadku może być prostsza alternatywa. Kwestia usuwania niepotrzebnych bibliotek zostanie omówiona w dalszej części tego samouczka.

Analizuję pakiet

W aplikacji występują 2 główne zależności:

  • Firebase: platforma oferująca wiele przydatnych usług na potrzeby aplikacji internetowych na iOS i Androida oraz aplikacji internetowych. Tutaj Baza danych czasu rzeczywistego jest wykorzystywana do przechowywania i synchronizowania informacji o każdym kotku w czasie rzeczywistym.
  • Moment.js: biblioteka narzędziowa, która ułatwia obsługę dat w języku JavaScript. Data urodzenia każdego kotka jest przechowywana w bazie danych Firebase, a do obliczania jego wieku w tygodniach służy moment.

W jaki sposób tylko 2 zależności mogą zwiększyć rozmiar pakietu o prawie 1 MB? Jedną z powodów jest to, że każda zależność może z kolei mieć własne zależności, więc jeśli weźmie się pod uwagę każdą zależność „drzewa”, będzie o wiele więcej niż dwie. Gdy aplikacja zawiera wiele zależności, łatwo może szybko osiągnąć duże rozmiary.

Przeanalizuj usługę pakietów, aby lepiej zrozumieć, co się dzieje. Istnieje wiele różnych narzędzi społecznościowych, 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 konfiguracyjnym pakietu webpack. Zaimportuj go na początku webpack.config.js:

const path = require("path");

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

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

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

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

Analizator pakietów Webpack

Nie tak słodkie, jak oglądanie kocich kocich kotków, ale i tak niezwykle przydatne. Najechanie kursorem na dowolny pakiet powoduje wyświetlenie jego rozmiaru na 3 różne sposoby:

Rozmiar statystyk Rozmiar przed minifikacją lub kompresją.
Przeanalizowane rozmiary Rozmiar rzeczywistego pakietu w pakiecie po jego skompilowaniu. Wersja 4 pakietu internetowego (używanego w tej aplikacji) automatycznie minimalizuje skompilowane pliki, dlatego jest ona mniejsza niż rozmiar statystyk.
Rozmiar pliku gzip Rozmiar pakietu po skompresowaniu 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żą część pakietu.

Usuwanie nieużywanych pakietów

Wizualizacja pokazuje, że pakiet firebase składa się z dużej ilości więcej niż tylko bazy danych. Obejmuje dodatkowe pakiety, takie jak:

  • firestore
  • auth
  • storage
  • messaging
  • functions

Wszystkie te usługi świadczone przez Firebase są niesamowite (więcej informacji znajdziesz w dokumentacji), ale żadna z nich nie jest używana w aplikacji, więc nie ma powodu, by importować je wszystkie.

Cofnij zmiany w webpack.config.js, aby ponownie zobaczyć aplikację:

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

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

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

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

Teraz po ponownym załadowaniu aplikacji ostrzeżenie dotyczące Narzędzi deweloperskich nie będzie się wyświetlać. Otwarcie panelu Sieć w Narzędziach deweloperskich pokazuje też niewielkie zmniejszenie rozmiaru pakietu:

Zmniejszono rozmiar pakietu do 480 KB

Usunięto ponad połowę rozmiaru pakietu. Firebase oferuje wiele różnych usług i umożliwia deweloperom uwzględnianie tylko tych, które są rzeczywiście potrzebne. W tej aplikacji do przechowywania i synchronizowania wszystkich danych używano tylko firebase/database. Import danych firebase/app, który konfiguruje platformę interfejsu API dla każdej z różnych usług, jest zawsze wymagany.

Wiele innych popularnych bibliotek, np. lodash, pozwala też programistom na selektywne importowanie różnych części pakietów. Bez wykonywania wielu pracy zaktualizowanie importowanych bibliotek do aplikacji w taki sposób, aby zawierały tylko to, co jest używane, może znacznie poprawić wydajność.

Mimo że rozmiar pakietu został zmniejszony o nieco, jest jeszcze wiele do zrobienia. 😈

Usuwam niepotrzebne pakiety

W przeciwieństwie do Firebase importowanie części biblioteki moment nie jest tak proste, a może można ją całkowicie usunąć.

Urodziny każdego uroczego kotka są przechowywane w formacie Unix (w milisekundach) w bazie danych Firebase.

Data urodzenia zapisana w formacie Unix

Jest to sygnatura czasowa konkretnej daty i godziny wyrażona jako liczba milisekund, które upłynęły od godziny 00:00 czasu UTC 1 stycznia 1970 r. Jeśli aktualną datę i godzinę można obliczyć w tym samym formacie, prawdopodobnie da się utworzyć małą funkcję do określania wieku kotów w tygodniach.

Jak zawsze nie kopiuj i nie wklejaj treści w podany niżej sposób. Zacznij od usunięcia pola moment z importów w src/index.js.

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

Dostępny jest detektor zdarzeń Firebase, który obsługuje zmiany wartości w naszej bazie danych:

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

Powyżej dodaj małą funkcję, która oblicza liczbę tygodni od podanej 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 między bieżącą datą i godziną (new Date).getTime() a datą urodzenia (argument birthDate, już wyrażona w milisekundach) jest obliczana i dzielona przez liczbę milisekund w ciągu jednego tygodnia.

Wszystkie wystąpienia moment można też usunąć z detektora, 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>
    `})
});

Załaduj ponownie aplikację i jeszcze raz przyjrzyj się panelowi Network (Sieć).

Zmniejszono rozmiar pakietu do 225 KB

Rozmiar naszego pakietu został ponownie zmniejszony o ponad połowę.

Podsumowanie

Dzięki temu ćwiczeniu w programowaniu dowiesz się, jak analizować poszczególne pakiety i dlaczego może to pomóc w usuwaniu nieużywanych lub niepotrzebnych pakietów. Zanim zaczniesz optymalizować aplikację za pomocą tej metody, pamiętaj, że w przypadku większych aplikacji może to być znacznie bardziej skomplikowane.

Jeśli chodzi o usuwanie nieużywanych bibliotek, sprawdź, które części pakietu są używane, a które nie. W przypadku tajemniczego pakietu, który wygląda na to, że nigdzie nie jest używany, cofnij się i sprawdź, które zależności najwyższego poziomu mogą go potrzebować. Spróbuj je oddzielić.

Sytuacja jest nieco bardziej skomplikowana, jeśli chodzi o usuwanie niepotrzebnych bibliotek. Ważne jest, aby ściśle współpracować z zespołem, i sprawdzić, czy istnieje możliwość uproszczenia części kodu. Usunięcie języka moment w tej aplikacji może wydawać się właściwe za każdym razem, ale co, jeśli trzeba obsługiwać strefy czasowe i różne języki? A co, jeśli dochodzi do bardziej złożonych manipulacji datami? Manipulacja datami i godzinami oraz ich analizowanie może stać się bardzo trudne, a biblioteki takie jak moment i date-fns znacznie to upraszczają.

Wszystko się kompromisuje i trzeba ocenić, czy warto złożoność i wysiłek, aby wdrożyć niestandardowe rozwiązanie, zamiast polegać na bibliotece zewnętrznej.