Lassen Sie Grunt index.html für verschiedene Setups generieren


208

Ich versuche, Grunt als Build-Tool für meine Webanwendung zu verwenden.

Ich möchte mindestens zwei Setups haben:

I. Entwicklungssetup - Laden Sie Skripte aus separaten Dateien ohne Verkettung.

meine index.html würde also ungefähr so ​​aussehen:

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

II. Produktions-Setup - Laden Sie meine Skripte minimiert und verkettet in eine Datei.

mit index.html entsprechend:

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

Die Frage ist, wie kann ich grunzen lassen, um diese index.html abhängig von der Konfiguration zu machen, wenn ich grunt devoder ausführe grunt prod?

Oder vielleicht grabe ich in die falsche Richtung und es wäre einfacher, immer zu generieren, MyApp-all.min.jsaber entweder alle meine Skripte (verkettet) oder ein Loader-Skript, das diese Skripte asynchron aus separaten Dateien lädt, darin abzulegen?

Wie machst du das, Jungs?


3
Probieren Sie das Yeoman-Tool aus, das eine 'usemin'-Aufgabe enthält, die genau das tut, was Sie tun. Darüber hinaus enthalten Yeamon-Generatoren viele leicht zu erlernende "bewährte Methoden", die bei Verwendung eines neuen Tools nur schwer zu erlernen sind.
EricSonaron

Antworten:


161

Ich habe kürzlich diese Grunt- v0.4.0kompatiblen Aufgaben entdeckt:

  • Grunz-Vorprozess

    Grunzaufgabe um das vorverarbeitete npm-Modul.

  • grunzen-env

    Grunzaufgabe zur Automatisierung der Umgebungskonfiguration für zukünftige Aufgaben.

Unten sind Ausschnitte aus meinem Gruntfile.js.

ENV-Setup:

env : {

    options : {

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

    },

    dev: {

        NODE_ENV : 'DEVELOPMENT'

    },

    prod : {

        NODE_ENV : 'PRODUCTION'

    }

},

Vorverarbeitung:

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 %>'
            }

        }

    }

}

Aufgaben:

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']);

Und in der /src/tmpl/index.htmlVorlagendatei (zum Beispiel):

<!-- @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 -->

Ich bin mir sicher, dass mein Setup anders ist als das der meisten Leute, und der Nutzen des oben genannten hängt von Ihrer Situation ab. Für mich ist das Yeoman- Grunz-Usemin zwar ein großartiger Code, aber robuster als ich persönlich brauche.

HINWEIS: Ich habe heute gerade die oben aufgeführten Aufgaben entdeckt, sodass mir möglicherweise eine Funktion fehlt und / oder sich mein Prozess später ändern kann. Im Moment liebe ich die Einfachheit und die Funktionen, die Grunt-Preprocess und Grunt-Env bieten. :) :)


Update Januar 2014:

Motiviert durch eine Abwertung ...

Als ich diese Antwort veröffentlichte, gab es für Grunt nicht viele Optionen 0.4.x, die eine Lösung boten, die meinen Anforderungen entsprach. Jetzt, Monate später, würde ich vermuten, dass es mehr Optionen gibt, die besser sein könnten als das, was ich hier gepostet habe. Während ich diese Technik für meine Builds immer noch persönlich verwende und gerne verwende, bitte ich zukünftige Leser, sich die Zeit zu nehmen, die anderen gegebenen Antworten zu lesen und alle Optionen zu recherchieren. Wenn Sie eine bessere Lösung finden, posten Sie bitte Ihre Antwort hier.

Update Februar 2014:

Ich bin mir nicht sicher, ob es jemandem helfen wird, aber ich habe dieses Demo-Repository auf GitHub erstellt , das ein vollständiges (und komplexeres Setup) unter Verwendung der oben beschriebenen Technik (en) zeigt.


Danke, ich werde es überprüfen!
Dmitry Pashkevich

3
Ihre Lösung hat mir Stunden erspart, meinen Kopf gegen eine Wand zu schlagen. Vielen Dank.
sthomps

