Sytuacja kobiet w IT w 2024 roku
12.01.20212 min
Netanel Basal

Netanel BasalFrontend ArchitectDatorama

Eliminacja martwego kodu w Angularze

Dowiedz się, jak możesz wyeliminować martwy kod w Angularze, używając do tego Tersera.

Eliminacja martwego kodu w Angularze

Zdarzają się przypadki, kiedy chcemy uruchomić kod jedynie w trybie produkcyjnym, lub developerskim. Może chodzić o jakąś drobnostkę (np. logowanie danych na konsoli), ale możemy też chcieć ładować całą bibliotekę, a to już znacznie większa operacja. Pokażę Wam tutaj, jak sprawić, aby do końcowego pakietu nie trafił niepożądany kod. Zacznijmy od rozwiązania, które zna każdy:

import { environment } from './environments/environment';

if (environment.production) {
  console.log('PROD MODE');
} else {
  console.log('DEV MODE');
}


Możemy wykorzystać pliki środowiskowe - Angular CLI załaduje odpowiedni plik w zależności od konfiguracji. Usunie on też niechciany kod kiedy przenosimy projekt na produkcję. Więcej o tej funkcji możecie przeczytać tutaj

Rozwiązanie to będzie działało w większości przypadków, ale co z zewnętrznymi bibliotekami, które nie mogą korzystać ze zmiennej środowiskowej? Jak mogą pozbyć się kodu, którego należy używać jedynie w trybie developerskim?

Jeśli spojrzymy na kod źródłowy Angulara CLI, to zobaczymy, że używa on Terser, aby zmniejszyć nasz kod. Jedną z funkcji Terser jest conditional compilation API. Pozwala ona na stworzenie globalnej stałej, którą można konfigurować w czasie kompilacji. Na przykład: 

await minify(`if(DEBUG) { console.log('DEV') }`, {
  compress: {
    dead_code: true,
    global_defs: {
      DEBUG: false
    }
  }
}).code;

// returns: ''


W powyższym przykładzie Terser najpierw zastępuje każde wystąpienie zmiennej DEBUG wartością false. Następnie, ponieważ włączyliśmy opcję dead_code, Terser zdaje sobie sprawę, że linijka if (false) {…} jest bezużyteczna, więc ją usuwa:


Przykład


Jeśli teraz spojrzymy na kod źródłowy Angulara CLI, to zobaczymy, że zmienna ngDevMode jest teraz stałą globalną w Terser global_defs. Oznacza to, że możemy jej używać zarówno w naszej aplikacji, jak i w bibliotekach zewnętrznych:

declare const ngDevMode: boolean;

@Component({
  selector: 'lib-my-lib',
  template: ` <p>my-lib works!</p> `
})
export class MyLibComponent {
  ngOnInit() {
    if (ngDevMode) {
      console.log('DEV MODE');
    }
  }
}


Kiedy konsumujemy komponent w naszej aplikacji i przenosimy go na produkcję, to Terser usunie kod wewnątrz instrukcji if z naszego pakietu. Pamiętaj, że jeśli chcesz obsługiwać kompilację po stronie serwera, to musisz dodać jeszcze jeden check:

declare const ngDevMode: boolean;

@Component({
  selector: 'lib-my-lib',
  template: ` <p>my-lib works!</p> `
})
export class MyLibComponent {
  ngOnInit() {
    if (typeof ngDevMode === 'undefined' || ngDevMode) {
      console.log('DEV MODE');
    }
  }
}

Moje projekty

Oto kilka z moich projektów open source:

  • Akita:zarządzanie stanem przeznaczone dla aplikacji JS
  • Spectator: narzędzie do uproszczenia testów Angulara
  • Transcolo: biblioteka Angulara do internacjonalizacji 
  • Error-Tailor- do walki z błędami w apkach Angulara 
  • Forms Manager:fundament pod właściwe zarządzanie formami w Angularze
  • Cashew:elastyczna biblioteka, która wyłapuje żądania HTTP


I wiele więcej!


Oryginał tekstu w języku angielskim możesz przeczytać tutaj. 

<p>Loading...</p>