Tento článek patří do seriálu Zrychlení webu a dev stack. Ostatní články seriálu:
- Cachujeme, GZipujeme, zrychlujeme
- SVG a PNG Sprite, zrychlujeme podruhé
- Minifikace - zrychlujeme po třetí
- DataURI - zrychlujeme po čtvrté
- Webpack lusknutím prstu - Laravel Mix - Alternativa ke Gruntu a Gulpu
- Fiddler - web debugger
- Nastavení GZip komprese u souborů s fonty
- Automatizace s Gruntem - Automatizace ostatních technik ze seriálu
- Systém SVG ikon s Gulpem
Grunt i všechny jeho balíčky jsou napsané v NodeJS, takže je asi jasné, že si jej musíme nainstalovat také. Naštěstí je stejně jako většina moderních jazyků multiplatformní, a funguje pod Windows i Linuxem. Když máme NodeJS, je zapotřebí Node package manager, zkráceně NPM (I když možná ne...). Ten někdy je součástí instalace NodeJS. Poté si můžeme hledat pluginy, a samozřejmě nainstalujeme Grunt.
Grunt lze velmi výhodně využít k automatizaci technik pro zrychlení načítání, o kterých jsem psal v předchozích článcích.
package.json
Pokud si najdeme balíček, většinou obsahuje příkaz k instalaci podobný tomu níže. Přepínač --save-dev totiž vloží informace o aktuálním balíčku do souboru package.json, díky čemuž do GITu nemusíme nahrávat všechny balíčky, které mohou mít stovky MB.
# Nainstaluje balíček grunt-contrib-clean a vloží do package.json npm install grunt-contrib-clean --save-dev # Nainstaluje všechny balíčky zmíněné v package.json npm install
Stačí na jiném počítači spustit npm install a všechny balíčky se nainstalují také. Soubor package.json můžete vytvořit ručně a vložit základní kostru, jako je ukázáno níže. Nebo stačí zadat npm init, který soubor vytvoří za vás. Někdy stačí pouze vložit { }
{ "name": "blog", "devDependencies": { } }
Balíčky a jejich nastavení
Další soubor, který vytvoříme se jmenuje Gruntfile.js a vložíme jej do hlavní složky projektu. Výhodou konfiguračního souboru je, že je nečekaně napsán v JavaScriptu, takže si v něm můžeme libovolně volat funkce a psát skripty. Celý můj Gruntfile najdete níže a obsahuje plno balíčků pro kompilaci React JSX syntaxe do JavaScriptu, Sassu do CSS, spojení CSS a JS souborů, build a spuštění serveru v Golangu a také automatickou synchronizaci prohlížeče. To vše automaticky po změně souborů. Gruntem se ale také dají automatizovat testy a mnohé další.
Soubor není krátký, ale zato jsem komentáře vložil přímo do něj. Celý soubor můžete také stáhnout, pokud se lépe bude číst v editoru.
module.exports = function(grunt) { // Vlastní funkce, kterou si zavoláme níže v tasku concat this.getConcatArray = function(dist) { // POZOR // Minifikovaný React je produkční verze, neminifikovaná je vývojová verze // Vývojová verze obsahuje dodatečné funkce pro kontrolu, které zpomalují běh a v provozu by neměly být. var useMinfiedPlugins = false; var concatFiles = [ // concat spojuje soubory v abecedním pořadí // Zde si prioritizuji nějaké soubory, a určím pro ně pevné pořadí '<%= wwwAssets %>/js/src/plugins/**/*.js', // Prvně vložíme všechny zkomilované JSX soubory až poté pluginy a další '<%= wwwAssets %>/js/src/_*._jsx.js', // soubory začínající _ mají přednost '<%= wwwAssets %>/js/src/stores/*._jsx.js', // Poté ze složky store '<%= wwwAssets %>/js/src/components/*._jsx.js', // Dále ze složky components '<%= wwwAssets %>/js/src/*._jsx.js', // Až poté všechny ostatní ve složce src končící na ._jsx.js '<%= wwwAssets %>/js/src/main._jsx.js', // Hlavní JSX soubor až poslední '<%= wwwAssets %>/js/src/*.js', // Pak všechny ostatní JS soubory, již vložené dříve se znova nevloží ]; if (useMinfiedPlugins || dist == true) { // Unshift vloží na začátek pole. React musí být vždy první // Druhý řádek, negace značí, že soubor react.js se vložit nesmí, protože se vkládá react.min.js concatFiles.unshift('<%= wwwAssets %>/js/src/plugins/react.min.js'); concatFiles.push('!<%= wwwAssets %>/js/src/plugins/react.js'); }else{ concatFiles.unshift('<%= wwwAssets %>/js/src/plugins/react.js'); concatFiles.push('!<%= wwwAssets %>/js/src/plugins/react.min.js'); } return concatFiles; } // Samotná konfigurace Gruntu grunt.initConfig({ wwwAssets: 'www', // Pouze proměnná, je použita mnohokrát níže // Task compass převede SASS s frameworkem Compass do CSS // Celý task má 2 cíle, dist a debug které můžou být spuštěny podle potřeby // Nastavení balíčků najdete vždy u každého z nich v dokumentaci compass: { dist: { options: { config: 'config.rb', sourcemap: true, force: true } }, debug: { options: { config: 'config.rb', sourcemap: false, outputStyle: 'expanded' } } }, // PostCSS je CSS postprocessor, obsahuje množství pluginů // Já zde použil pouze Autoprefixer postcss: { options: { // map: true, // inline sourcemaps processors: [ require('autoprefixer')({browsers: '>1%'}), // add vendor prefixes ] }, dist: { src: '<%= wwwAssets %>/css/styles.css', dest: '<%= wwwAssets %>/css/styles.css' } }, // Balíček pro sledování změn v souborech // pokud se specifikovaný soubor změní, spustí jednotlivé tasky watch: { sass: { files: '<%= wwwAssets %>/css/src/*.scss', tasks: ['compass:debug', 'postcss'] }, react: { // Jakýkoli soubor co má příponu JSX a nachází se ve složce www/js/jsx/ nebo libovolné podsložce files: '<%= wwwAssets %>/js/jsx/**/*.jsx', // Spustí task clean s cilem react, babel a target debug v tasku concat tasks: ['clean:react', 'babel', 'concat:debug'] }, js: { // Jakýkoli *.js soubor v www/js/src/, ale nesmi končit na *._jsx.js // Tento soubor může být změnen v targetu react a provedl by se zbytečně 2x files: ['<%= wwwAssets %>/js/src/*.js', '!<%= wwwAssets %>/js/src/*._jsx.js'], tasks: ['concat:debug'] } }, // Vymaže všechny soubory končící na ._jsx.js ve složce www/js/src/ a všech podsložkách clean: { react: ['<%= wwwAssets %>/js/src/**/*._jsx.js'] }, // Provede spojení daných souborů v 1 jediný concat: { options: { separator: '\n', process: function(src, filepath) { return '\n// Source: ' + filepath + '\n' + src; }, }, // target debug a dist, oba volají funkci definovanou nahoře která vrátí pole souborů, které spojit a v jakém pořadí debug: { src: this.getConcatArray(false), dest: '<%= wwwAssets %>/js/scripts.js' }, dist: { src: this.getConcatArray(true), dest: '<%= wwwAssets %>/js/scripts.js' } }, // Kompilace JSX syntaxe a ES2015 do běžného JavaScriptu babel: { // https://php.quicoto.com/use-babel-to-compile-react-jsx-with-grunt/ options: { presets: ['stage-0', 'es2015', 'react'] }, jsx: { files: [{ // Zde se soubory ve složce www/js/jsx/ a podsložek přeloží a // uloží do složky www/js/src/ ale složky zůstanou zachovány // Příklad: www/js/jsx/main.jsx -> www/js/src/main._jsx.js // Nebo: www/js/jsx/stores/articles.jsx -> www/js/src/stores/articles._jsx.js expand: true, cwd: '<%= wwwAssets %>/js/jsx/', src: ['**/*.jsx'], dest: '<%= wwwAssets %>/js/src/', ext: '._jsx.js' }] } }, // Task který kontroluje soubory a pokud se změní, provede refresh prohlížeče browserSync: { dev: { // Které soubory sledovat, chci pouze výsledné, které se uloží až // Compass zkompiluje SASS soubory do finálního CSS // Babel a Concat přeloží a spojí všechny JS soubory bsFiles: { src : [ '<%= wwwAssets %>/css/styles.css', '<%= wwwAssets %>/js/scripts.js' ] }, options: { // Můj server běží na této adrese // browserSync dokáže i server vytvořit a servírovat HTML soubory proxy: 'https://localhost:1443', watchTask: true } } }, // Run slouží ke spuštění příkazů jako v příkazové řádce // Server se kompiluje a spustí pomocí Makefile a task run spustí tento soubor // Až se v příkazové řádce objeví "./blog" tak se tváří jako vyřízený a pokračují další tasky run: { options: { ready: new RegExp("\./blog"), wait: false, }, GoServer: { cmd: 'make', args: [ 'run' ] } } }); // Musíme načíst jednotlivé balíčky, které chceme používat grunt.loadNpmTasks('grunt-contrib-compass'); grunt.loadNpmTasks('grunt-babel'); grunt.loadNpmTasks('grunt-postcss'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-browser-sync'); grunt.loadNpmTasks('grunt-run'); // Registrujeme vlastní tasky a specifikujeme, co daný task zastupuje // Můžete si všimnout, že tasky se dají skládat, default task spustí také můj task build-debug // Každý task se spustí jako task:target, přičem záleží na balíčku co udělají, pokud target není specifikovaný // Některý spustí pouze 1, některé jako watch všechny grunt.registerTask('default', ['build-debug', 'run', 'browserSync', 'watch']); grunt.registerTask('build', ['clean', 'compass:dist', 'postcss', 'babel', 'concat:dist']); grunt.registerTask('build-debug', ['clean', 'compass:debug', 'postcss', 'babel', 'concat:debug']); };
Nyní můžeme pomocí příkazů spouštět jednotlivé tasky ať už vlastní, nebo definované. Pokud však žádný neuvedeme, spustí se default. V případě Gruntu je potřeba se přepnout pomocí příkazu cd do složky daného projektu.
# Spustí default task grunt # Spustí build-debug, což zahrnuje clean, compass:debug, postcss... grunt build-debug # Spustí pouze task clean grunt clean
K tomuto článku již není možné přidávat další komentáře
Komentáře
Zdravím a děkuji za dobře napsaný článek. S gruntem se teprve seznamuji a každá ukázka použití se hodí :)