Sprawna praca z Composerem w Drupal
Composer jest aktualnie jednym z najważniejszych narzędzi w świecie PHP. Pozwala na uporządkowanie obsługi zewnętrznych bibliotek, ułatwiając przy tym ich bieżącą aktualizację. Przy wielkiej ilości zadań Drupal developmentu, których na co dzień się podejmujemy, nie potrafimy sobie już wyobrazić pracy bez wykorzystania Composera. Zapraszam do przeczytania 10 poniższych porad, które pozwolą Ci lepiej zrozumieć moce drzemiące w popularnym managerze pakietów.
1. Aktualizuj poprzez Composer zarówno moduły, jak i core
Drupal współpracuje z Composerem na dość specyficznych warunkach. Wiele starszych projektów jest skonfigurowanych w taki sposób, aby pobierać za pomocą Composera jedynie moduły, skórki i zewnętrzne biblioteki. Sam core trzeba aktualizować ręcznie.
Manualna aktualizacja podważa sens używania managera pakietów, jest jednak na to prosty sposób. Wykorzystaj szablon https://github.com/drupal/recommended-project. Polecam ten sposób startowania projektów w Drupal, w Droptica używamy go przy większości realizacji. Pozwala on na przechowywanie w repozytorium jedynie własnego kodu, bez zewnętrznych zależności. Gdy pojawi się nowa wersja Drupala, wystarczy pobrać ją komendą:
composer update drupal/core --with-all-dependencies
2. Przyspiesz dzięki hirak/prestissimo
Composer nie słynie z szybkości działania ani z oszczędności zasobów. Jedną z przyczyn takiego stanu rzeczy jest sekwencyjny sposób działania komendy install. Kolejne biblioteki ściągane są jedna po drugiej i w przypadku wystąpienia jakiegokolwiek przestoju - czas instalacji pakietów wydłuża się w nieskończoność.
Aby pokonać to ograniczenie, włącz plugin Prestissimo (https://github.com/hirak/prestissimo). Wprowadza on do Composera element równoległości. Dzięki niemu skomplikowany projekt zainstaluje się nawet kilkanaście razy szybciej.
composer global require hirak/prestissimo
Jakie są potencjalne wady Prestissimo? Po pierwsze mogą wystąpić problemy z obsługą repozytoriów prywatnych (trzeba wówczas zdefiniować niezbędne tokeny i klucze w pliku auth.json), po drugie - od wersji 2.0 Composera plugin stanie się zbędny (zastąpi go obsługa curl-multi).
3. Zmniejsz apetyt na pamięć dzięki Drupal Optimizations
Wspomniałem w poprzednim punkcie o pamięciożerności Composera. W przypadku Drupala potęguje ją mnogość zewnętrznych zależności, zwłaszcza tych pochodzących od Symfony. Problem został zauważony przez społeczności Symfony i Drupala. Rozwiązanie w postaci pluginu do Composera przygotował polski developer, Jakub Piasecki.
Aby dodać Drupal Optimizations do projektu, wywołaj komendę:
composer require zaporylie/composer-drupal-optimizations:^1.1
Jak działa plugin? Zakłada on, że używamy wersji Drupal >= 8.5. Na tej podstawie unika sprawdzania starszych tagów w repozytoriach komponentów Symfony. Taki sposób optymalizacji według autora zmniejsza zużycie pamięci ponadtrzykrotnie. Dzięki temu komenda composer update wywołuje się znacznie szybciej.
4. Kontroluj limit dostępnej pamięci
Jeśli dwa powyższe pluginy nie wystarczają i wciąż masz problemy z przekraczaniem limitu pamięci - jedynym ratunkiem może okazać się jego powiększenie. Kilka sposobów przedstawia oficjalna dokumentacja. Composer przy każdym uruchomieniu podejmuje próbę zwiększenia limitu do 1,5GB, jednak taka wartość niejednokrotnie nie wystarcza.
Jeśli Composer nie reaguje na zmiany limitu - sprawdź, czy edytujesz właściwy plik z konfiguracją (zobacz przede wszystkim, czy znajduje się on na liście dostępnej po wywołaniu komendy php --ini). Upewnij się też, czy serwer, na ktorym wywołujesz Composera zezwala na tak duże zużycie pamięci. Gdy problem dotyczy komendy composer update - pamiętaj, że możesz uruchomić ją lokalnie z większym limitem i wygenerować plik composer.lock, a na podstawie tego pliku wywołać na serwerze komendę composer install, która wykorzystuje znacznie mniej zasobów.
5. Odkryj komendę outdated i przełącznik --dry-run
Większość użytkowników Composera używa głównie komend install i update. I nie ma w tym nic złego do momentu, gdy potrzebujemy większej kontroli nad aktualizacją. Jeśli zależy Ci na sprawdzeniu, co właściwie zamierza zrobić komenda composer update - wywołaj ją z przełącznikiem --dry-run. Jak sama nazwa wskazuje - zostanie wtedy uruchomiona "na sucho", bez żadnych zmian w kodzie.
Inną metodą na przejrzenie dostępnych aktualizacji jest komenda composer outdated. Przedstawia ona w czytelny sposób wszystkie pakiety, które muszą zostać uaktualnione (osobnym kolorem oznaczone są tu pakiety, których nowsze wersje są zablokowane poprzez ograniczenia nałożone w composer.json). To doskonała alternatywa dla modułu Update Manager.
6. Przekonwertuj swój projekt przez Composerize
Jeśli posiadasz już projekt w Drupal, który nie jest utrzymywany przy pomocy Composera - nic straconego! Dostępnych jest kilka narzędzi generujących plik composer.json na podstawie kodu znalezionego w danym projekcie. Najczęściej używany jest plugin grasmash/composerize-drupal. Jego instalacja odbywa się w następujący sposób:
composer global require grasmash/composerize-drupal
Po wywołaniu poniższych komend (przy założeniu, że [repo-root] to ścieżka do głównego katalogu projektu, a [drupal-root] to ścieżka do index.php), otrzymamy plik composer.json zawierający wszystkie moduły i skórki i profile występujące w projekcie, skonfigurowany do obsługi patchowania i ściągania pakietów z https://asset-packagist.org/.
cd path/to/drupal/project/repo
composer composerize-drupal --composer-root=[repo-root] --drupal-root=[drupal-root]
Wywołanie komendy composer install spowoduje zainstalowanie najnowszych wersji modułów w miejsce istniejących. Od tej chwili zewnętrzne zależności nie muszą być przechowywane w repozytorium projektu, wystarczy umieścić w nim pliki composer.json i composer.lock.
7. Zapoznaj się z Asset Packagist
Composer służy głównie do zarządzania pakietami PHP. Istnieje jednak możliwość połączenia go z repozytoriami NPM i Bower. Jest to przydatne w przypadku, gdy chcemy utrzymywać najnowsze wersje bibliotek frontendowych (jak np. Colorbox albo Slick). Połączenie takie zapewnia projekt Asset Packagist (https://asset-packagist.org/).
Aby korzystać z dodatkowych bibliotek, zdefiniuj nowe repozytorium w pliku composer.json:
"repositories": [
{
"type": "composer",
"url": "https://asset-packagist.org"
}
]
Pamiętaj też o zmianie lokalizacji bibliotek na kompatybilną z Drupalem. W tym celu upewnij się, że Twój projekt zawiera dodatek composer/installers:
composer require composer/installers
A następnie umieść odpowiednie zapisy w sekcji "extras" pliku composer.json:
"extra": {
"installer-types": ["bower-asset", "npm-asset"],
"installer-paths": {
"web/libraries/{$name}": ["type:bower-asset", "type:npm-asset"]
}
}
Załóżmy, że chcesz dodać do swojej strony bibliotekę Colorbox. Najpierw wyszukaj ją na stronie https://asset-packagist.org/, kliknij na jej tytuł i zaczekaj, aż Asset Packagist ściągnie informacje o Colorbox do swojego repozytorium (ten krok nie jest zawsze konieczny, może okazać się potrzebny w przypadku mało popularnych bibliotek).
Skopiuj pełną nazwę pakietu z przedrostkiem npm-asset/bower-asset i wywołaj komendę:
composer require npm-asset/jquery-colorbox
Jeśli wszystko pójdzie dobrze, colorbox znajdzie się w katalogu web/libraries Twojego projektu.
Mówiąc o Asset Packagist muszę zaznaczyć, że jego wykorzystanie ma sens wyłącznie w przypadku, gdy potrzebujemy ściągnąć do projektu pojedynczą bibiliotekę bez dodatkowych zależności - w postaci, w jakiej wstępuje w repozytorium. Composer nie zastąpi w tym przypadku komendy npm install colorbox, która oprócz Colorboxa pobierze dodatkowo kilkaset lub kilkadziesiąt pakietów zależnych. Ma to swoje wady i zalety. Zaletą jest oszczędność miejsca i uniknięcie ściągania nadmiarowych plików, wadą - brak możliwości uruchamiania kodu wywodzącego się z NodeJS. Innymi słowy, zyskujemy łatwiejszą aktualizację bibliotek frontendowych, tracimy zaś możliwość samodzielnego ich kompilowania.
8. Nie bój się używać Cweagan's Patches
Używanie plików .patch jest w Drupalu powszechne i ma wyjątkowo długą tradycję. Composer ułatwia zarządzanie patchami i pozwala zapanować nad ich zaawansowanymi zestawami. Zacznij od komendy dodającej do projektu plugin Cweagan's Patches:
composer require cweagans/composer-patches
Niezbędną konfigurację umieść w pliku composer.json:
"patches": {
"drupal/core": {
"Fix everything": "patches/core_fix_everything.patch",
"Fix one more thing": "https://www.drupal.org/files/issues/fix-one-more.patch"
},
"drupal/colorbox": {
"Fix something": "patches/colorbox_fix_something.patch",
}
}
Pliki z patchami mogą znajdować się zarówno w Twoim repozytorium, jak i w Internecie. Więcej opcji konfiguracyjnych znajdziesz w dokumentacji na stronie https://github.com/cweagans/composer-patches. Wszystkie poprawki z powyższej listy zostaną automatycznie zastosowane do oryginalnych plików przy następnym wywołaniu composer update.
Jakie korzyści odniesiesz z użycia Cweagan's Patches? Przede wszystkim zgromadzisz w jednym miejscu wszystkie łatki i zapomnisz o ich manualnym nakładaniu. Composer zajmie się tym sam. Wciąż jednak musisz pilnować, czy zmiany zawarte w patchach nie zostały już uwzględnione w nowszych wersjach uaktualnianych pakietów.
9. W Drupalu odrobina paranoi nie zaszkodzi
Drupal jest projektem mocno zorientowanym na bezpieczeństwo, ale jednocześnie jego architektura niesie za sobą pewne potencjalne zagrożenia. Mówię tu przede wszystkim o strukturze katalogów, która wymusza umieszczanie w webroot (czylu katalogu serwera udostępnianym na zewnątrz) zbyt wielu plików zawierających kod PHP. Co prawda odpowiednia konfiguracja eliminuje możliwość odczytania tego kodu, jednak nowoczesne praktyki - promowane głównie przez Symfony - dążą do pozostawienia w webroot wyłącznie plików przeznaczonych dla końcowego użytkownika.
Integracja Drupala z Composerem otworzyła nowe możliwości w kierunku zabezpieczenia plików PHP przed przypadkowym odczytaniem. Teoretycznie wszystkie ścieżki pobieranych bibliotek mogą być dowolnie zmieniane, ich odnalezieniem zajmuje się autoload. Ekstremalnym przypadkiem wykorzystania tej cechy Composera jest szablon https://github.com/drupal-composer/drupal-paranoia. Wymusza on przechowywanie wszystkich plików projektu w osobnym katalogu /app, udostępniając na zewnątrz wyłącznie linki symboliczne do zasobów takich, jak plik index.php lub katalogi sites/*/files.
Przypominam, że takie podejście wymaga posiadania systemu z rodziny UNIX.
10. Optymalizuj wersję produkcyjną
Istnieje kilka podstawowych zasad, jak używać Composera w środowisku produkcyjnym. Zastosowanie się do nich zwiększy bezpieczeństwo strony i przyspieszy jej działanie:
- Na serwerze produkcyjnym używaj wyłącznie komendy composer install, dopilnuj też, aby w repozytorium zawsze znajdował się plik composer.lock. Jeśli dopuścisz do uruchomienia komendy composer update, skutek może być nieprzewidziany. Aktualizację przeprowadzaj wyłącznie w środowisku developerskim. Takie podejście pozwoli Ci uniknąć problemów z niekompatybilnością nowych wersji.
- Używaj przełącznika composer install --no-dev, aby zaniechać instalacji bibliotek developerskich. Są one zadeklarowane w sekcji require-dev pliku composer.json.
- Wykorzystaj przełącznik composer install --optimize-autoloader, aby zbudować mapę klas. Dzięki niej autoloader nie będzie szukał plików na dysku według reguł PSR-4/PSR-0, zamiast tego otrzyma na podstawie nazwy klasy gotową ścieżkę do pliku z jej definicją. Aktywowanie tej optymalizacji w środowisku developerskim jest kłopotliwe, wiąże się bowiem z koniecznością czyszczenia cache po każdej zmianie w strukturze plików projektu.