GruntJS - nechte nudnou práci strojům

Příklad použití Grunt JS pro automatizaci rutinních činností, předvedený na setkání vývojařů GDG SCL Liberec 5.12.2013.

Story

Bylo nebylo Ramesh Nair sepsal docela pěknou javascriptovou kalkulačku viz. http://calc.hiddentao.com/

Na desktopu funguje bezvadně, z mobilu už je to trochu slabší, takže jsem kód trochu přepsal a ovládání pomocí myši a klávesnice předělal na touch události. Mimo jiné.

Protože LTE datové přenosy fungují jen v reklamách a 3G sítě jen na vybraných místech v Praze, chceme mít kód na mobilním zařízení co nejmenší. Nebo alespoň já. Takže proč výsledný javascript trochu nezmenšit? A co je dneska na světě lepší pro zmenšování javascriptu, než Google Closure compiler v advanced režimu.

Closure compiler přebírá při spouštění řadu parametrů, navíc ho budu spouštět opakovaně. To je úkol jak dělaný pro nějakého pomocníka. Kdysi jsem na to měl bat soubor ve Windows. Ale v Linuxu mi nefunguje. Asi by se na to dal napsat Bash či Python skript...

Ale kdepak. Ve světě javascriptu je dneska pomocníkem číslo jedna GruntJS.

Začínáme

Grunt běží nad nodeJS, stejně jako všechny jeho pluginy. Díky tomu ho můžete použít na všech platformách, pro které existuje node.js. Pro Closure compiler potřebujeme také Javu.

Nejprve je potřeba nainstalovat Grunt klienta a to jako jako globální npm balíček. Uděláme to příkazem:

npm install -g grunt-cli

Základem gruntování jsou dva konfigurační soubory. Package.json nám ohlídá závislosti projektu a Gruntfile.js je hlavním konfiguračním souborem pro jednotlivé úkoly, které bude Grunt řešit. Package json vytvoříme v aktuálním adresáři příkazem:

npm init

Gruntfile.js může být prozatím prázdný, naplní ho jednotlivé úkoly. Nejprve ale potřebujeme samotný grunt-task aby je měl kdo vykonávat.

npm install grunt --save-dev

Volba --save-dev je velice užitečná - do konfiguračního souboru package.json nám zaregistruje závislost na Gruntjs včetně verze. Takže to nemusíme řešit ručně. Konfigurační soubor bude vypadat nějak takhle:

{
  "name": "simplecalc",
  "version": "0.0.1",
  "description": "simple calculator and grunt demo",
  "author": "Jiri Vrany",
  "license": "MIT",
  "devDependencies": {
    "grunt": "~0.4.2"
  }
}

Stav projektu na začátku, včetně této konfigurace, najdete v prvním commitu do vzorového repozitáře. Commitoval jsem průběžně (nebo se o to aspoň snažil), takže v historii repozitáře můžete sledovat jak se jednotlivé konfigurační soubory v čase měnily.

Nastupuje compiler

Closure compiler task pro grunt se instaluje stejně jako všechny ostatní pomocí npm. Closure compiler je potřeba si stáhnout samostatně. V konfiguračním souboru gruntfile.js pak musíme nastavit správnou cestu ke kompilátoru - closurePath. Celý konfigurační soubor s jedním úkolem pro grunta, vypadá takhle:

module.exports = function(grunt) {

    grunt.loadNpmTasks('grunt-closure-compiler');

    grunt.initConfig({
        'closure-compiler': {
            frontend: {
                closurePath: 'tools/closure',
                js: 'app/calc.js',
                jsOutputFile: 'dist/calc.js',
                maxBuffer: 500,
                options: {
                    compilation_level: 'ADVANCED_OPTIMIZATIONS',
                    language_in: 'ECMASCRIPT5_STRICT'
                }
            }
        }
    });

    // Default task(s).
    grunt.registerTask('default', [
      'closure-compiler',
      ]);
};

Grunt pracuje jako NodeJS modul, a celá konfigurace je uzavřena do JS funkce. Základní konfigurační direktivy jsou loadNpmTask - pro načtení úlohy, initConfig - pro konfigurace a registerTask, pro vytváření komplexnějších úloh složených z několika úkolů. Načítání jednotlivých npm lze automatizovat za pomocí package.json, ale pro začátek je to takto přehlednější.

Konfigurace je hotová, takže můžeme překládat. Pokud je soubor calc.js v adresáři app správně anotovaný a přeložitelný, objeví se nám výsledek v adresáři dist. Samozřejmě, že až po té co úlohu spustíme. A protože máme registrovaný výchozí task - default, stačí k tomu jen příkaz:

grunt

Můžeme ale pustit i konkrétní úlohu, v tomto případě tedy closure-compiler, víc jich zatím nemáme:

grunt closure-compiler

A to je celé. Od této chvíle se zase už zase můžu měnit kód a nechat closure compiler pracovat. A nebo můžu použít grunt k tomu, abych měl té automatiky ještě trochu více.

Další úlohy

Grunt toho umí opravdu hodně. Pluginů pro jednotlivé úlohy bude hodně přes 100. Jen od samotných vývojářů Grunta (tzv. contrib pluginů) je jich už 30. Pro daný problém - tedy mobilní aplikaci jsem v ukázce použil ještě:

Všechny pluginy je vhodné instalovat s přepínačem --save-dev. Všechny použité pluginy jsou vidět ve finální verzi konfiguračního souboru. A všechny mají dobrou a přehlednou dokumentaci (chtěl jsem napsat samozřejmě, ale ono to tak samozřejmé není).

Pokud by bylo třeba, šlo by přidávat další a další pluginy. Například pro spouštění různých testů: Mocha, Jasmine, Qunit. Dokonce to jde i paralelně. Také můžete překládat coffee script či less. No zkrátka na co si člověk vzpomene a ještě hromadu věcí o kterých možná ani neví, že existují.

Jedním z dalších plusů celého řešení je, že pokud si uděláte klon tohoto repozitáře, stačí v adresáři napsat jen:

npm install

Grunt a všechny další pluginy se nainstalují tak, jak jim to určil konfigurační soubor. Stačí tedy jen přidat Closure compiler (bower task jsem pro něj zatím nenašel) a vše je připraveno k práci - na jiném počítači, u kolegy v týmu a tak dále.

Grunt je výborný nástroj, který vás odstíní od nudné a rutinní činnosti a umožní vám se soustředit na to, co je na vývoji aplikací zábavné - tedy samotné programování. Tak se nebojte a začněte gruntovat.