Utiliser Grunt dans ASP.NET Core

Grunt est un exécuteur de tâches JavaScript qui automatise la minification des scripts, la compilation TypeScript, les outils « lint » de qualité du code, les préprocesseurs CSS et à peu près toutes les tâches répétitives qui doivent être effectuées pour prendre en charge le développement du client. Grunt est entièrement pris en charge dans Visual Studio.

Cet exemple utilise un projet ASP.NET Core vide comme point de départ pour montrer comment automatiser le processus de génération du client à partir de zéro.

L’exemple terminé nettoie le répertoire de déploiement cible, combine des fichiers JavaScript, vérifie la qualité du code, condense le contenu du fichier JavaScript et déploie à la racine de votre application web. Nous allons utiliser les packages suivants :

  • grunt : package de l’exécuteur de tâches Grunt.

  • grunt-contrib-clean : un plug-in qui supprime des fichiers ou des répertoires.

  • grunt-contrib-jshint : un plug-in qui passe en revue la qualité du code JavaScript.

  • grunt-contrib-concat : un plug-in qui joint des fichiers à un seul fichier.

  • grunt-contrib-uglify : un plug-in qui minifie le JavaScript pour réduire sa taille.

  • grunt-contrib-watch : un plug-in qui surveille l’activité des fichiers.

Préparation de l’application

Pour commencer, configurez une nouvelle application web vide et ajoutez des exemples de fichiers TypeScript. Les fichiers TypeScript sont automatiquement compilés en JavaScript à l’aide des paramètres Visual Studio par défaut et seront notre matière première à traiter à l’aide de Grunt.

  1. Dans Visual Studio, créez un nouveau ASP.NET Web Application.

  2. Dans la boîte de dialogue Nouveau projet ASP.NET, sélectionnez le modèle ASP.NET Core Vide puis cliquez sur le bouton OK.

  3. Dans l’Explorateur de solutions, passez en revue la structure du projet. Le dossier \src comprend des nœuds wwwroot et Dependencies vides.

    empty web solution

  4. Ajoutez un nouveau dossier nommé TypeScript à votre répertoire de projet.

  5. Avant d’ajouter des fichiers, vérifiez que l’option « Compiler lors de l’enregistrement » pour les fichiers TypeScript est activée dans Visual Studio. Accédez à Outils>Options>Éditeur de texte>Typescript>Projet :

    options setting auto compilation of TypeScript files

  6. Cliquez avec le bouton droit sur le répertoire TypeScript, puis sélectionnez Ajouter > Nouvel élément dans le menu contextuel. Sélectionnez l’élément Fichier JavaScript et nommez le fichier Tastes.ts (notez l’extension *.ts). Copiez la ligne de code TypeScript ci-dessous dans le fichier (lors de l’enregistrement, un nouveau fichier Tastes.js s’affiche avec la source JavaScript).

    enum Tastes { Sweet, Sour, Salty, Bitter }
    
  7. Ajoutez un deuxième fichier au répertoire TypeScript et nommez-le Food.ts. Copier le code ci-dessous dans le fichier.

    class Food {
      constructor(name: string, calories: number) {
        this._name = name;
        this._calories = calories;
      }
    
      private _name: string;
      get Name() {
        return this._name;
      }
    
      private _calories: number;
      get Calories() {
        return this._calories;
      }
    
      private _taste: Tastes;
      get Taste(): Tastes { return this._taste }
      set Taste(value: Tastes) {
        this._taste = value;
      }
    }
    

Configuration de NPM

Ensuite, configurez NPM pour télécharger grunt et grunt-tasks.

  1. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet, puis sélectionnez Ajouter > Nouvel élément dans le menu contextuel. Sélectionnez l’élément Fichier de configuration NPM, laissez le nom par défaut, package.json, puis cliquez sur le bouton Ajouter.

  2. Dans le fichier package.json, à l’intérieur des accolades de l’objet devDependencies, entrez « grunt ». Sélectionnez grunt dans la liste IntelliSense et appuyez sur la touche Entrée. Visual Studio cite le nom du package grunt et ajoute un signe deux-points. À droite des deux-points, sélectionnez la dernière version stable du package en haut de la liste IntelliSense (appuyez sur Ctrl-Space si IntelliSense n’apparaît pas).

    grunt Intellisense

    Remarque

    NPM utilise le contrôle de version sémantique pour organiser les dépendances. Le contrôle de version sémantique, également appelé SemVer, identifie les packages avec le schéma de version <majeure>.<mineure>.<correctif>. IntelliSense simplifie le contrôle de version sémantique en n’affichant que quelques choix courants. L’élément supérieur de la liste IntelliSense (0.4.5 dans l’exemple ci-dessus) est considéré comme la dernière version stable du package. Le symbole caret (^) correspond à la version principale la plus récente et le tilde (~) à la version mineure la plus récente. Consultez la Référence de l’analyseur de version semver NPM comme guide de l’expressivité complète que SemVer fournit.

  3. Ajoutez d’autres dépendances pour charger des packages grunt-contrib-* pour clean, jshint, concat, uglify et watch, comme illustré dans l’exemple ci-dessous. Les versions n’ont pas besoin de correspondre à l’exemple.

    "devDependencies": {
      "grunt": "0.4.5",
      "grunt-contrib-clean": "0.6.0",
      "grunt-contrib-jshint": "0.11.0",
      "grunt-contrib-concat": "0.5.1",
      "grunt-contrib-uglify": "0.8.0",
      "grunt-contrib-watch": "0.6.1"
    }
    
  4. Enregistrez le fichier package.json.

