Niech Grunt wygeneruje plik index.html dla różnych konfiguracji

208

Próbuję użyć Grunta jako narzędzia do kompilacji mojej aplikacji internetowej.

Chcę mieć co najmniej dwie konfiguracje:

I. Konfiguracja programistyczna - ładuj skrypty z oddzielnych plików, bez konkatenacji,

więc mój index.html wyglądałby mniej więcej tak:

<!DOCTYPE html>
<html>
    <head>
        <script src="js/module1.js" />
        <script src="js/module2.js" />
        <script src="js/module3.js" />
        ...
    </head>
    <body></body>
</html>

II. Konfiguracja produkcji - załaduj moje skrypty zminimalizowane i połączone w jednym pliku,

odpowiednio z index.html:

<!DOCTYPE html>
<html>
    <head>
        <script src="js/MyApp-all.min.js" />
    </head>
    <body></body>
</html>

Pytanie brzmi: w jaki sposób mogę zmusić chrząka, aby te index.html zależały od konfiguracji podczas uruchamiania grunt devlub grunt prod?

A może kopie w złym kierunku i łatwiej byłoby zawsze wygenerować, MyApp-all.min.jsale umieścić w nim wszystkie moje skrypty (połączone) lub skrypt ładujący, który asynchronicznie ładuje te skrypty z osobnych plików?

Jak to robicie chłopaki?

Dmitrij Paszkiewicz
źródło
3
Wypróbuj narzędzie Yeoman, które obejmuje zadanie „usemin”, które robi to, co Ty. Ponadto generatory Yeamon zawierają wiele „dobrych praktyk” łatwych do nauczenia, których trudno się nauczyć przy użyciu nowego narzędzia.
EricSonaron,

Odpowiedzi:

161

Niedawno odkryłem te v0.4.0zadania kompatybilne z Grunt :

  • pomruk wstępny

    Zadanie Grunt wokół modułu wstępnego przetwarzania npm.

  • grunt-env

    Zadanie Grunt automatyzujące konfigurację środowiska dla przyszłych zadań.

Poniżej znajdują się moje fragmenty Gruntfile.js .

Konfiguracja ENV:

env : {

    options : {

        /* Shared Options Hash */
        //globalOption : 'foo'

    },

    dev: {

        NODE_ENV : 'DEVELOPMENT'

    },

    prod : {

        NODE_ENV : 'PRODUCTION'

    }

},

Proces wstępny:

preprocess : {

    dev : {

        src : './src/tmpl/index.html',
        dest : './dev/index.html'

    },

    prod : {

        src : './src/tmpl/index.html',
        dest : '../<%= pkg.version %>/<%= now %>/<%= ver %>/index.html',
        options : {

            context : {
                name : '<%= pkg.name %>',
                version : '<%= pkg.version %>',
                now : '<%= now %>',
                ver : '<%= ver %>'
            }

        }

    }

}

Zadania:

grunt.registerTask('default', ['jshint']);

grunt.registerTask('dev', ['jshint', 'env:dev', 'clean:dev', 'preprocess:dev']);

grunt.registerTask('prod', ['jshint', 'env:prod', 'clean:prod', 'uglify:prod', 'cssmin:prod', 'copy:prod', 'preprocess:prod']);

I w /src/tmpl/index.htmlpliku szablonu (na przykład):

<!-- @if NODE_ENV == 'DEVELOPMENT' -->

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script>
    <script src="../src/js/foo1.js"></script>
    <script src="../src/js/foo2.js"></script>
    <script src="../src/js/jquery.blah.js"></script>
    <script src="../src/js/jquery.billy.js"></script>
    <script src="../src/js/jquery.jenkins.js"></script>

<!-- @endif -->

<!-- @if NODE_ENV == 'PRODUCTION' -->

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

    <script src="http://cdn.foo.com/<!-- @echo name -->/<!-- @echo version -->/<!-- @echo now -->/<!-- @echo ver -->/js/<!-- @echo name -->.min.js"></script>

