Elixir, czyli wygodne zarządzanie assetami

Elixir to bardzo przyjemna nakładka na Gulp, która sprawia, że zarządzanie naszymi assetami staje się o wiele prostrze i przyjemniejsze. Możemy w bardzo łatwy sposób łączyć, minifikować oraz wersjonować nasze statyczne pliki. Używasz Less, Sass, CoffeeScript lub chcesz czerpać garściami z dobroci EcmaScript 6? Nie ma sprawy. Elixir ma to wszystko w małym palcu.

Eee… Gulp, Elixir… z czym to się je?

No właśnie, czym jest Gulp? To taki system do automatyzacji wykonywanych zadań dla języka JavaScript. A po co nam Elixir? Jak by się uprzeć, to nie jest on nam do niczego potrzebny, ale wtedy zamiast kilku komend musielibyśmy napisać o wiele więcej kodu, żeby uzyskać ten sam efekt… Elixir oferuje nam po prostu przyjazne API podczas pracy. Dlatego nie będziemy się męczyć i pójdziemy na skróty. W końcu nasza wygoda też ma znaczenie.

No dobrze, to jak zacząć?

  1. Na początek musimy zainstalować Node.js. W tym celu wchodzimy na stronę Node.js, pobieramy plik instalacyjny i dokonujemy instalacji.
  2. Sprawdzamy z konsoli czy wszystko jest ok, czyli wyświetlamy zainstalowaną wersję Node.js node -v
  3. Sprawdzamy też wersję dla npm (to taki odpowiednik composera dla JavaScript) npm -v
  4. Zakładam, że obyło się bez niespodzianek, więc możemy przejśc do instalacji Gulp:
  5. npm install –global gulp
  6. Jeśli instalacja Gulp się powiodła, możemy zacząć tworzyć nasz przykładowy projekt. Ściągamy CodeIgniter (w chwili powstawania tego wpisu najnowszą wersją jest 3.0.5) i dokonujemy kilku zmian organizacyjnych. Oczywiście nie musimy tego robić, ale moim zdaniem jest to dobra praktyka, z którą możemy się przy okazji zapoznać. Ponadto taka zmiana sprawi, że wszystko będzie „uporządkowane” (przynajmniej wg mnie). Oto jak powinna wyglądać struktura naszego projektu po zmianach:
    nasz_projekt/
    ├── application/
    ├── system/
    ├── public/
    │ ├── css/
    │ ├── js/
    │ └── index.php
    ├── resources/
    │ ├── sass/
    │ └── js/
    ├── gulpfile.js
    └── package.json

    Dwa ostatnie pliki (gulpfile.js i package.json) jak i katalog resources jeszcze nie powstały, ale załączam je, żeby nie było wątpliwości co i gdzie ma się znaleźć. Po dojściu do kolejnych punktów, wszystko stanie się jasne.

    Najważniejszą zmianą jest przeniesienie pliku index.php do katalogu public (który musieliśmy stworzyć). Zakładamy więc, że nasza przykładowa domena, dla tego projektu (http://naszprojekt.dev) będzie kierowała bezpośrednio na katalog public. Musimy jeszcze tylko edytować plik index.php i zmienić ścieżki, dla dwóch zmiennych, które pozwalają na zlokalizowanie plikow frameworka:

    $system_path = '../system';
    
    $application_folder = '../application';
  7. Jeśli nasza nowa struktura aplikacji jest gotowa, możemy stworzyć plik package.json (to taki odpowiednik dla composer.json z PHP) w głównym katalogu naszego projektu.
    {
        "private": true,
        "devDependencies": {
            "gulp": "^3.8.8"
        },
        "dependencies": {
            "laravel-elixir": "^5.0.0"
        }
    }
  8. Możemy teraz wykonać polecenie npm install. W głównym katalogu naszego projektu zostanie stworzony folder node_modules. Na marginesie – jeśli używamy systemu kontroli wersji, to upewnijmy się, żeby dla tego katalogu nigdy nie śledzić zmian. Najlepiej dodać go od razu do .gitignore.
  9.  Zaraz zaczniemy konfigurację naszego głównego pliku, ale przedtem nakreślę jak wygląda struktura naszych assetów. Zamysł jest taki, aby wszystkie nasze pliki trzymać w katalogu resources/sass i resources/js. Dopiero wynikowe pliki pracy Elixir trafią do odpowiednich katalogów w public/css i public/js. Plików z tych dwóch ostatnich katalogów będziemy używać na codzień w naszej aplikacji. Tutaj mała uwaga, jeśli używalibyśmy Less, to nasze pliki trzymalibyśmy w katalogu resources/less, jeśli CSS, to resources/css – zasada jest raczej przejrzysta. W razie wątpliwości można zajrzeć do dokumentacji.
  10. Stwórzmy teraz jakieś przykładowe pliki, na których będziemy mogli sprawdzić jak działa Elixir.
    // app.scss
    @import "colors";
    
    body {
        background-color: $primary-background;
        color: $primary-color;
    }
    $primary-background: green;
    $primary-color: white;
    console.log('one')
    console.log('two')
  11. Teraz w głównym katalogu naszego projektu możemy stworzyć plik gulpfile.js, w którym będziemy definiować wszytkie zadania jakie są do wykonania.
    var elixir = require('laravel-elixir');
    
    elixir.config.assetsPath = 'resources';
    elixir.config.publicPath = 'public';
    
    elixir(function(mix) {
        mix.sass([
          'app.scss'
        ]);
    
        mix.scripts([
            "one.js",
            "two.js"
        ]);
    });
  12. Żeby wykonać wszystkie zadania, które zdefiniowaliśmy, wystraczy teraz w konsoli wpisać polecenie gulp . Jeśli pracujemy przy projekcie i wprowadzamy zmiany, to ciągłe wpisywanie tego polecenia w konsoli, może być dosyć uciążliwe, dlatego w takim przypadku można użyć polecenia gulp watch . Sprawi ono, że każda zmiana w którymś z plików, spowoduje ponowne wywołanie naszego zadania i kompilację assetów. Tutaj ważna uwaga – assety są minifikowane tylko wtedy, kiedy dodamy specjalną flagę do wywołania gulp –production . W innym wypadku Elixir uzna, że pracujemy w środowisku developerskim i z oczywistych względów pominie proces minifikacji.
  13.  Moją ulubioną funkcją, którą posiada Elixir jest możliwość wersjonowania assetów. Zazwyczaj używa się dosyć „agresywnego” cache’owania i jest to bardzo dobre rozwiązanie, ale problem pojawia się kiedy dokonujemy jakichś zmian. Co zrobić, żeby użytkownicy zawsze mieli najświerzsze pliki js/css? Zazwyczaj dodawało się (różnymi sposobami) jakąś specjalną zmienną QUERY_STRING, typu: style.css?v=12. Elixir pozwala nam taki proces całkowinie zautomatyzować. Pierwszą rzeczą jaką musimy zrobić, to edytować plik gulpfile.js, aby nasze assety były wersjonowane.
    var elixir = require('laravel-elixir');
    
    elixir.config.assetsPath = 'resources';
    elixir.config.publicPath = 'public';
    
    elixir(function(mix) {
        mix.sass([
          'app.scss'
        ])
    
        mix.scripts([
            "one.js",
            "two.js"
        ])
    
        mix.version([
          'public/css/app.css',
          'public/js/all.js'
        ]);
    });

    Co się tutaj właściwie dzieje? Przy komendzie version musimy określić, o które dokładnie pliki nam chodzi – co ważne, odwołujemy się do naszych wynikowych plików, bo to na ich podstawie są tworzone wersje. Teraz w katalogu public, został wygenerowany katalog build, który zawiera nasze zwersjonowane wersje plików. Jest tam też plik rev-manifest.json i to on umożliwi nam automatyczne używanie aktualnej wersji plików w naszym projekcie.

    Teraz pora na stworzenie helpera dla CI, który załatwi za nas całą sprawę.

    /**
     * Elixir asset helper
     *
     * @param string $file File name
     * @return string
     */
    function elixir($file)
    {
        static $manifest = NULL;
    
        if (is_null($manifest))
        {
            $manifest = json_decode(file_get_contents(FCPATH . '/build/rev-manifest.json'), TRUE);
        }
    
        if (isset($manifest[$file]))
        {
            return '/build/' . $manifest[$file];
        }
    
        show_error("File {$file} not defined in asset manifest.");
    }

    13. Pozostało nam więc tylko przetestować jak to wszystko działa razem. Żeby to zrobić musimy stworzyć przykładową stronę. Stworzymy nową metodę w kontrolerze Welcome:

    class Welcome extends CI_Controller {
    
        public function index()
        {
            $this->load->view('welcome_message');
        }
    
        public function test()
        {
            $this->load->helper('elixir');
            $this->load->view('test');
        }
    
    }

    Teraz nasz testowy widok:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <title>CodeIgniter, Gulp i Elixir</title>
      <link href="<?= elixir('css/app.css'); ?>" rel="stylesheet">
      <script src="<?= elixir('js/all.js'); ?>" type="text/javascript"></script>
    </head>
    <body>
    
    To jest biały tekst na zielonym tle... i jakieś logi w konsoli.
    
    </body>
    </html>

    14. Możemy wykonać polecenie gulp  w konsoli. Jeśli odwiedzimy adres: http://naszprojekt.dev/welcome/test, to powinniśmy zobaczyć biały tekst na zielonym tle. Jeśli spojrzymy w źródło strony, to zobaczymy, że nasze nazwy plików, które podaliśmy jako parametr w helperze elixir, zostały zamienione na nazwy plików wersjonowanych. Teraz zmieńmy kolor tła strony na brown (musimy edytować plik resources/sass/colors.scss) i wywołajmy polecenie gulp , aby wygenerować pliki ponownie. Jeśli odświerzymy naszą testową stronę, to zobaczymy, że zmiany zostaly uwzgędnione, a co ważniejsze zmieniła się też wersja plików, które wczytał helper elixir.

Gotowe. W tym wpisie zostały pokazane tylko podstawy. Jest jeszcze trochę innych opcji – przede wszystki pod względem konfiguracji. Możemy np. definiować własne nazwy dla plikow, które zostaną wygenerowane, używać EcmaScript 6 itd. Nie jest to nic skomplikowanego i po zapoznaniu się z dokumentacją nie będzie żadnym problemem. Jeśli więc zainteresujecie się tym tematem, to zachęcam do przejrzenia dokumentacji Elixir.

6 komentarzy do wpisu „Elixir, czyli wygodne zarządzanie assetami”

  1. Dzięki za tuto. Elixir w zasadzie ma wszystko co potrzeba, i jest trochę prostszy niż stosowanie samego gulpa. Ogólnie z node to mam taki problem, że czasem coś przestaje działać po zupdejtowaniu. Np musiałem doklejać es6 promise polyfill,żeby zadziałały starsze skrypty. No ale porzuciłem compass i jestem już w tym „bagienku” :)

    A jako alternatywę mogę podpowiedzieć http://robo.li , kótry też wiele potrafi, a nie wymaga instalacji node.

  2. pytanko z tej beczki, wrzucam mix browser synca z proxy:localhost:8000 , za pierwszym razem mieli wszystko ok, ale przy zmianie pliku, już nie widzi.

    Stronę odpalam php -S localhost:8000 .

    mix.browserSync({
    proxy: ‚localhost:8000’
    });

    Jak może być przyczyna, pozdrawiam!

    • mix.browserSync({
      proxy: ‚localhost:8000’ //oczywiscie nawias byl taki
      });

      Rowniez nie dziala jesli jako proxy dam mojastrona.dev czy cos takiego i uzywam apache.

      • działa, tylko nocą miałem jakieś zaciemnienie. Trzeba określić wszystkie ścieżki naszej aplikacji, oto lista(aplikacja CI w starym stylu z index w roocie):

        elixir.config.assetsPath = ‚resources/assets’;
        elixir.config.publicPath = ”;
        elixir.config.appPath = ‚application’;
        elixir.config.css.folder = ‚css’;
        elixir.config.css.sass.folder = ‚sass’;
        elixir.config.css.outputFolder = ‚assets/css’;
        elixir.config.js.outputFolder = ‚assets/js’;
        elixir.config.viewPath = ‚application/views’;
        elixir.config.jsPath = ‚assets/js’;
        elixir.config.cssPath = ‚assets/css’;

        Należy to wkleić w gulpfile.js zaraz za var elixir = require…

        Jeśli byłyby jakieś problemy to można wystatować stronę wbudowanym serwerem php, czyli wejść tam gdzie mamy index.php i w konsoli:

        php -S 0.0.0.0:8000

Dodaj komentarz

This site uses Akismet to reduce spam. Learn how your comment data is processed.