1
@sthomps Ich bin froh, dass es geholfen hat! Seit ich diese Aufgaben entdeckt habe, liebe ich den Workflow. Zu Ihrer Information, ich habe eine geringfügige Änderung am Prozess vorgenommen ... Anstatt mehrere Kontextvariablen an meine HTML-Vorlagen zu übergeben, habe ich mich dafür entschieden, eine Variable zu übergeben, path : '/<%= pkg.name %>/dist/<%= pkg.version %>/<%= now %>/<%= ver %>'die alle Variablen enthält (das ist mein Erstellungspfad). Auf meiner Vorlage habe ich : <script src="http://cdn.foo.com<!-- @echo path -->/js/bulldog.min.js"></script>. Wie auch immer, ich bin froh, dass ich dir etwas Zeit sparen konnte! : D
mhulse

4
Sie können dasselbe nur mit einer Grunzvorlage tun , indem Sie einfach ein anderes dataObjekt für dev / prod übergeben.
Mathias Bynens

2
Mann, ich liebe diese Lösung. Sie ist sauber, lesbar und nicht überarbeitet.
Gaurang Patel

34

Ich habe meine eigene Lösung gefunden. Noch nicht poliert, aber ich denke, ich werde mich in diese Richtung bewegen.

Im Wesentlichen verwende ich grunt.template.process () , um meine index.htmlaus einer Vorlage zu generieren , die die aktuelle Konfiguration analysiert und entweder eine Liste meiner ursprünglichen Quelldateien oder Links zu einer einzelnen Datei mit verkleinertem Code erstellt. Das folgende Beispiel gilt für js-Dateien, aber der gleiche Ansatz kann auf CSS und andere mögliche Textdateien erweitert werden.

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 + '\'');
    });
}

Schließlich index.tmplmit eingebauter Generierungslogik:

<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. Es wurde herausgefunden, dass Yeoman , das auf Grunzen basiert, eine integrierte Usemin- Aufgabe hat, die in Yeomans Build-System integriert ist. Es generiert eine Produktionsversion von index.html aus Informationen in der Entwicklungsversion von index.html sowie anderen Umgebungseinstellungen. Ein bisschen raffiniert, aber interessant anzusehen.


5
grunt-template ist ein sehr leichter Wrappergrunt.template.process()(den Sie hier verwenden), der dies noch einfacher machen würde. Sie können dasselbe mit grunt-template tun,indem Sie einfach ein anderesdataObjekt für dev / prod übergeben.
Mathias Bynens

15

Ich mag die Lösungen hier nicht (einschließlich der, die ich zuvor gegeben habe ) und hier ist der Grund:

  • Das Problem mit der Antwort mit der höchsten Bewertung besteht darin, dass Sie die Liste der Skript-Tags manuell hinzufügen müssen, wenn Sie eine JS-Datei hinzufügen / umbenennen / löschen.
  • Das Problem mit der akzeptierten Antwort ist, dass Ihre Liste der JS-Dateien keine Musterübereinstimmung aufweisen kann. Dies bedeutet, dass Sie es im Gruntfile von Hand aktualisieren müssen.

Ich habe herausgefunden, wie ich diese beiden Probleme lösen kann. Ich habe meine Grunzaufgabe so eingerichtet, dass jedes Mal, wenn eine Datei hinzugefügt oder gelöscht wird, die Skript-Tags automatisch generiert werden, um dies widerzuspiegeln. Auf diese Weise müssen Sie weder Ihre HTML-Datei noch Ihre Grunzdatei ändern, wenn Sie Ihre JS-Dateien hinzufügen / entfernen / umbenennen.

Um zusammenzufassen, wie das funktioniert, habe ich eine HTML-Vorlage mit einer Variablen für die Skript-Tags. Ich benutze https://github.com/alanshaw/grunt-include-replace , um diese Variable zu füllen. Im Dev-Modus stammt diese Variable aus einem Globbing-Muster aller meiner JS-Dateien. Die Überwachungsaufgabe berechnet diesen Wert neu, wenn eine JS-Datei hinzugefügt oder entfernt wird.

