Jak poprawnie korzystać z LESS

Jak napisał na swoim blogu Chris Coyer, dobrze, że pytanie „czy używac preprocesora CSS” przerodziło się w „którego preprocesora CSS używać”. Ja korzystam z LESS — nie ze względu na jakieś jego kosmiczne możliwości w porównaniu z innymi, ale z przyzwyczajenia. Ale na drodze do radosnego korzystania z LESS stoją pewne przeszkody.

LESS wymaga JavaScriptu

No właśnie. LESS jest napędzany JavaScriptem. O ile nie jest to wielkim problemem dla większości użytkowników, należy pamiętać, że jakiś tam procent użytkowników wyłącza obsługę JavaScriptu. Piszę „jakiś tam” nie ze względu na brak danych na ten temat, ale raczej na fakt, że zależnie od strony internetowej, jej użytkownicy będa mieli JavaScript wyłączony w większym lub mniejszym odsetku, np. spodziewam się, że odwiedzający mój blog będą mieli wyłączony JavaScript znacznie częściej, toteż oprócz Prettify, nie używam JS w ogóle.

Co zatem zrobić, żeby nieszczęśnicy z wyłączonym JavaScriptem mogli dostać jakiś CSS na stronie?

Odpowiedzi są (co najmniej) dwie: albo prekompilować LESS lokalnie, na serwer wrzucając gotowe pliki CSS, albo prekompilować LESS po stronie serwera.

No właśnie: LESS można prekompilować również po stronie serwera, nie tylko klienta. Służy do tego bardzo fajny port LESSCSS, zwany LESSPHP. Dokumentację skryptu można oczywiście znaleźć na jego stronie, ale żeby nie zmuszać czytelników do zaglądania tam:

require_once "lessc.inc.php";
try {
    lessc::ccompile(
        PUBLIC_PATH . "/less/style.less",
        PUBLIC_PATH . "/css/style.css"
    );
} catch (exception $ex) {
    exit("lessc fatal error: " . $ex->getMessage());
}

Powyższy fragment kodu sprawdzi nam przy każdy wysłanym żądaniu przeglądarki, czy plik CSS istnieje i nie jest przypadkiem starszy niż oryginalny plik LESS, a jeśli tak, to przekompiluje LESS. Wszystko po stronie serwera, a przeglądarka dostanie wygenerowany automatycznie plik CSS.

LESSPHP obciąża serwer

Może nie jest to jakieś wielkie obciążenie, ale przy stronach o dużym natężeniu ruchu może to mieć znaczenie. Zawsze to jednak dołączenie dodatkowego pliku z niemałą klasą PHP, sprawdzenie istnienia pliku CSS, porównanie dat utworzenia CSS i LESS — a pamiętajmy, że plików LESS może być więcej niż jeden! Jeśli nie chcemy, żeby aplikacja męczyła twardy dysk przy każdym żądaniu przeglądarki, proponuję następujące rozwiązanie: kompilację warunkową. Warunek kompilacji może być dowolny, ja proponuję jednak kombinację tych trzech opcji:

APPLICATION_ENV

Po pierwsze, sprawdzenie wartości stałej APPLICATION_ENV, czy jej odpowiednika oznaczającego środowisko, w którym aktualnie pracuje aplikacja. Jeśli piszemy stronę na lokalnym serwerze, w virtual hoście (tutaj Apache) możemy określić sobie taką deklarację:

SetEnv APPLICATION_ENV development

Na serwerze produkcyjnym takiej deklaracji nie będzie, lub wartość zmiennej będzie ustawiona na production. Wykorzystujemy to w naszej aplikacji, tworząc odpowiednią stałą:

define("APPLICATION_ENV",
    (getenv("APPLICATION_ENV") ?
    getenv("APPLICATION_ENV") :
    "production")
);

Tak zdefiniowana stała będzie miała wartość development tylko na serwerze lokalnym.

Adres IP

Możemy również pozwolić na rekompilację pod warunkiem, że ze stroną łączymy się z danego adresu IP (zapewne naszego własnego):

$ip = $_SERVER["REMOTE_ADDR"];

Zmienna GET

Trzeci sposób, który proponuję to sprawdzenie, czy w tablicy GET nie ma jakiejś wartości, np. "LESS".

$less = isset($_GET["LESS"]);

Ostateczny kod

Reasumując, nasz kod mógłby wyglądać tak:

define("PUBLIC_PATH", realpath(dirname(__FILE__)));
define("APPLICATION_ENV",
    (getenv("APPLICATION_ENV") ?
    getenv("APPLICATION_ENV") :
    'production')
);
$ip = $_SERVER["REMOTE_ADDR"];
$less = isset($_GET["LESS"]);
if (APPLICATION_ENV == "development" ||
    ($less && in_array($ip, array("123.123.123.123")))
) {
    require_once "lessc.inc.php";
    try {
        lessc::ccompile(
            PUBLIC_PATH . "/less/style.less",
            PUBLIC_PATH . "/css/style.css"
        );
    } catch (exception $ex) {
        exit("lessc fatal error: ".$ex->getMessage());
    }
}

W ten sposób kod wykona się tylko jeżeli jest wywołany lokalnie lub z naszego adresu IP i z odpowiednim parametrem w query stringu.

Zachęcam do eksperymentów!


Komentarze

Andrzej

2012-10-30, 17:01

Mimo wszystko najlepiej i najefektywniej skompresować CSS lokalnie i taki wrzucić na serwer i nie bawić się w żadne warunkowe kompilacje. Ale co ja tam wiem... ;)

Dominik Marczuk

2012-10-30, 17:14

A dlaczego "co ja tam wiem"? Nie dość, że łebski gość z Ciebie (wnioskując po wypowiedziach na GL), to jeszcze skromny :D. Oczywiście, że metoda, o której mówisz jest najwydajniejsza, przecież to nie podlega nawet dyskusji. Ale w momencie, gdy dopiero stronkę stylujesz, to wygodnie jest mieć jednak jakiś automat. Ja w wersji produkcyjnej po prostu zakomentowuję wywołanie funkcji kompilującej LESS - zawsze w razie czego można odkomentować, a na co dzień zasobów nie żre :).


Napisz komentarz


Szukaj wpisów


Chmura tagów