<!-- @endif -->

Jestem pewien, że moja konfiguracja różni się od większości ludzi, a przydatność powyższego zależy od twojej sytuacji. Dla mnie, mimo że jest to niesamowity kawałek kodu, Yeoman pomruk-usemin jest bardziej niezawodny niż osobiście potrzebuję.

UWAGA: I właśnie odkrył wyżej wymienione zadania dzisiaj, więc może brakować funkcji i / lub mój proces może ulec zmianie w dół drogi. Póki co, uwielbiam prostotę i funkcje, które mają do zaoferowania funkcje pre-procesowe i en-gruntowe . :)


Aktualizacja z stycznia 2014 r .:

Motywowany głosowaniem w dół ...

Kiedy opublikowałem tę odpowiedź, nie było wielu opcji dla Grunta, 0.4.xktóre oferowały rozwiązanie, które działało na moje potrzeby. Teraz, miesiące później, zgaduję, że jest więcej opcji, które mogłyby być lepsze niż to, co tutaj zamieściłem. Chociaż nadal osobiście używam i lubię korzystać z tej techniki w moich kompilacjach , proszę przyszłych czytelników o przeczytanie innych udzielonych odpowiedzi i zbadanie wszystkich opcji. Jeśli znajdziesz lepsze rozwiązanie, opublikuj swoją odpowiedź tutaj.

Aktualizacja z lutego 2014 r .:

Nie jestem pewien, czy przyniesie to jakąkolwiek pomoc, ale utworzyłem to repozytorium demonstracyjne na GitHub, które pokazuje pełną (i bardziej złożoną konfigurację) przy użyciu technik opisanych powyżej.

mhulse
źródło
Dzięki, sprawdzę to!
Dmitrij Paszkiewicz
3
Twoje rozwiązanie pozwoliło mi zaoszczędzić godziny uderzania głową w ścianę. Dzięki.
sthomps
1
@sthomps Cieszę się, że pomogło! Odkąd odkryłem te zadania, uwielbiałem przepływ pracy. Do twojej wiadomości, dokonałem jednej drobnej zmiany w procesie ... Zamiast przekazywać kilka zmiennych kontekstowych do moich szablonów HTML, zdecydowałem się przekazać jedną path : '/<%= pkg.name %>/dist/<%= pkg.version %>/<%= now %>/<%= ver %>'zmienną, która łączy wszystkie zmienne (to moja ścieżka kompilacji). Na moim szablonu będę mieć: <script src="http://cdn.foo.com<!-- @echo path -->/js/bulldog.min.js"></script>. W każdym razie cieszę się, że mogłem zaoszczędzić trochę czasu! : D
mhulse
4
Możesz zrobić to samo, używając tylko szablonu-pomruku , po prostu przekazując inny dataobiekt dla dev / prod.
Mathias Bynens
2
Człowieku, uwielbiam to rozwiązanie. Jest czyste, czytelne i niezbyt dopracowane.
Gaurang Patel,
34

Wymyśliłem własne rozwiązanie. Jeszcze nie dopracowane, ale myślę, że pójdę w tym kierunku.

W skrócie, używam grunt.template.process () do generowania mojego index.htmlz szablonu, który analizuje bieżącą konfigurację i tworzy albo listę moich oryginalnych plików źródłowych, albo łącza do pojedynczego pliku ze zminimalizowanym kodem. Poniższy przykład dotyczy plików js, ale to samo podejście można rozszerzyć na css i inne możliwe pliki tekstowe.

grunt.js:

/*global module:false*/
module.exports = function(grunt) {
    var   // js files
        jsFiles = [
              'src/module1.js',
              'src/module2.js',
              'src/module3.js',
              'src/awesome.js'
            ];

    // Import custom tasks (see index task below)
    grunt.loadTasks( "build/tasks" );

    // Project configuration.
    grunt.initConfig({
      pkg: '<json:package.json>',
      meta: {
        banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
          '<%= grunt.template.today("yyyy-mm-dd") %> */'
      },

      jsFiles: jsFiles,

      // file name for concatenated js
      concatJsFile: '<%= pkg.name %>-all.js',

      // file name for concatenated & minified js
      concatJsMinFile: '<%= pkg.name %>-all.min.js',

      concat: {
        dist: {
            src: ['<banner:meta.banner>'].concat(jsFiles),
            dest: 'dist/<%= concatJsFile %>'
        }
      },
      min: {
        dist: {
        src: ['<banner:meta.banner>', '<config:concat.dist.dest>'],
        dest: 'dist/<%= concatJsMinFile %>'
        }
      },
      lint: {
        files: ['grunt.js'].concat(jsFiles)
      },
      // options for index.html builder task
      index: {
        src: 'index.tmpl',  // source template file
        dest: 'index.html'  // destination file (usually index.html)
      }
    });


    // Development setup
    grunt.registerTask('dev', 'Development build', function() {
        // set some global flags that all tasks can access
        grunt.config('isDebug', true);
        grunt.config('isConcat', false);
        grunt.config('isMin', false);

        // run tasks
        grunt.task.run('lint index');
    });

    // Production setup
    grunt.registerTask('prod', 'Production build', function() {
        // set some global flags that all tasks can access
        grunt.config('isDebug', false);
        grunt.config('isConcat', true);
        grunt.config('isMin', true);

        // run tasks
        grunt.task.run('lint concat min index');
    });

    // Default task
    grunt.registerTask('default', 'dev');
};

index.js (the index task):

module.exports = function( grunt ) {
    grunt.registerTask( "index", "Generate index.html depending on configuration", function() {
        var conf = grunt.config('index'),
            tmpl = grunt.file.read(conf.src);

        grunt.file.write(conf.dest, grunt.template.process(tmpl));

        grunt.log.writeln('Generated \'' + conf.dest + '\' from \'' + conf.src + '\'');
    });
}

Wreszcie, index.tmplz logiką generacji wypaloną:

<doctype html>
<head>
<%
    var jsFiles = grunt.config('jsFiles'),
        isConcat = grunt.config('isConcat');

    if(isConcat) {
        print('<script type="text/javascript" src="' + grunt.config('concat.dist.dest') + '"></script>\n');
    } else {
        for(var i = 0, len = jsFiles.length; i < len; i++) {
            print('<script type="text/javascript" src="' + jsFiles[i] + '"></script>\n');
        }
    }
%>
</head>
<html>
</html>

UPD. Okazało się, że Yeoman , oparty na chrząstce, ma wbudowane zadanie usemin, które integruje się z systemem kompilacji Yeoman. Generuje wersję produkcyjną pliku index.html na podstawie informacji w wersji rozwojowej pliku index.html, a także innych ustawień środowiska. Trochę wyrafinowany, ale interesujący.

Dmitrij Paszkiewicz
źródło
5
pomruk-szablon jest bardzo lekkim opakowaniemgrunt.template.process()(którego tu używasz), który uczyniłby to jeszcze łatwiejszym. Możesz zrobić to samo, używając szablonu-gruntu , po prostu przekazując innydataobiekt dla dev / prod.
Mathias Bynens
15

Nie podoba mi się tutaj rozwiązania (w tym te, które wcześniej podałem ) i oto dlaczego:

  • Problem z najwyższą głosowaną odpowiedzią polega na tym, że musisz ręcznie zsynchronizować listę znaczników skryptu podczas dodawania / zmiany nazwy / usuwania pliku JS.
  • Problem z zaakceptowaną odpowiedzią polega na tym, że na liście plików JS nie można dopasować wzorca. Oznacza to, że musisz zaktualizować go ręcznie w Gruntfile.

