Vytváříme vlastní Grunt plugin a pouštíme do světa npm

19. 7. 2020
0
0
7 min.
Vytváříme vlastní Grunt plugin a pouštíme do světa npm

Vytváření vlastních pluginů na Gruntu je překvapivě snadné. Možná se ptáte proč to dělat? Odpovědí mohou být různé, pro mě jsou důvody následující:

  • používám Grunt ve svém vývojovém prostředí (pro účely kódování je plně dostačující)
  • potřebuji specifické úpravy souborů, které neumožňuje žádný jiný plugin
  • líbí se mi myšlenka vytvoření vlastního pluginu, který si může stáhnout a používat kdokoliv na světě
  • jednoduchost

A protože jsem čerstvě během pár hodin vytvořil vlastní funkční plugin, rozhodl jsem se o tom podělit na svém blogu. Třeba se někomu bude hodit.

Jste připravení? Dáme se do práce!

Inicializace a instalace grunt pluginu

Začneme oficiálním návodem od Gruntu, který popisuje pár jednoduchých kroku pro tvorbu pluginu. V této fázi nic vymýšlet nebudeme a držíme se návodu.

  1. Nainstalujte grunt-init do vašeho počítače příkazem npm install -g grunt-init
  2. Nainstalujte gruntplugin šablonu příkazem
    git clone git://github.com/gruntjs/grunt-init-gruntplugin.git ~/.grunt-init/gruntplugin
    (%USERPROFILE%\.grunt-init\gruntplugin pro uživatele Windows)
  3. Spusťte příkaz grunt-init gruntplugin v prázdné složce. Spustí se průvodce, který vám položí sadu otázek. Po dokončení průvodce se vytvoří všechny potřebné soubory.
  4. Spusťte příkaz npm install

Tadááá. Právě jsme vytvořili a nainstalovali svůj první Grunt plugin. Nyní když spustíte příkaz grunt, pak proběhne výchozí build grunt pluginu, a pokud uvidíte zelený Done, pak vše funguje správně.

TIP: pokud nejdříve vytvoříte GIT repozitař pluginu (například v Github nebo Gitlab) a projekt inicializujete v této složce, pak inicializace Grunt pluginu je mnohem jednodušší, protože průvodce sám předvyplní všechny otázky a vy mačkáte jenom ENTER.

Rozbor a pochopení souborů

Když se podíváme co se vlastně stalo, tak v naši prázdné složce se objevili různé soubory. Nejvíce nás budou zajímat jen Gruntfile.js – ve kterém nastavujeme především soubory, které chceme prohnat skrz náš plugin a tasks/{nazev-projektu}.js – ve kterém probíhá veškerá logika a operace našeho pluginu. Nejefektivnější způsob pochopení je právě tento soubor, ve kterém si zkuste logiku pozměnit, spustit grunt a sledovat co se děje.

Vytváříme vlastní logiku

Jelikož já jsem převážně frontend kodér a předpokládám, že vy taky, tak vytvoříme jednoduchý Grunt plugin, který bude pracovat s HTML soubory a nějakým způsobem je upravovat.

Nejdříve potřebujeme nainstalovat knihovnu jsdom, která nám umožní číst obsah html souborů a pracovat s nim. Do příkazové řádky vložte.

npm
		npm i jsdom
	

Nyní, když máme nainstalováno, vytvoříme soubor index.html ve složce test a jeho obsah bude následující:

test/index.html
		<html>
  <body>
    <p>hello world</p>
    <p>this is my first grunt plugin</p>

    <img src="images/image.jpg" alt="">
    <img src="images/test.png" alt="">
  </body>
</html>
	

Nyní řekneme Gruntfile.js aby procházel tento náš soubor. Uděláme to jednoduše úpravou našeho tasku. Já svůj plugin pojmenoval „my-first-plugin“, vy ho možná pojmenovali jinak, tak si to upravte podle sebe. Zároveň vytvoříme jedno nastavení copyText, které uživatele pluginu budou moci měnit dle vlastních potřeb.

gruntfile.js
		my_first_plugin: {
  main: {
    options: {
      copyText: 'Copyright: My first grunt plugin'
    },
    files: {
      'tmp/index.html': 'test/index.html'
    }
  },
},
	

Dostáváme se k logice našeho pluginu, který jak už víme, píšeme v souboru tasks/my_first_plugin.js.

tasks/my_first_plugin.js
		'use strict';