Um im Entwicklungs- oder Produktmodus unterschiedliche Ergebnisse zu erzielen, füllen Sie diese Variable einfach mit einem anderen Wert. Hier ist ein Code:

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

jsSrcFileArrayist Ihr typisches Grunzmuster. jsScriptTagsnimmt das jsSrcFileArrayund verkettet sie zusammen mit scriptTags auf beiden Seiten. destPathist das Präfix, das ich für jede Datei haben möchte.

Und so sieht HTML aus:

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

</head>

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

Wie Sie in der Konfiguration sehen können, generiere ich den Wert dieser Variablen als fest codiertes scriptTag, wenn sie im prodModus ausgeführt wird. Im Dev-Modus wird diese Variable auf einen Wert wie den folgenden erweitert:

<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>

Lassen Sie mich wissen, wenn Sie Fragen haben.

PS: Dies ist eine verrückte Menge an Code für etwas, das ich in jeder clientseitigen JS-App tun möchte. Ich hoffe, jemand kann daraus ein wiederverwendbares Plugin machen. Vielleicht werde ich eines Tages.


1
Hört sich gut an. Gibt es eine Chance, dass Sie einige Schnipsel teilen?
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 thatWie hast du das gemacht?
CodyBugstein

2
Eine andere Frage: Kennen Sie eine Möglichkeit, nur Blöcke von HTML- <script>Tags zu löschen ?
CodyBugstein

@Imray nicht aus meinem Kopf. Du meinst ohne irgendeine Form von Vorlage (zB Grunzen-Einschließen-Ersetzen)? Der erste Gedanke, der mir in den Sinn kommt, wäre xslt. Wahrscheinlich keine gute Lösung.
Daniel Kaplan

1
Diese Antwort ist genau das Richtige, auch wenn ich persönlich entfernt destPathvon jsScriptTagsund tauschte grunt.file.expandMappingmit , grunt.file.expandda die Dateien , die ich bereits an den richtigen Stellen wollte. Dies hat die Dinge sehr vereinfacht. Danke @DanielKaplan, du hast mir sehr viel Zeit gespart :)
DanielM

13

Ich habe mir schon eine Weile die gleiche Frage gestellt und ich denke, dieses Grunz-Plugin könnte so konfiguriert werden, dass es das tut, was Sie wollen: https://npmjs.org/package/grunt-targethtml . Es implementiert bedingte HTML-Tags, die vom Grunzziel abhängen.


2
Ich habe dieses Plugin gesehen, aber ich mag die Idee nicht, alle Dateien (und tatsächlich eine Logik) in meiner index.html manuell anzugeben, da ich bereits eine Liste der Quell-js / css-Dateien in meiner Grunzkonfiguration habe und nicht ' Ich möchte mich nicht wiederholen. Fazit ist - es ist nicht in index.html, wo Sie entscheiden sollten, welche Dateien enthalten sein sollen
Dmitry Pashkevich

+1 für grunt-targethtml. Obwohl es etwas hässlich ist, if-Anweisungen hinzuzufügen, um in Ihrer index.html zu "entscheiden", welche Assets geladen werden sollen. Trotzdem macht es Sinn. Dies ist der Ort, an dem Sie normalerweise Ressourcen in Ihr Projekt aufnehmen möchten. Außerdem führte mich die Nachverfolgung dazu, Grunzbeiträge zu überprüfen. Es enthält einige großartige Dinge.
Carbontax

8

Ich suchte nach einer einfacheren und direkteren Lösung und kombinierte die Antwort aus dieser Frage:

So platzieren Sie einen anderen Block in gruntfile.js