Zrozumiałem, jak rozwiązać oba te problemy. Skonfigurowałem moje zadanie karczowania, aby za każdym razem, gdy plik był dodawany lub usuwany, tagi skryptów były automatycznie generowane, aby to odzwierciedlić. W ten sposób nie musisz modyfikować pliku html ani chrząkać podczas dodawania / usuwania / zmiany nazw plików JS.

Podsumowując, jak to działa, mam szablon HTML ze zmienną dla znaczników skryptu. Korzystam z https://github.com/alanshaw/grunt-include-replace do wypełnienia tej zmiennej. W trybie deweloperskim ta zmienna pochodzi ze wzoru globowania wszystkich moich plików JS. Zadanie oglądania ponownie oblicza tę wartość, gdy plik JS jest dodawany lub usuwany.

Teraz, aby uzyskać różne wyniki w trybie deweloperskim lub produkcyjnym, wystarczy wypełnić tę zmienną inną wartością. Oto kod:

var jsSrcFileArray = [
    'src/main/scripts/app/js/Constants.js',
    'src/main/scripts/app/js/Random.js',
    'src/main/scripts/app/js/Vector.js',
    'src/main/scripts/app/js/scripts.js',
    'src/main/scripts/app/js/StatsData.js',
    'src/main/scripts/app/js/Dialog.js',
    'src/main/scripts/app/**/*.js',
    '!src/main/scripts/app/js/AuditingReport.js'
];

var jsScriptTags = function (srcPattern, destPath) {
    if (srcPattern === undefined) {
        throw new Error("srcPattern undefined");
    }
    if (destPath === undefined) {
        throw new Error("destPath undefined");
    }
    return grunt.util._.reduce(
        grunt.file.expandMapping(srcPattern, destPath, {
            filter: 'isFile',
            flatten: true,
            expand: true,
            cwd: '.'
        }),
        function (sum, file) {
            return sum + '\n<script src="' + file.dest + '" type="text/javascript"></script>';
        },
        ''
    );
};

...