module.exports = function(grunt) {

  var jsdom = require('jsdom');
  var JSDOM = jsdom.JSDOM;

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('my_first_plugin', 'The best Grunt plugin ever.', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      copyText: ''
    });

    // Iterate over all specified file groups.
    this.files.forEach(function(f) {
      // Check that the source file exists
      if (f.src.length === 0) {
        // Print a success message.
        grunt.log.warn('File "' + f.dest + '" does not exist.');
        return;
      }

      // init dom
      var dom = new JSDOM(grunt.file.read(f.src));
      var doc = dom.window.document;

      grunt.log.write(('Reading: ').green + f.src.toString());

      //calculate content length
      var paragraphs = doc.querySelectorAll('p');
      Array.prototype.forEach.call(paragraphs, function(el, i){
        var contentLength = el.textContent.length;
        el.setAttribute('data-content-length', contentLength);
      });

      //lazyload images
      var images = doc.querySelectorAll('img');
      Array.prototype.forEach.call(images, function(el, i){
        el.setAttribute('data-src', el.getAttribute('src'));
        el.classList.add('js-lazyload');
        el.setAttribute('src', 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7');
      });

      //append copyright to body
      var copy = doc.createElement("p");
      copy.textContent = options.copyText;
      doc.body.append(copy);

      var modifiedHtml = dom.serialize();

      // Write the destination file.
      grunt.file.write(f.dest, modifiedHtml);

      grunt.log.write('... ' + ('ok').green);
    });
  });
};
	

Nyní když do příkazového řádku zadám grunt my_first_plugin, tak proběhnou veškeré operace, ale když zadám jen grunt, tak grunt zařve chybu. Proč? Protože grunt provádí testy, které jsou vidět na tomto řádku v gruntfile.js
grunt.registerTask('test', ['clean', 'my_first_plugin', 'nodeunit']);.

Opravit to můžeme dvěma způsoby:

  1. jednodušší varianta je smazat nežádoucí kroky. Čili odmazat nodeunit z pole
  2. složitější a pracnější způsob je napsat testy správně, které jsou ve složce test, v mém případě je to soubor test/my_first_plugin_test.js. Když soubor otevřete tak uvidíte, že grunt porovnává jestli obsah vstupního a výstupního souboru prohnaného gruntem jsou stejné. Jelikož do souboru provádíme úpravy tak stejné být nesmí. Mírně pozměníme logiku a vše bude fungovat správně.
test/my_first_plugin_test.js
		exports.my_first_plugin = {
  setUp: function(done) {
    // setup here if necessary
    done();
  },
  main: function(test) {
    test.expect(1);

    var actual = grunt.file.read('tmp/index.html');
    var expected = grunt.file.read('test/index.html');
    test.notEqual(actual, expected, 'should describe what the default behavior is.');

    test.done();
  }
};
	

Hotovo! Nyní když zadáme grunt do příkazového řádku, veškeré procesy proběhnou a grunt napíše „Done“. Když se podíváme do výstupního souboru, který se nachází v tmp/index.html tak vypadá následně:

tmp/index.html
		<html>
   <body>
        <p data-content-length="11">hello world</p>
        <p data-content-length="29">this is my first grunt plugin</p>

        <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="" data-src="images/image.jpg" class="js-lazyload">
        <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="" data-src="images/test.png" class="js-lazyload">
    
        <p>Copyright: My first grunt plugin</p>
    </body>
</html>
	

Při porovnání html souborů vidíme provedené operace, jsou to:

  1. najdeme všechny paragrafy, spočítáme počet znaků v každém z nich a vložíme to do data-content-length atributu
  2. projdeme všechny obrázky, přesuneme src do data-src atributu, přidáme třídu js-lazyload a do src vložíme base64 placeholder
  3. před </body> vložíme copyright text, který bude možné měnit skrze nastavení v gruntu

Jsou to jen příklady, které mě napadly. Možností máte neomezené množství a můžete se soubory provádět cokoliv co vás napadne a co vám javascript dovolí 🙂

Publikace do světa

Nyní, když máme funkční plugin připravený k publikaci do světa, do příkazové řádky vepíšeme npm publish. Tímto příkazem se vytvoří veřejný npm balíček, který si kdokoliv může stáhnout a používat včetně vás.

Pokud vám článek přišel užitečný neváhejte se pochlubit co jste udobřili v komentářích.

Chcete odebírat podobné články?

Přihlášení proběhlo úspěšně

Související články

Komentáře

Zatím zde nejsou žádné komentáře.

Přidat nový komentář
Odpovědět na komentář

od: