Jak se vypořádat s LESS soubory ve Visual Studiu 2015

Tomáš Herceg       12.05.2015       Visual Studio, HTTP/HTML, JavaScript       12775 zobrazení

Pokud jste si nainstalovali nové Visual Studio 2015 a nezbytný balíček Web Essentials, jistě jste si všimli, že některé funkce, které ve VS 2013 fungovaly, najednou zmizely. Mimo jiné se jedná o automatickou kompilaci LESS souborů.

Když člověk ve Visual Studiu 2013 přidal do projektu LESS soubor a něco do něj napsal, Web Essentials automaticky vygenerovaly zkompilované CSSko. Kromě toho se LESSka kompilovala i při buildu, což bylo výhodné ve chvíli, kdy člověk pracuje v týmu a stáhne si změny od někoho jiného. V LESS souborech mohou být namergeovány úpravy obou lidí a bylo tedy vhodné, aby se při kompilaci přegenerovaly i CSS soubory. Web Essentials byly navíc celkem snadno konfigurovatelné a tato konfigurace se dala vložit i do projektu tak, aby se dostala ke všem členům týmu – všem se to poté chovalo stejně. Až potud to bylo bezvadné.

Potíž nastává u větších projektů, kde chcete třeba používat kontinuální integraci nebo projekt kompilovat a nasazovat z příkazového řádku, zkrátka určité úkoly automatizovat. Web Essentials jsou jen plugin do Visual Studia a funkce, které dělají, nedokáží dělat v rámci MSBuildu jako takového.

Navíc ve chvíli, kdy potřebujete udělat něco složitějšího, než jen vzít všechny LESS soubory z projektu a zkompilovat je do CSS, nastává problém, protože Web Essentials to nepodporují a upravit si celý ten proces snadno také nemůžete. Takových situací může být překvapivě mnoho – stačí, když potřebujete po zkompilování CSS vytvořit bundle. Nebo když chcete při buildu nad CSS soubory pustit nějaký analyzátor. Anebo když třeba do projektu nainstalujete balíček Bootstrap Less Source, což je stádo LESS souborů, které není potřeba kompilovat, protože se všechny navzájem includují a používají se tak, že vezmete bootstrap.less, naincludujete jej do svého LESS souboru a na tom pak stavíte. Kompilovat chcete jen to vaše LESSko a ne ta bootstrapová, protože ta házejí chyby, pokud se kompilují samostatně a nejsou za sebou zapojeny ve správném pořadí.

Visual Studio 2015 proto od tohoto jednoduchého, ale necustomizovatelného přístupu upustilo, a nabízí možnost, která je jen o trochu pracnější, zato poskytuje mnohem více flexibility. Pokud chcete přesně to, co dělaly Web Essentials, stačí nakopírovat pár souborů, které můžete mít někde předpřipravené, nebo se to dá snadno řešit třeba pomocí vlastního NuGet balíčku. Pokud však chcete cokoliv více, máte možnost si to upravit k obrazu svému.

 

Grunt a Bower

Tato dvojice technologií zajišťuje výše popsaný proces. Jsou to nástroje, které se používají i v nedotnetovém světě, a existuje kolem nich dost velká komunita, což má mnoho výhod – tou hlavní je, že když se objeví nějaká nová feature v LESSu, máte ji hned k dispozici a nemusíte čekat na Microsoft, až ji zaintegruje do Visual Studia (i když Web Essentials byly updatovány celkem často). Nicméně můžete používat mnohem více nástrojů než jen ty, co se do Web Essentials dostanou.

Bower

Bower je balíčkovací systém podobný NuGetu, specializuje se ale na klientské skripty. NuGet sice dnes obsahuje nejběžnější javascriptové knihovny jako jQuery nebo Bootstrap, nicméně většina autorů mimo svět Microsoftu na tvorbu balíčků pro NuGet kašle (anebo o NuGetu ani neví). A tak ve chvíli, kdy potřebujete třeba nějaký plugin do jQuery nebo libovolnou méně obvyklou knihovnu, na NuGetu jej většinou nenajdete, zatímco na Boweru ano.

Neznamená to, že NuGet na javascriptové záležitosti nesmíte používat, ale doporučuje se NuGet používat na serverové .NETové knihovny, na které byl konec konců vymyšlen, a Bower na klientské závislosti.

 

Grunt

Grunt je task runnerů. Nasypete do něj konfigurační soubor, kde nakonfigurujete různé tasky, a pak mu řeknete, které z nich má spustit. Není na tom nic světoborného, nicméně je to praktičtější než automatizovat procesy přes příkazový řádek, a existuje do toho celá řada modulů, které stačí jen nainstalovat a použít.

Alternativou ke Gruntu je Gulp, což je něco podobného, akorát s jinou syntaxí. Visual Studio jej podporuje také, takže si můžete vybrat.

Jak to použít?

Pokud používáte novou ASP.NET 5 aplikaci, pak následující krok můžete vynechat, protože nová šablona už s Gruntem a Bowerem počítá. V případě, že běžíte na starším .NETu (4.6 nebo nižší), je nutné použít novou položku, kterou do Visual Studia přidají Web Essentials.

Přidání Gruntu a Boweru do projektu

Tato akce do projektu přidá několik souborů, o kterých si nyní povíme.

 

Package.json

První z nich je package.json, která obsahuje konfiguraci pro NPM (Node Package Manager). Ten se stará o stahování balíčků, které budou provádět operace během vývoje – např. již zmíněnou kompilaci LESSu. Tento soubor obsahuje sekci devDependencies, do níž vypíšeme všechny balíčky, které chceme používat v rámci buildu ve Visual Studiu.

{
  "name": "package",
  "version": "1.0.0",
  "private": true,
  "devDependencies": {
    "grunt": "0.4.5",
    "grunt-bower-task": "0.4.0",
    "grunt-contrib-less": "1.0.1",
    "grunt-contrib-watch": "0.6.1"
  }
}

Jakmile soubor uložíte, Visual Studio na pozadí požadované balíčky stáhne. Ve vzorovém souboru máme 4 balíčky.

  • grunt je task runner, který vezme soubor gruntfile.js a spustí tasky, které jsou v něm definované. Budeme si o něm povídat dále.
  • grunt-bower-task je task, který spustí bower. Ten zkontroluje, jestli jsou staženy všechny balíčky, a pokud ne, tak je stáhne.
  • grunt-contrib-less je task, který je zodpovědný za kompilaci LESSu do CSS.
  • grunt-contrib-watch je task, který sleduje určité soubory na disku a ve chvíli, kdy se změní, umožňuje spustit nějakou akci. Tím docílíme toho, že ihned jakmile LESS změníme a uložíme, vygeneruje se CSS.

V případě, že byste chtěli balíčky updatovat, Visual Studio pro to má kontextovou akci.

image

 

Bower.json

Druhý z přidaných souborů je bower.json, který obsahuje konfiguraci Boweru. V sekci dependencies určíte, které knihovny chcete, a bower je sám stáhne. Bower standardně funguje tak, že je nasměrován na celý repozitář dané knihovny a stáhne ho na disk celý (včetně nápovědy, testů atd.). Z toho pak umí vykopírovat určité soubory (tzv. exporty) a umístí je do námi zvoleného adresáře, který se includuje do projektu. Web Essentials v bower.json přidávají ještě sekci exportsOverride, která se používá v případě, že chcete z balíčků vytáhnout i jiné soubory, než ty, co Bower vykopírovává standardně. Pro jednoduché scénáře však tato sekce není potřeba.

Přidali jsme balíček jQuery. IntelliSense nám sama nabízí poslední dostupnou verzi.

{
  "name": "bower",
  "license": "Apache-2.0",
  "private": true,
  "dependencies": {
    "jquery": "2.1.4"
  }
}

 

Gruntfile.js

Posledním přidaným souborem je gruntfile. Tento soubor definuje úkoly, které se spustí v nějaké fázi – například při otevření projektu, po skončení kompilace atd.

/// <binding AfterBuild='default' ProjectOpened='watch' />
module.exports = function (grunt) {
    grunt.initConfig({
        bower: {
            install: {
                options: {
                    targetDir: "Scripts",
                    layout: "byComponent",
                    cleanTargetDir: false
                }
            }
        },
        less: {
            dev: {
                files: [{
                    src: ['Content/*.less'],
                    expand: true,
                    rename: function (dest, src) { return dest + src.replace('.less', '.css') },
                    dest: ''
                }]
            }    
        },
        watch: {
            less: {
                files: "Content/*.less",
                tasks: ["less"]
            }
        }
    });

    grunt.registerTask("default", ["bower:install", "less:dev"]);
    grunt.loadNpmTasks("grunt-bower-task");
    grunt.loadNpmTasks("grunt-contrib-less");
    grunt.loadNpmTasks("grunt-contrib-watch");
};

