Blog (10)
Komentarze (45)
Recenzje (0)

Grunt.js i automatyzacja pracy - początek

@HitcHGrunt.js i automatyzacja pracy - początek17.05.2015 13:50

Lepiej sformatowany artykuł z podlinkowaniem możecie znaleźć tu: http://psds.pl/grunt-js-i-automatyzacja-pracy/

Słowem wstępu - czym jest Grunt?

Grunt.js jest task runnerem w którym możemy stworzyć listę zadań (użyjąc gotowych lub napisać swoje) wykonywane pod odpaleniu odpowiedniego polecenia. Pozwala nam to oszczędzić sporo czasu, zautomatyzować naszą prace i pozbyć się czasem nudnej i żmudnej pracy. Dla przykładu: komplipacja scss bądź less, minifikacja css, generowanie sprite'ów, sprawdzenie błedów w plikach JS i wiele więcej.

Sama instalacja i konfiguracja jest dziecinnie prosta, choć wymaga trochę czasu i pomysłów co możemy jeszcze usprawnić (a zawsze można).

Na początek przygotujmy nasze środowisko.

Potrzebujemy:

Node.js - instalujemy najnowszą wersje, automatycznie doda nam PATH do konsoli dzięki czemu będziemy mogli instalować moduły poleceniem npm install Grunt.js - po instalacji node.js w konsoli wykonujemy polecenie npm install -g grunt-cli Pomysły co można sobie zautomatyzować ;)

Zaczynamy zabawę

Podzielimy zadania na 2 środowiska - developerskie i produkcyjne. W pierwszym znajdą się zadania wykonywane przy każdej zmianie w pliku, w produkcyjnym natomiast zadbamy o odchudzenie plików.

Środowisko developerskie

Na początek ułatwmy sobie prace z scss. Przyjrzyjmy się strukturze tasków w Gruncie. Może przerażać, ale bez obawy - całość jest dziecinnie prosta!


module.exports = function(grunt) {
    // Project configuration.
    grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    task: {
        opcje: {

        },
        operacje: {

        }
    }
  });
   grunt.loadNpmTasks('modul-grunta'); // w taki sposób ładujemy nasze moduły
   grunt.registerTask('default', ['zadanie domyślne']); // określany jakie zadania wykonują się po wpisaniu w konsoli grunt
};

Wypadałoby od razu wyjaśnić z czego jest zbudowany plik Gruntfile.js. Skruktura pliki zazwyczaj jest taka sama, różni się zadaniami (czy zawsze o tym innym razem).

W 4 linii: pkg: grunt.file.readJSON('package.json'), mamy odniesienie do pliku package.json - plik ten zawiera informację o tym z jakich modułów korzystamy. Na razie się nim nie przejmujmy.

Poniżej pierwsze zainicjowanie taska. Zadania możemy znaleźć na Gruntjs.com lub npmjs.com.

Na pierwszy ogień idzie kompilacja plików scss. Użyję do tego libsassa - jest zdecydowanie szybszy niż compass i sass. Pobierzemy sobie zadanie grunt-libsass poleceniem npm install grunt-libsass --save-dev (dopisek --save-dev dodaje nam pakiet do pliku package.json, więc warto go używać). Czas na stworzenie taska.

libsass: { //zadanie główne
    files: {
        expand: true,
        src: ['css/style.scss'], // pliki na których domyślnie ma byc wykonane zadanie
        dest: '', // gdzie mają się zapisać skompilowane pliki css (w tym przypadku zapisze się w lokalizacji pliku scss
        ext: '.css' // rozszenie po skimpilowaniu
    }
},

Pełna lista ustawień przeważnie znajduje się na stronie pakietu bądź na githubie autora.

Teraz trzeba powiedzieć gruntowi, żeby załadowal nasze zadanie: grunt.loadNpmTasks('grunt-libsass'); Teraz wystarczy odpalić polecenie grunt libsass, żeby skompilowało nasze pliki.