Les packages de chaque élément devDependencies sont téléchargés, ainsi que tous les fichiers requis par chaque package. Vous pouvez trouver les fichiers de package dans le répertoire node_modules en activant le bouton Afficher tous les fichiers dans l’Explorateur de solutions.

grunt node_modules

Remarque

Si nécessaire, vous pouvez restaurer manuellement les dépendances dans l’Explorateur de solutions en cliquant avec le bouton droit sur Dependencies\NPM et en sélectionnant l’option de menu Restaurer les packages.

restore packages

Configuration de Grunt

Grunt est configuré à l’aide d’un manifeste nommé Gruntfile.js qui définit, charge et inscrit des tâches qui peuvent être exécutées manuellement ou configurées pour s’exécuter automatiquement en fonction des événements dans Visual Studio.

  1. Cliquez avec le bouton droit sur le projet et sélectionnez Ajouter>Nouvel élément. Sélectionnez le modèle d’élément Fichier JavaScript, remplacez le nom par Gruntfile.js, puis cliquez sur le bouton Ajouter.

  2. Ajoutez le code suivant à Gruntfile.js. La fonction initConfig définit les options de chaque package, et le reste du module charge et inscrit les tâches.

    module.exports = function (grunt) {
      grunt.initConfig({
      });
    };
    
  3. Dans la fonction initConfig, ajoutez des options pour la tâche clean, comme illustré dans l’exemple Gruntfile.js ci-dessous. La tâche clean accepte un tableau de chaînes de répertoires. Cette tâche supprime les fichiers de wwwroot/lib et supprime l’intégralité du répertoire /temp.

    module.exports = function (grunt) {
      grunt.initConfig({
        clean: ["wwwroot/lib/*", "temp/"],
      });
    };
    
  4. Sous la fonction initConfig, ajoutez un appel à grunt.loadNpmTasks. Cela rend la tâche exécutable à partir de Visual Studio.

    grunt.loadNpmTasks("grunt-contrib-clean");
    
  5. Enregistrez Gruntfile.js. Le fichier doit ressembler à la capture d’écran ci-dessous.

    initial gruntfile

  6. Cliquez avec le bouton droit sur Gruntfile.js, puis sélectionnez Explorateur d’exécuteur de tâches dans le menu contextuel. La fenêtre Explorateur d’exécuteur de tâches s’ouvre.

    task runner explorer menu

  7. Vérifiez que clean s’affiche sous Tâches dans l’Explorateur d’exécuteur de tâches.

    task runner explorer tasks list

  8. Cliquez avec le bouton droit sur la tâche de nettoyage, puis sélectionnez Exécuter dans le menu contextuel. Une fenêtre de commande affiche la progression de la tâche.

    task runner explorer run clean task

    Remarque

    Il n’y a pas encore de fichiers ou de répertoires à nettoyer. Si vous le souhaitez, vous pouvez les créer manuellement dans l’Explorateur de solutions, puis exécuter la tâche de nettoyage en tant que test.

  9. Dans la fonction initConfig, ajoutez une entrée pour concat à l’aide du code ci-dessous.

    Le tableau de propriétés src répertorie les fichiers à combiner, dans l’ordre dans lequel ils doivent être combinés. La propriété dest attribue le chemin d’accès au fichier combiné généré.

    concat: {
      all: {
        src: ['TypeScript/Tastes.js', 'TypeScript/Food.js'],
        dest: 'temp/combined.js'
      }
    },
    

    Notes

    La propriété all dans le code ci-dessus est le nom d’une cible. Les cibles sont utilisées dans certaines tâches Grunt pour autoriser plusieurs environnements de génération. Vous pouvez afficher les cibles intégrées à l’aide d’IntelliSense ou affecter les vôtres.

  10. Ajoutez la tâche jshint à l’aide du code ci-dessous.

    L’utilitaire code-quality jshint est exécuté sur chaque fichier JavaScript trouvé dans le répertoire temp.

    jshint: {
      files: ['temp/*.js'],
      options: {
        '-W069': false,
      }
    },
    

    Notes

    L’option « -W069 » est une erreur produite par jshint lorsque JavaScript utilise la syntaxe entre crochets pour affecter une propriété au lieu de la notation par point, c’est-à-dire Tastes["Sweet"] au lieu de Tastes.Sweet. L’option désactive l’avertissement pour permettre au reste du processus de continuer.

  11. Ajoutez la tâche uglify à l’aide du code ci-dessous.

    La tâche minifie le fichier combined.js trouvé dans le répertoire temp et crée le fichier de résultats dans wwwroot/lib en suivant la convention d’affectation de noms standard <nom de fichier>.min.js.

    uglify: {
     all: {
       src: ['temp/combined.js'],
       dest: 'wwwroot/lib/combined.min.js'
     }
    },
    
  12. Sous l’appel à grunt.loadNpmTasks qui charge grunt-contrib-clean, incluez le même appel pour jshint, concat et uglify à l’aide du code ci-dessous.

    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    
  13. Enregistrez Gruntfile.js. Le fichier doit ressembler à l’exemple ci-dessous.

    complete grunt file example

  14. Notez que la liste de tâches de l’Explorateur d’exécuteur de tâches comprend les tâches clean, concat, jshint et uglify. Exécutez chaque tâche dans l’ordre et observez les résultats dans l’Explorateur de solutions. Chaque tâche doit s’exécuter sans erreurs.

    task runner explorer run each task

    La tâche concat crée un fichier combined.js et le place dans le répertoire temp. La tâche jshint s’exécute simplement et ne produit pas de sortie. La tâche uglify crée un fichier combined.min.js et le place dans wwwroot/lib. À l’achèvement, la solution doit ressembler à la capture d’écran ci-dessous :

    solution explorer after all tasks

    Remarque

    Pour plus d’informations sur les options de chaque package, consultez https://www.npmjs.com/ et recherchez le nom du package dans la zone de recherche de la page principale. Par exemple, vous pouvez rechercher le package grunt-contrib-clean pour obtenir un lien de documentation qui explique tous ses paramètres.