Tento soubor říká následující – v sekci grunt.initConfig jsou konfigurace jednotlivých úkolů:

  • bower – tento task ověří, zda-li jsou staženy všechny bowerové balíčky, a pokud ne, tak je stáhne. To je důležité, protože pokud se na projektu pracuje v týmu a někdo přidá balíček, ostatním se musí nejpozději během kompilace stáhnout.
    V nastavení tasku je mimo jiné definováno, že exporty z boweru budou umístěny v adresáři Scripts.
  • less – tento task kompiluje LESS soubory. Je nastaven tak, že zkompiluje všechny *.less soubory v adresáři Content. Funkce rename pak definuje, jak se má jmenovat výsledný soubor.
  • watch – tento task bude sledovat všechny soubory *.less v adresáři Content a v případě, že se libovolný z nich změní, spustí pro něj task less.

Pod konfigurací je registrace tasku, který se jmenuje default, a který budeme spouštět při kompilaci – ten stáhne bower balíčky a následně spustí less.

Každý task v gruntu může mít několik targetů, které se definují v první úrovni. Task bower má target install, task less má target dev atd.

V praxi by člověk u LESSu ještě target production, který by výstupní soubor navíc minifikoval. Při nasazování (např. na integračním serveru) řekneme, že se má spouštět task, který se odkáže na produkční target a ne na ten vývojářský.

A dole pod tím jsou klauzule, které načtou tasky z daných modulů specifikovaných v package.json.

Úplně nahoře v souboru je pak XML komentář, který Visual Studiu říká, že task default se má spustit po každé kompilaci, a task watch se má spustit hned při otevření projektu.

 

Ve Visual Studiu 2015 je nově okno Task Runner Explorer, kde vidíte načtený gruntfile.js a můžete ručně spouštět tasky.

image

Vidíme, že mi tam běží task watch a sleduje, jestli se nezměnily některé soubory.

 

Konfiguraci si musí každý upravit sám, protože každý má trochu jiné konvence, kam dává knihovny, kam dává LESS soubory atd. Nicméně ve chvíli, kdy se dostanete do nějakého ideálního stavu, můžete si vytvořit projektovou šablonu nebo NuGet balíček, který vám tyto tři soubory do projektu nainstaluje.

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

 

 

Nový příspěvek

 

Příspěvky zaslané pod tento článek se neobjeví hned, ale až po schválení administrátorem.

Gulp

Pro ty co radši používají Gulp namísto Grunt, přikládám jak to samé (Less, Watch) řešit v něm.

package.json:

{
  "name": "package",
  "version": "1.0.0",
  "private": true,
  "devDependencies": {
    "gulp": "3.8.11",
    "gulp-less": "3.0.3",
    "rimraf": "2.3.3"
  }
}

gulpfile.js:

/// <binding AfterBuild='copy, less' Clean='clean' ProjectOpened='watch' />

// Import required components
var gulp = require("gulp");
var less = require("gulp-less");
var rimraf = require("rimraf");
var fs = require("fs");

// Read project file
eval("var project = " + fs.readFileSync("./project.json"));

// Setup paths
var paths = {
    bower: "./bower_components/",
    lib: "./" + project.webroot + "/Scripts/lib/",
    content: "./" + project.webroot + "/Content",
};

// Remove copied files
gulp.task("clean", function (cb) {
    rimraf(paths.lib, cb);
});

// Copy libraries
gulp.task("copy", ["clean"], function () {
    var bower = {
        "jquery": "jquery/jquery*.{js,map}"
    };
    for (var destinationDir in bower) {
        gulp.src(paths.bower + bower[destinationDir])
          .pipe(gulp.dest(paths.lib + destinationDir));
    };
});

// Compile and copy less files
gulp.task("less", function () {
    gulp.src("./Content/site.less")
        .pipe(less())
        .pipe(gulp.dest(paths.content));
});

// Watch for less files change
gulp.task("watch", function () {
    gulp.watch("./Content/**", ["less"]);
});
nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

Příspěvky zaslané pod tento článek se neobjeví hned, ale až po schválení administrátorem.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback