W poprzedniej części trochę poszaleliśmy z opcjami w npm install. Teraz skoncentrujmy się nad tym jak to można jeszcze bardziej zoptymalizować. Dla przypomnienia, chcemy zoptymalizować wykonywanie npm install na build server, lub w miejscach gdzie często to wykonujemy dla określonego projektu. Część 1 skończyła się na zapytaniu:

npm install --no-optional --skip-installed --cache "D:\npm_cache" --cache-min 999999

Jeżeli posiadamy na serwerze dobry, szybki dysk twardy to, za pomocą małego tricku jesteśmy wstanie przyspieszyć nasz czas wykonania do kilku sekund (zależy od dysku).

W tym celu wykorzystamy trick pakowania i rozpakowywania – najlepiej bez kompresji, to ma być zabójczo szybkie a nie powolne.

Mianowicie kod nasz powinien odpowiadać następującemu scenariuszowi:

  1. Rozpakuj archiwum (jeżeli istnieje) do katalogu node_modules
  2. Wykonaj czyszczenie (o tym zaraz)
  3. Zainstaluj paczki zgodnie z częścią 1
  4. Zapakuj node_modules i podmień lub stwórz plik z (1)

Koniec. Coś takiego jak będzie działało nam --skip-installed, spowoduje widoczną poprawę prędkości instalowania paczek na dyskach SSD, na szybkich dyskach SSD to po prostu będzie miodzio.

Teraz, wspomniałem tutaj o czyszczeniu (krok 2). Warto zaznaczyć, że mając coś zipowane, może się okazać że posiadamy tam tego więcej niż aktualnie projekt potrzebuje (package.json). Dlatego też warto wywalić z node_modules wszystkie te paczki, które nie są zdefiniowane w package.json. Można to wykonać za pomocą komendy prune – wykanie jej jest banalnie proste :)

npm prune

Teraz, jeżeli to wszystko połączymy to jesteśmy wstanie stworzyć plik BAT, który to za nas wszystko wykona i poda jeszcze czas wykonania. Poniżej przykładowy skrypt do wykorzystania na przykład w TeamCity.

@echo off

set cache=%1
set cache7="%cache%\tc_cache.7z"

set STARTTIME=%TIME%

:: temporary system path at cmd startup to include 7zip
set PATH=%PATH%;"%CD%\.tools"
rem set PATH=%PATH%;"C:\Program Files\7-zip\"

:: unpack zip cache
echo extracting 7z node_modules cache
call 7za x %cache7% -aos >nul: 2>nul

:: remove packages if we have some that has changed (we have them in node_modules but not in package.jspn)
echo pruning node_modules
call npm prune

echo installing node_modules no-optional;skip-installed;cache
call npm install --no-optional --skip-installed --cache "%cache%" --cache-min 9999999

:: if there was an npm install error, propage it
if %errorlevel% neq 0 exit /b %errorlevel%

:: zip node_modules for cache purpose
echo creating 7z node_modules cache for next time
call 7za a -t7z -mx0 -mmt %cache7% node_modules >nul 2>nul

echo cleaning artifacts (_nul file for whatever ^>nul is creating it)
del _nul 2>nul

set ENDTIME=%TIME%

echo done %STARTTIME% - %ENDTIME%

W kolejnej części zobaczymy czy da się coś zrobić z tym dyskiem, by jednak to nie od niego zależało jak szybko to się będzie wykonywało :)

4 KOMENTARZE

  1. W moim projekcie jest 2MB źródeł (c#,js,scss, grafika) a po skonfigurowaniu gulpa do konwersji scss do css npm naściągał 30MB plików, 8170 plików i 2003 folderów. Do tego musiałem się nagimnastykować, żeby pasował node-sass (kombinacje install/uninstall, rebuild), bo nie chcałem z githubu ściągać binarki (licho wie jak z wirusami).

    Pliki nie mogą być współdzielone, wszystko musi lecieć do node_modules. Zależności się powielają, w katalogach zalega mnóstwo plików (testy, źródła w C, js, yml). Spodziewałem się kilku plików a nie śmietnika.

    Bower też nie lepszy – w nuget zdarzają się świeższe pakiety niż w bower (choćby underscore). Do tego doliczmy bezsens (podobnie jak npm) ściągania wszystkich plików dla jednego rozwiązania zamiast (tak jak to zrobiono w nuget) js z ew. css.

    Sprawdziłem –no-optional i niestety to samo 40MB zajętego dysku/8177 plików, żeby być nowoczesnym i iść z duchem czasu (dla jednej funkcjonalności przy kompilowaniu!). Toż to 1/20 ilości plików w moim windows 10 :-D

    Nie pomyślałeś nad rozwiązaniem ramdysk? Ram jest tani, pamięć szybka, zaś dyski SSD nie lubią małych plików, mają słabą wydajność przy takich plikach (widać to w testach IO4KB).
    Spakowane archiwum node_modules na dany projekt można trzymać na ssd, zrobić z tego SHA1 i wynik zapisywać do repo. Przed buildem po SHA1 poszukać w magazynie (czy nawet redisie ;-) ) i rozpakować do ramu ew. cały zip trzymać w repo i rozpakowywać. Gdy zawartość node_modules sie nie zmienia, git nie robi kopii do nowych commitów tylko linkuje.

    Całość dla mnie ponurego obrazu dopełnia słaba dokumentacja modułów, porzucanie projektów (np. takana – fajnie się zapowiadała, po windowsem problem, od roku na githubie brak akcji)
    Moim zdaniem trzeba być ostrożnym z nodejs i npm.

    Microsoft idzie w tę głupią modę, w VS2015 w WebEssentials wyrzucono cześć funkcjonalności, sugerując wykorzystanie gulpa, tylko, że jego obsługa lekko kuleje (np. w źródle nie wskazuje błedów w pliku źródłowym).
    Moim zdaniem MS właśnie powinien włączyć stare WebEssentials do VS, kto to słyszał, żeby niezłe IDE także do JS domyślnie nie miało konwersji js/scss i innych operacji.

Comments are closed.