Ale to nadal za mało. Czemu nie miałoby kompilować od razu po zapisaniu pliku? I to jakiegokolwiek w folderze z naszymi scss?

I z pomocą przychodzi nam obowiązkowe zadanie: watch! Instalujemy: npm install grunt-contrib-watch --save-dev, konfigurujemy:

watch: {
    scss: { // możemy określić dowolną nazwę
        files: ['css/*.scss'], //określamy na jakich plikach pracujemy
        tasks: ['libsass'] // wybieramy zadania jakie na nich wykonujemy, po kolei
    }
}

Ładujemy zadanie: grunt.loadNpmTasks('grunt-contrib-watch'); I dodajemy watch do domyślnych zadań (wykonywanych po odpaleniu polecenia grunt. grunt.registerTask('default', ['watch']); Zapisujemy, odpalamy w konsoli grunt i od teraz każda modyfikacja pliku scss w folderze css będzie powodować automatyczne kompilowanie.

Sprite - wszystkie ikony w jednym obrazku

Żeby nieco zmniejszyć liczbę zapytać i przyspieszyć działanie strony możemy latwo scalić ikony w jeden obrazek i dla każdej ikony zmieniać background-position. Bez obaw - nic nie musimy pisać sami! Wykorzystamy grunt-spritesmith. Instalujemy npm install grunt-spritesmith --save-dev.

Następnie zadanie dla Grunta:

sprite: {
    all: {
        src: 'images/icons/*.png', // folder z naszymi ikonami, każda zmiana w nim będzie podować wygenerowanie sprita
        dest: 'images/spritesheet.png', // wynikowy plik z ikonami
        destCss: 'css/icons.scss', // plik gdzie wygeneruje nam mixin bądź css
        padding: 10, // odstęp pomiędzy ikonami
        cssOpts: {
            cssClass: function (item) {
                return '.icon-' + item.name; // przedrostek klasy
            }
          }
    }
}

Zadanie dla Was to stworzenia taska z optymalizacą otrzymanego PNG :) (np. grunt-pngmin).

Oto nasz cały plik gruntfile.js

module.exports = function (grunt) {
    'use strict';
    grunt.initConfig({
        sprite: {
            all: {
                src: 'images/icons/*.png', // folder z naszymi ikonami
                dest: 'images/spritesheet.png', // wynikowy plik z ikonami
                destCss: 'css/icons.scss', // plik gdzie wygeneruje nam mixin bądź css
                padding: 10, // odstęp pomiędzy ikonami
                cssOpts: {
                    cssClass: function (item) {
                        return '.icon-' + item.name; // przedrostek klasy
                    }
                }
            }
        },
        libsass: {
            files: {
                expand: true,
                src: ['css/style.scss'],
                dest: '',
                ext: '.css'
            }
        },
        watch: {
            libsass: {
                files: ['css/*.scss', 'css/**/*.scss'],
                tasks: ['libsass']
            },
            sprite: {
              files: ['images/icons/*.png'],
              tasks: ['sprite']
          }
        }
    });

    // ładowanie wybranych modułów dla Grunt.js
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-libsass');
    grunt.loadNpmTasks('grunt-spritesmith');

    // rejestrowanie domyślnego zestawu zadań dla Grunt.js
    grunt.registerTask('default', ['watch']);
}; 

Możemy również zdefiniować swoje zadania: grunt.registerTask('zadanie', ['inne', 'zadania', 'ktore', 'wykonujemy']);. Podobnie jest z wykonaniem pojedynczego zadania i subzadania: grunt libsass wykonana nam wszystko z libsass, ale już grunt libsass:files tylko to co znajduje się w files.

Dodajcie sobie również task grunt-notify żeby być powiadamianym o udane bądź nie kompilacji, w końcu nie patrzymy ciągle na konsole.

Generowanie środowiska produkcyjnego