und kam mit folgenden einfachen Schritten:

  1. Behalten Sie zwei Versionen Ihrer Indexdateien bei, wie Sie sie aufgelistet haben, und nennen Sie sie index-development.html und index-prodoction.html.
  2. Verwenden Sie die folgende Logik im concat / copy-Block Ihrer Gruntfile.js für Ihre index.html-Datei:

    concat: {
        index: {
            src : [ (function() {
                if (grunt.option('Release')) {
                  return 'views/index-production.html';
                } else {
                  return 'views/index-development.html';
                }
              }()) ],
           dest: '<%= distdir %>/index.html',
           ...
        },
        ...
    },
  3. Führen Sie 'grunt --Release' aus, um die Datei index-product.html auszuwählen, und lassen Sie das Flag weg, um die Entwicklungsversion zu erhalten.

Keine neuen Plugins zum Hinzufügen oder Konfigurieren und keine neuen Grunzaufgaben.


3
Der einzige Nachteil hierbei ist, dass zwei index.html-Dateien verwaltet werden müssen.
Adam Marshall

5

Diese Grunzaufgabe namens scriptlinker scheint eine einfache Möglichkeit zu sein, die Skripte im Entwicklungsmodus hinzuzufügen. Sie könnten wahrscheinlich zuerst eine Concat-Task ausführen und sie dann im Prod-Modus auf Ihre verkettete Datei verweisen.


+1. Die Dokumentation ist verwirrend und einige Dinge (appRoot, relative) funktionieren nicht immer wie beabsichtigt, aber dennoch: hilfreiches Tool.
Hashchange

1
@ Hashchange Ich benutze dieses Tool nicht. Am Ende habe ich stattdessen github.com/alanshaw/grunt-include-replace verwendet. Ich habe eine Variable in meiner HTML-Datei, die die Skript-Tags darstellt. Dann fülle ich diese Variable mit einem String des gewünschten HTML-Codes. Im Dev-Modus ist diese Variable eine Liste der Skripte. Im Prod-Modus ist diese Variable die verkettete, minimierte Version.
Daniel Kaplan

Vielen Dank für den Zeiger auf grunt-include-replace. (Ich brauchte tatsächlich ein Tool zum Hinzufügen aller Spezifikationsdateien in einem Verzeichnis zu einer Mocha index.html-Datei. Scriptlinker ist dafür in Ordnung.)
Hashchange

@hashchange Sie haben Recht mit der Dokumentation saugen. Wie können Sie feststellen, wo die Skriptkacheln in Ihrer HTML-Datei abgelegt werden sollen?
Daniel Kaplan

1
Sie definieren einen HTML-Kommentar. Schauen Sie sich diese Datei an . Einfügungen erfolgen bei <!--SINON COMPONENT SCRIPTS-->und <!--SPEC SCRIPTS-->. Und hier ist die Grunt-Aufgabe, die es erledigt (eine tatsächlich funktionierende, im Gegensatz zu den Dingen in den Dokumenten). Hoffe es hilft;)
Hashchange

5

grunt-dom-munger liest und bearbeitet HTML mit CSS-Selektoren. Ex. Lesen Sie Tags aus Ihrem HTML. Entfernen Sie Knoten, fügen Sie Knoten hinzu und vieles mehr.

Sie können grunt-dom-munger verwenden, um alle Ihre JS-Dateien zu lesen, die durch Ihre index.html verknüpft sind, sie hässlich machen und dann grunt-dom-munger erneut verwenden, um Ihre index.html so zu ändern, dass nur die minimierte JS verknüpft wird


5

Ich habe ein Grunz-Plugin namens grunt-dev-prod-switch gefunden. Alles, was es tut, ist, bestimmte Blöcke zu kommentieren, nach denen es sucht, basierend auf einer --env-Option, die Sie an grunzen übergeben (obwohl es Sie auf dev, prod und test beschränkt).

Sobald Sie es wie hier beschrieben eingerichtet haben , können Sie beispielsweise Folgendes ausführen:

grunt serve --env=devund alles, was es tut, ist die Blöcke auskommentieren, die von umbrochen werden

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

und es werden Blöcke auskommentiert, die von umwickelt werden

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

Es funktioniert auch mit Javascript. Ich verwende es, um die richtige IP-Adresse für meine Backend-API einzurichten. Die Blöcke ändern sich einfach zu

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