grunt.initConfig({

    includereplace: {
        dev: {
            options: {
                globals: {
                    scriptsTags: '<%= jsScriptTags(jsSrcFileArray, "../../main/scripts/app/js")%>'
                }
            },
            src: [
                'src/**/html-template.html'
            ],
            dest: 'src/main/generated/',
            flatten: true,
            cwd: '.',
            expand: true
        },
        prod: {
            options: {
                globals: {
                    scriptsTags: '<script src="app.min.js" type="text/javascript"></script>'
                }
            },
            src: [
                'src/**/html-template.html'
            ],
            dest: 'src/main/generatedprod/',
            flatten: true,
            cwd: '.',
            expand: true
        }

...

    jsScriptTags: jsScriptTags

jsSrcFileArrayto Twój typowy wzorzec globowania plików. jsScriptTagspobiera jsSrcFileArrayi łączy je razem z scripttagami po obu stronach. destPathto prefiks, który chcę w każdym pliku.

A oto jak wygląda HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Example</title>

</head>

<body>    
@@scriptsTags
</body>
</html>

Teraz, jak widać w konfiguracji, generuję wartość tej zmiennej jako scripttag zakodowany na stałe, gdy jest ona uruchomiona w prodtrybie. W trybie deweloperskim zmienna ta rozwija się do wartości takiej jak ta:

<script src="../../main/scripts/app/js/Constants.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/Random.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/Vector.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/StatsData.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/Dialog.js" type="text/javascript"></script>

Daj mi znać, jeśli masz jakieś pytania.

PS: To szalona ilość kodu do czegoś, co chciałbym zrobić w każdej aplikacji JS po stronie klienta. Mam nadzieję, że ktoś może to zmienić we wtyczkę wielokrotnego użytku. Może kiedyś to zrobię.

Daniel Kaplan
źródło
1
Brzmi obiecująco. Czy jest jakaś szansa, że ​​możesz podzielić się krótkimi fragmentami?
Adam Marshall
I've set up my grunt task so that every time a file is added or deleted, the script tags automatically get generated to reflect thatJak to zrobiłeś?
CodyBugstein
2
Kolejne pytanie: Czy znasz sposób na usunięcie bloków <script>tagów HTML ?
CodyBugstein
@Nie pomaluj mnie z czubka głowy. Masz na myśli bez jakiejkolwiek formy szablonów (np. Pomruk-włącz-zamień)? Pierwszą myślą, która pojawia się w mojej głowie, byłoby xslt. Prawdopodobnie nie jest to dobre rozwiązanie.
Daniel Kaplan
1
Ta odpowiedź jest na miejscu, chociaż ja osobiście usunięty destPathz jsScriptTagsi zamieniłem grunt.file.expandMappingz grunt.file.expandjak pliki chciałem były już w odpowiednich miejscach. To bardzo uprościło sprawy. Dziękuję @DanielKaplan, zaoszczędziłeś mi ogromnie dużo czasu :)
DanielM
13

Od dłuższego czasu zadaję sobie to samo pytanie i myślę, że ta wtyczka może być skonfigurowana do robienia tego, co chcesz: https://npmjs.org/package/grunt-targethtml . Implementuje warunkowe tagi HTML, które zależą od celu chrząknięcia.

Per Quested Aronsson
źródło
2
Widziałem tę wtyczkę, ale nie podoba mi się pomysł ręcznego określania wszystkich plików (i faktycznej logiki) w moim pliku index.html, ponieważ mam już listę źródłowych plików js / css w mojej konfiguracji i nie chcę się powtórzyć. Najważniejsze jest to, że
Dmitrij Paszkiewicz w dniu
+1 dla grunt-targethtml. Chociaż dodawanie instrukcji „decydujących” w pliku index.html jest trochę brzydkie, które zasoby należy załadować. Nadal ma to sens. Jest to miejsce, w którym zwykle będziesz chciał uwzględnić zasoby w swoim projekcie. Również śledzenie tego doprowadziło mnie do sprawdzenia chrząknięcia. Ma w sobie świetne rzeczy.
carbontax,
8

Szukałem prostszego, prostszego rozwiązania, więc połączyłem odpowiedź z tego pytania:

Jak umieścić, jeśli inaczej blok w gruntfile.js

i wymyślił następujące proste kroki:

  1. Zachowaj dwie wersje plików indeksu na liście i nazwij je index-development.html i index-prodoction.html.
  2. Użyj poniższej logiki w bloku concat / copy swojego pliku Gruntfile.js dla pliku index.html:

    concat: {
        index: {
            src : [ (function() {
                if (grunt.option('Release')) {
                  return 'views/index-production.html';
                } else {
                  return 'views/index-development.html';
                }
              }()) ],
           dest: '<%= distdir %>/index.html',
           ...
        },
        ...
    },
  3. uruchom „grunt --Release”, aby wybrać plik index-production.html i pozostaw flagę, aby mieć wersję programistyczną.

Brak nowych wtyczek do dodania lub skonfigurowania oraz brak nowych zadań chrząknięcia.

Edward Tan
źródło
3
Jedynym minusem jest to, że istnieją dwa pliki index.html do utrzymania.
Adam Marshall
5

To chrząknięcie o nazwie scriptlinker wygląda na łatwy sposób dodawania skryptów w trybie programistycznym. Prawdopodobnie możesz najpierw uruchomić zadanie konkat, a następnie skierować je do pliku konkatenowanego w trybie prod.

Daniel Kaplan
źródło
+1. Dokumentacja jest myląca, a niektóre rzeczy (appRoot, krewny) nie zawsze działają zgodnie z przeznaczeniem, ale nadal: pomocne narzędzie.
hashchange
1
@hashchange Nie używam tego narzędzia. Skończyło się na użyciu github.com/alanshaw/grunt-include-replace . Mam zmienną w moim pliku HTML reprezentują tagi skryptu. Następnie zapełniam tę zmienną ciągiem HTML, który chcę. W trybie deweloperskim ta zmienna jest listą skryptów. W trybie prod ta zmienna jest połączoną, zminimalizowaną wersją.
Daniel Kaplan
Dzięki za wskaźnik do pomrukowania-włącz-zamień. (Właściwie potrzebowałem narzędzia do dodawania wszystkich plików specyfikacji w katalogu do pliku index.html Mocha. Scriptlinker jest w porządku.)
hashchange
@hashchange masz rację na temat wysysania dokumentacji. Jak to powiedzieć, gdzie umieścić kafelki skryptu w pliku HTML?
Daniel Kaplan
1
Definiujesz komentarz HTML. Spójrz na ten plik . Wstawienia mają miejsce o <!--SINON COMPONENT SCRIPTS-->i <!--SPEC SCRIPTS-->. A oto zadanie Grunt, które to robi (faktycznie działające, w przeciwieństwie do tego, co jest w dokumentach). Mam nadzieję, że to pomaga;)
hashchange
5

grunt-dom-munger czyta HTML i manipuluje nim za pomocą selektorów CSS. Dawny. odczytaj tagi z html. Usuń węzły, dodaj węzły i nie tylko.

Możesz użyć grunt-dom-munger, aby odczytać wszystkie pliki JS, które są połączone przez twój index.html, uglifikować je, a następnie użyć ponownie grunt-dom-munger, aby zmodyfikować index.html, aby połączyć tylko zminimalizowany JS

brillout
źródło
5

Znalazłem wtyczkę chrząka o nazwie chrobot-dev-prod-switch. Jedyne, co robi, to komentowanie pewnych bloków, których szuka, na podstawie opcji --env, którą przekazujesz do chrząknięcia (chociaż ogranicza cię to do tworzenia, dźgania i testowania).

Po ustawieniu go jako wyjaśnia tutaj , można uruchomić na przykład:

grunt serve --env=dev, a wszystko to komentuje bloki, które są owinięte

    <!-- env:test/prod -->
    your code here
    <!-- env:test/prod:end -->

i odkomentuje bloki, które są owinięte

    <!-- env:dev -->
    your code here
    <!-- env:dev:end -->

Działa również na javascript, używam go do ustawiania właściwego adresu IP do połączenia z moim interfejsem API. Bloki po prostu zmieniają się na

    /* env:dev */
    your code here
    /* env:dev:end */

W twoim przypadku byłoby to tak proste:

<!DOCTYPE html>
<html>
    <head>
        <!-- env:dev -->
        <script src="js/module1.js" />
        <script src="js/module2.js" />
        <script src="js/module3.js" />
        ...
        <!-- env:dev:end -->
        <!-- env:prod -->
        <script src="js/MyApp-all.min.js" />
        ...
        <!-- env:prod:end -->
    </head>
    <body></body>
</html>
anonimowy
źródło
4

chrząknięcie to fantastyczny skrypt, który świetnie się tu sprawdzi. Używam go w moim skrypcie automatycznego budowania JQM.

https://github.com/imaginethepoet/autojqmphonegap

Spójrz na mój plik grunt.coffee:

bake:
    resources: 
      files: "index.html":"resources/custom/components/base.html"

Spogląda na wszystkie pliki w pliku base.html i zasysa je, aby utworzyć plik index.html. Działa fantastycznie w aplikacjach wielostronicowych (phonegap). Pozwala to na łatwiejszy rozwój, ponieważ wszyscy deweloperzy nie pracują na jednej długiej, jednostronicowej aplikacji (zapobiegając wielu kontrolom konfliktów). Zamiast tego możesz podzielić strony i pracować na mniejszych fragmentach kodu i skompilować do pełnej strony za pomocą polecenia watch.

Bake czyta szablon z base.html i wstrzykuje strony HTML komponentu do zegarka.

<!DOCTYPE html>

jQuery Mobile Demos

app.initialize ();

<body>
    <!--(bake /resources/custom/components/page1.html)-->
    <!--(bake /resources/custom/components/page2.html)-->
    <!--(bake /resources/custom/components/page3.html)-->
</body>

Możesz pójść o krok dalej i dodać zastrzyki na swoich stronach do wyskakujących okienek „menu”, „itp”, aby naprawdę podzielić strony na mniejsze, łatwe do zarządzania komponenty.

imaginethepoet
źródło
Może uda Ci się poprawić swoją odpowiedź za pomocą demonstracji kodu, która używa chrząkania?
Dmitrij Paszkiewicz
4

Użyj kombinacji przewodowej https://github.com/taptapship/wiredep i usemin https://github.com/yeoman/grunt-usemin , aby chrząknąć zajął się tymi zadaniami. Wiredep doda Twoje zależności jeden plik skryptu na raz, a usemin połączy je wszystkie w jeden plik do produkcji. Można to zrobić za pomocą kilku komentarzy HTML. Na przykład moje pakiety altanki są automatycznie dołączane i dodawane do html po uruchomieniu bower install && grunt bowerInstall:

<!-- build:js /scripts/vendor.js -->
<!-- bower:js -->
<!-- endbower -->
<!-- endbuild -->
Scottux
źródło
2

Ta odpowiedź nie dotyczy noobów!

Użyj szablonów Jade ... przekazywanie zmiennych do szablonu Jade to standardowy przypadek użycia torfowiska

Używam chrząknięcia (chrząknięcie-contrib-jade), ale nie musisz chrząkać. Wystarczy użyć standardowego modułu jade npm.

Jeśli używasz chrząknięcia, Twój plik chrząstek chciałby czegoś takiego ...

jade: {
    options: {
      // TODO - Define options here
    },
    dev: {
      options: {
        data: {
          pageTitle: '<%= grunt.file.name %>',
          homePage: '/app',
          liveReloadServer: liveReloadServer,
          cssGruntClassesForHtmlHead: 'grunt-' + '<%= grunt.task.current.target %>'
        },
        pretty: true
      },
      files: [
        {
          expand: true,
          cwd: "src/app",
          src: ["index.jade", "404.jade"],
          dest: "lib/app",
          ext: ".html"
        },
        {
          expand: true,
          flatten: true,
          cwd: "src/app",
          src: ["directives/partials/*.jade"],
          dest: "lib/app/directives/partials",
          ext: ".html"
        }
      ]
    }
  },

Możemy teraz łatwo uzyskać dostęp do danych przekazywanych przez chrząknięcie w szablonie Jade.

Podobnie jak podejście zastosowane przez Modernizra, ustawiam klasę CSS na znaczniku HTML zgodnie z wartością przekazywanej zmiennej i mogę użyć logiki JavaScript na podstawie tego, czy klasa CSS jest obecna, czy nie.

Jest to świetne, jeśli używasz Angulara, ponieważ możesz zrobić ng-if, aby uwzględnić elementy na stronie w zależności od tego, czy klasa jest obecna.

Na przykład mogę dołączyć skrypt, jeśli klasa jest obecna ...

(Na przykład mogę załączyć skrypt przeładowania na żywo w dev, ale nie w produkcji)

<script ng-if="controller.isClassPresent()" src="//localhost:35729/livereload.js"></script> 
danday74
źródło
2

Zastanów się processhtml . Pozwala zdefiniować wiele „celów” dla kompilacji. Komentarze służą do warunkowego dołączania lub wykluczania materiałów z HTML:

<!-- build:js:production js/app.js -->
...
<!-- /build -->

staje się

<script src="js/app.js"></script>

Podobno nawet robi takie fajne rzeczy (zobacz README ):

<!-- build:[class]:dist production -->
<html class="debug_mode">
<!-- /build -->

<!-- class is changed to 'production' only when the 'dist' build is executed -->
<html class="production">
dat
źródło