Przy generowaniu środowiska produkcyjnego powinno nam zależeć na możliwie największym zmniejszeniu wagi plików - nie musi to być czytelne. Jednym poleceniem załatwimy sprawę zminifikowania plików css, js i html. Zakładam, że korzystacie z @import w scss także pomijam łączenie.

Wykorzystamy zadanie grunt-contrib-compressor, idealnie się nada a jest bardzo proste w obsłudze. Całość oczyszczona i odchudzona będzie trzymana w folderze dist. Oto task:

compressor:{
    css:{
        files: {
            'dist/css/style.css': ['css/style.css']
        }
    },
    js:{
        options: {
            mangle: true
        },
        files:grunt.file.expandMapping(['js/*.js','js/*/*.js'], '', {
            rename: function(base,file) {
                return 'dist/'+file;
            }
        })
    },
    html:{
        options:{
            removeComments: true, // usunie komentarze
            collapseWhitespace: true
        },
        files:{
            'dist/index.html': ['index.html']
        }
    }
},

Jak możecie zauważyć niewiele różni się od przykładu na Githubie. A żeby oduczyć stosowania kopiuj-wklej zostawiam Wam modyfikację do wprowadzenia - minifikację wszystkich plików HTML.

I tu małe zadanie: czasem zdarzy się, że nie działają JSy. Problemem może być brak średników. Jest od tego zadanie - dodaje (skutecznie) średniki dla końcu linii tam gdzie potrzeba. jssemicoloned może być pomocny! Dajcie znać o efektach :)

Nasz Gruntfile.js na koniec powinien wyglądać tak:

module.exports = function (grunt) {
  'use strict';
  grunt.initConfig({
      sprite: {
          all: {
              src: 'images/icons/*.png',
              dest: 'images/spritesheet.png',
              destCss: 'css/icons.scss',
              padding: 20,
              cssOpts: {
                  cssClass: function (item) {
                      return '.icon-' + item.name;
                  }
              },
          }
      },
      libsass: {
          files: {
              expand: true,
              src: ['css/style.scss', 'css/icons.scss', 'css/modules/**/*.scss'],
              dest: '',
              ext: '.css'
          }
      },
      notify: {
          watch: {
              options: {
                  title: 'Wszystko ok!',
                  message: 'Bez błedów, oby tak dalej!'
              }
          }
      },
      compressor:{
          css:{
              files: {
                  'dist/css/style.css': ['css/style.css']
              }
          },
          js:{
              options: {
                  mangle: true
              },
              files:grunt.file.expandMapping(['js/*.js','js/*/*.js'], '', {
                  rename: function(base,file) {
                      return 'dist/'+file;
                  }
              })
          },
          html:{
              options:{
                  removeComments: true,
                  collapseWhitespace: true
              },
              files:{
                  'dist/index.html': ['index.html']
              }
          }
      },
      watch: {
          libsass: {
              files: ['css/*.scss', 'css/**/*.scss'],
              tasks: ['libsass', 'notify']
          },
          sprite: {
              files: ['images/icons/*.png'],
              tasks: ['sprite']
          }
      }
  });
  // ładowanie wybranych rozszerzeń dla Grunt.js

  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-compressor');
  grunt.loadNpmTasks('grunt-libsass');
  grunt.loadNpmTasks('grunt-notify');
  grunt.loadNpmTasks('grunt-spritesmith');

  // rejestrowanie domyślnego zestawu zadań dla Grunt.js
  grunt.registerTask('default', ['watch', 'notify']);
  grunt.registerTask('prod', ['compressor', 'notify']);
};
Szanowna Użytkowniczko! Szanowny Użytkowniku!
×
Aby dalej móc dostarczać coraz lepsze materiały redakcyjne i udostępniać coraz lepsze usługi, potrzebujemy zgody na dopasowanie treści marketingowych do Twojego zachowania. Twoje dane są u nas bezpieczne, a zgodę możesz wycofać w każdej chwili na podstronie polityka prywatności.

Kliknij "PRZECHODZĘ DO SERWISU" lub na symbol "X" w górnym rogu tej planszy, jeżeli zgadzasz się na przetwarzanie przez Wirtualną Polskę i naszych Zaufanych Partnerów Twoich danych osobowych, zbieranych w ramach korzystania przez Ciebie z usług, portali i serwisów internetowych Wirtualnej Polski (w tym danych zapisywanych w plikach cookies) w celach marketingowych realizowanych na zlecenie naszych Zaufanych Partnerów. Jeśli nie zgadzasz się na przetwarzanie Twoich danych osobowych skorzystaj z ustawień w polityce prywatności. Zgoda jest dobrowolna i możesz ją w dowolnym momencie wycofać zmieniając ustawienia w polityce prywatności (w której znajdziesz odpowiedzi na wszystkie pytania związane z przetwarzaniem Twoich danych osobowych).

Od 25 maja 2018 roku obowiązuje Rozporządzenie Parlamentu Europejskiego i Rady (UE) 2016/679 (określane jako "RODO"). W związku z tym chcielibyśmy poinformować o przetwarzaniu Twoich danych oraz zasadach, na jakich odbywa się to po dniu 25 maja 2018 roku.

Kto będzie administratorem Twoich danych?

Administratorami Twoich danych będzie Wirtualna Polska Media Spółka Akcyjna z siedzibą w Warszawie, oraz pozostałe spółki z grupy Wirtualna Polska, jak również nasi Zaufani Partnerzy, z którymi stale współpracujemy. Szczegółowe informacje dotyczące administratorów znajdują się w polityce prywatności.

O jakich danych mówimy?

Chodzi o dane osobowe, które są zbierane w ramach korzystania przez Ciebie z naszych usług, portali i serwisów internetowych udostępnianych przez Wirtualną Polskę, w tym zapisywanych w plikach cookies, które są instalowane na naszych stronach przez Wirtualną Polskę oraz naszych Zaufanych Partnerów.

Dlaczego chcemy przetwarzać Twoje dane?

Przetwarzamy je dostarczać coraz lepsze materiały redakcyjne, dopasować ich tematykę do Twoich zainteresowań, tworzyć portale i serwisy internetowe, z których będziesz korzystać z przyjemnością, zapewniać większe bezpieczeństwo usług, udoskonalać nasze usługi i maksymalnie dopasować je do Twoich zainteresowań, pokazywać reklamy dopasowane do Twoich potrzeb. Szczegółowe informacje dotyczące celów przetwarzania Twoich danych znajdują się w polityce prywatności.

Komu możemy przekazać dane?

Twoje dane możemy przekazywać podmiotom przetwarzającym je na nasze zlecenie oraz podmiotom uprawnionym do uzyskania danych na podstawie obowiązującego prawa – oczywiście tylko, gdy wystąpią z żądaniem w oparciu o stosowną podstawę prawną.

Jakie masz prawa w stosunku do Twoich danych?

Masz prawo żądania dostępu, sprostowania, usunięcia lub ograniczenia przetwarzania danych. Możesz wycofać zgodę na przetwarzanie, zgłosić sprzeciw oraz skorzystać z innych praw wymienionych szczegółowo w polityce prywatności.

Jakie są podstawy prawne przetwarzania Twoich danych?

Podstawą prawną przetwarzania Twoich danych w celu świadczenia usług jest niezbędność do wykonania umów o ich świadczenie (tymi umowami są zazwyczaj regulaminy). Podstawą prawną przetwarzania danych w celu pomiarów statystycznych i marketingu własnego administratorów jest tzw. uzasadniony interes administratora. Przetwarzanie Twoich danych w celach marketingowych realizowanych przez Wirtualną Polskę na zlecenie Zaufanych Partnerów i bezpośrednio przez Zaufanych Partnerów będzie odbywać się na podstawie Twojej dobrowolnej zgody.