Vue globale

Utilisez la méthode Grunt registerTask() pour exécuter une série de tâches dans une séquence particulière. Par exemple, pour exécuter les exemples d’étapes ci-dessus dans l’ordre clean -> concat -> jshint -> uglify, ajoutez le code ci-dessous au module. Le code doit être ajouté au même niveau que les appels loadNpmTasks(), en dehors d’initConfig.

grunt.registerTask("all", ['clean', 'concat', 'jshint', 'uglify']);

La nouvelle tâche s’affiche dans l’Explorateur d’exécuteur de tâches sous Tâches d’alias. Vous pouvez cliquer avec le bouton droit et l’exécuter comme vous le feriez pour d’autres tâches. La tâche all exécute clean, concat, jshint et uglify dans l’ordre.

alias grunt tasks

Détection des changements

Une tâche watch surveille les fichiers et les répertoires. L’observateur déclenche automatiquement des tâches s’il détecte des modifications. Ajoutez le code ci-dessous à initConfig pour surveiller les modifications apportées aux fichiers *.js dans le répertoire TypeScript. Si un fichier JavaScript est modifié, watch exécute la tâche all.

watch: {
  files: ["TypeScript/*.js"],
  tasks: ["all"]
}

Ajoutez un appel à loadNpmTasks() pour afficher la tâche watch dans l’Explorateur d’exécuteur de tâches.

grunt.loadNpmTasks('grunt-contrib-watch');

Cliquez avec le bouton droit sur la tâche watch dans l’Explorateur d’exécuteur de tâches, puis sélectionnez Exécuter dans le menu contextuel. La fenêtre de commande qui affiche la tâche watch en cours d’exécution affiche un message « En attente... ». Ouvrez l’un des fichiers TypeScript, ajoutez un espace, puis enregistrez le fichier. Cela déclenchera la tâche watch et l’exécution des autres tâches dans l’ordre. La capture d’écran ci-dessous montre un exemple d’exécution.

running tasks output

Liaison à des événements Visual Studio

À moins que vous ne souhaitiez démarrer manuellement vos tâches chaque fois que vous travaillez dans Visual Studio, liez les tâches aux événements Before Build, After Build, Clean et Project Open.

Liez watch afin qu’il s’exécute chaque fois que Visual Studio s’ouvre. Dans l’Explorateur d’exécuteur de tâches, cliquez avec le bouton droit sur la tâche watch et sélectionnez Liaisons>Project Open dans le menu contextuel.

bind a task to the project opening

Déchargez et rechargez le projet. Lorsque le projet se charge à nouveau, la tâche watch commence à s’exécuter automatiquement.

Résumé

Grunt est un exécuteur de tâches puissant qui peut être utilisé pour automatiser la plupart des tâches de génération de client. Grunt tire parti de NPM pour fournir ses packages et propose l’intégration des outils à Visual Studio. L’Explorateur d’exécuteur de tâches de Visual Studio détecte les modifications apportées aux fichiers de configuration et fournit une interface pratique pour exécuter des tâches, afficher les tâches en cours d’exécution et lier des tâches aux événements Visual Studio.