In Ihrem Fall wäre es so einfach:

<!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>

4

grunt-bake ist ein fantastisches grunt-Skript, das hier großartig funktionieren würde. Ich verwende es in meinem JQM-Auto-Build-Skript.

https://github.com/imaginethepoet/autojqmphonegap

Schauen Sie sich meine grunt.coffee-Datei an:

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

Dies betrachtet alle Dateien in base.html und saugt sie an, um index.html zu erstellen. Das funktioniert fantastisch für mehrseitige Apps (Phonegap). Dies erleichtert die Entwicklung, da nicht alle Entwickler an einer langen, einseitigen App arbeiten (wodurch viele Konflikt-Checkins verhindert werden). Stattdessen können Sie die Seiten aufteilen und an kleineren Codestücken arbeiten und mit einem Überwachungsbefehl zur vollständigen Seite kompilieren.

Bake liest die Vorlage aus base.html und fügt die HTML-Seiten der Komponente in watch ein.

<!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>

Sie können noch einen Schritt weiter gehen und Ihren Seiten Injektionen für "Menüs", "Popups" usw. hinzufügen, damit Sie Seiten wirklich in kleinere verwaltbare Komponenten aufteilen können.


Vielleicht können Sie Ihre Antwort mit einer Code-Demo verbessern, die Grunt-Bake verwendet?
Dmitry Pashkevich

4

Verwenden Sie eine Kombination aus Wiredep https://github.com/taptapship/wiredep und Usemin https://github.com/yeoman/grunt-usemin , damit Grunzen diese Aufgaben erledigt. Wiredep fügt Ihre Abhängigkeiten einzeln als Skriptdatei hinzu, und usemin verkettet sie alle zu einer einzigen Datei für die Produktion. Dies kann dann mit nur einigen HTML-Kommentaren erreicht werden. Zum Beispiel werden meine Bower-Pakete automatisch eingeschlossen und dem HTML hinzugefügt, wenn ich Folgendes ausführe bower install && grunt bowerInstall:

<!-- build:js /scripts/vendor.js -->
<!-- bower:js -->
<!-- endbower -->
<!-- endbuild -->

2

Diese Antwort ist nichts für Noobs!

Verwenden Sie Jade-Vorlagen ... Das Übergeben von Variablen an eine Jade-Vorlage ist ein Standard-Anwendungsfall

Ich benutze Grunzen (Grunt-Contrib-Jade), aber Sie müssen kein Grunzen verwenden. Verwenden Sie einfach das Standard-npm-Jademodul.

Wenn Sie grunzen, dann möchte Ihre Grunzdatei so etwas wie ...

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"
        }
      ]
    }
  },

Wir können jetzt einfach auf die Daten zugreifen, die von grunt in der Jade-Vorlage übergeben wurden.

Ähnlich wie bei Modernizr habe ich eine CSS-Klasse für das HTML-Tag entsprechend dem Wert der übergebenen Variablen festgelegt und kann von dort aus die JavaScript-Logik verwenden, je nachdem, ob die CSS-Klasse vorhanden ist oder nicht.

Dies ist ideal, wenn Sie Angular verwenden, da Sie ng-ifs ausführen können, um Elemente in die Seite aufzunehmen, je nachdem, ob die Klasse vorhanden ist.

Zum Beispiel könnte ich ein Skript einfügen, wenn die Klasse vorhanden ist ...

(Zum Beispiel könnte ich das Live-Reload-Skript in dev, aber nicht in die Produktion aufnehmen.)

<script ng-if="controller.isClassPresent()" src="//localhost:35729/livereload.js"></script> 

2

Betrachten Sie processhtml . Es ermöglicht die Definition mehrerer "Ziele" für Builds. Kommentare werden verwendet, um Material bedingt in den HTML-Code aufzunehmen oder aus ihm auszuschließen:

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

wird

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

Es gibt sogar vor, solche raffinierten Dinge zu tun (siehe README-Datei ):

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

<!-- class is changed to 'production' only when the 'dist' build is executed -->
<html class="production">
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.