Co zrobić, aby skrypt był pięć razy mniejszy i dużo trudniejszy do odczytania?

Manna5

Objaśnienie metod tzw. minifikacji kodu JavaScript.

***

Minifikacja JavaScriptu

JavaScript jest zdecydowanie dużym usprawnieniem w Internecie, zarówno po stronie klienta (możliwość uzyskania rezultatów niemożliwych w przypadku samego HTML i CSS), jak i po stronia serwera (Node.js, alternatywa dla PHP, ASP czy JSP). Są z nim jednak dwa problemy:

  • Nie można opublikować projektu zamkniętoźródłowego, gdyż zawsze jest wgląd do kodu (tylko gdy jest po stronie klienta)
  • Kod jest dużo większy od kodu dla procesorów fizycznych albo JVM

Oby dwa problemy wynikają z tego, że kod w JS do ostatniej chwili, czyli do wykonania jest w czystej formie źródłowej (w tej ostatniej chwili znajduje się w pamięci operacyjnej w formie AST). Gdyby chcieć wprowadzić modyfikacje rozwiązujące ten problem, trzeba by było pisać wszystkie przeglądarki (oraz runtime'y, jak Node, ale ich jest mniej, więc mniejszy problem) od nowa. Wymyślono więc inny sposób - minifikację kodu. Polega ona na przetłumaczeniu "normalnego" kodu na bardzo zagmatwany, i oczywiście łamiący wszystkie dobre praktyki i zasady formatowania kodu. Jedyną regułą jest to, że kod ma być jak najmniejszy.

Minifikacja automatyczna

Istnieje wiele internetowych minifikatorów, ale są one tak proste w obsłudze, że nie będę w tym momencie wiele o nich pisał. Zamiast tego zajmiemy się metodami minifikacji ręcznej, a do tematu minifikatorów będę sporadycznie wracał.

Minifikacja ręczna

Jako przykład, posłużę się następującą funkcją do wyliczania silni:

function factorial(number) {
    if (number < 2) {
        return 1;
    } else {
        return number * factorial(number-1);
    }
}

Pierwsze, co możemy zrobić, to oczywiście usunąć formatowanie. Teraz mamy:

function factorial(number){if(number<2){return 1;}else{return number*factorial(number-1);}}

Następnie, skróćmy nazwy identyfikatorów. Zamiast number wystarczy n. Przy założeniu, że to fragment biblioteki matematycznej, nazwy funkcji skrócić nie możemy ze względu na wygodę użytkownika biblioteki. Teraz kod jest jeszcze krótszy:

function factorial(n){if(n<2){return 1;}else{return n*factorial(n-1);}}

Względnie długie są także słowa kluczowe. Dużo lepiej użyć operatora trójargumentowego, i (jeśli jesteśmy pewni, że targetujemy tylko nowe przeglądarki) - funkcji strzałkowej:

factorial=n=>{return n<2?1:n*factorial(n-1);}

No i mamy 45 znaków zamiast 127, a pewnie dało by się to zrobić jeszcze lepiej. A nie lepiej użyć minifikatora? W tym przypadku javascript-minifier.com nie okazuje się lepszy (strata 7 znaków):

function factorial(a){return a<2?1:a*factorial(a-1)}

Przy dłuższych skryptach lepiej jednak mimo wszystko użyć jakiegoś minifikatora, zyskując w ten sposób na czasie.

Niekoniecznie zamknięty

Jeśli stosojemy w naszym otwartym projekcie minifikację w celach optymalizacyjnych, musimy pamiętać, aby udostępnić oryginalny kod, chociażby na GitHubie.

3 komentarzy

@Manna5 Mógłbyś go poprawić i napisać o tym jak minifikować JS.

Rzeczywiście bez sensu, ale nie widzę żadnego przycisku do usunięcia artykułu.

@Manna5 Jaki jest sens tego zabiegu?

Po pierwsze, zapis Base64 to nie jest żadne kodowanie, tylko inny zapis liczbowy. Równie dobrze mógłbyś użyć Base2, i wysłać kd 01010101010111010111011, ale to nie ma nic wspólnego z kodowaniem.

Po drugie, zapis base64 składa się tylko z 64 znaków, co znaczy że na jeden bajty (w których mogliśmy wsadzić 255 wartości, wsadzimy tylko 64), czyli tracimy 75% miejsca. Jeśli mamy kod JavaScript tylko mającym 1kB, to w Base64 zajmie on około 4kB.

Zwłaszcza że odczytanie tak "zakodowanego" skryptu jest banalnie proste. Jeśli faktycznie chcesz chronić swój kod, to lepiej go zminifikuj. Nie tylko zmniejsza to rozmiar, zamiast go zwiększać, to faktycznie odczytanie takiego kodu jest trudne. Nawet deminificatory nie potrafią tak dobrze prezentować kodu, by móc go odczytać od nowa.