Organisieren Ihrer Grunt-Aufgaben

Avatar of Jason Witt
Jason Witt am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Die Idee, Ihren Code in kleinere, mundgerechte Stücke zu zerlegen, schafft eine Umgebung, die einfach zu bearbeiten und zu pflegen ist. Das wird oft als Modul-Design betrachtet und ist heutzutage ein Standard für die Webentwicklung. Ich zeige Ihnen eine Möglichkeit, wie Sie Moduldesign nutzen können, um Ihre Grunt-Aufgaben besser zu organisieren.

Ich gehe davon aus, dass Sie die Grundlagen der Grunt-Nutzung bereits kennen. Wenn nicht, hier ist ein Artikel von Chris, der Ihnen den Einstieg erleichtert: Grunt für Leute, die Dinge wie Grunt seltsam und schwierig finden.

Wenn Sie Grunt verwenden, sind Sie wahrscheinlich daran gewöhnt, dass Ihre Gruntfile wie folgt aussieht.

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    sass: {
      dist: {
        options: {
          style: 'expanded',
          sourcemap: 'none'
        },
        files: {
          'style.css': 'sass/global.scss',      
          'css/dev.style.css': 'sass/global.scss',
          'css/ie9.style.css': 'sass/ie9.scss',
        }
      }
    },
    postcss: {
      options: {
        processors: [
          require('autoprefixer')(),
          require('rucksack-css')({ fallbacks: true })
        ]
      },
      dist: {
        src: 'style.css',
        dest: 'style.css'
      },
      dev: {
        src: 'css/dev.style.css',
        dest: 'css/dev.style.css'
      },
    },
    cssmin: {
      target: {
        files: {
          'style.css': 'style.css'
        }
      }
    },
    concat: {
      dist: {
        src: [
          'js/lib/no-conflict.js',
          'js/lib/skip-navigation.js',
        ],
        dest: 'js/scripts.js'
      },
    },
    jshint: {
      files: [
        'js/scripts.js',
        'js/ie.js',
      ],
      options: {
        scripturl: true,
        globals: {
          jQuery: true
        }
      }
    },
    uglify: {
      options: {
        mangle: false,
        compress: true,
        quoteStyle: 3
      },
      dist: {
        files: {
          'js/head.min.js': 'js/head.js',
          'js/scripts.min.js': 'js/scripts.js',
          'js/ie.min.js'     : 'js/ie.js',
        }
      }
    },
    watch: {
      scripts: {
        files: ['js/**/*.js'],
        tasks: ['concat', 'uglify'],
        options: {
          spawn: false
        }
      },
      css: {
        files: ['sass/**/*.scss'],
        tasks: ['sass', 'postcss', 'cssmin']
      }
    },
  });
  grunt.loadNpmTasks('grunt-postcss');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-jsvalidate');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-sass');
  grunt.registerTask('default', ['watch']);
};

Das ist eine ziemlich normal aussehende Gruntfile. Eigentlich ist das eine ziemlich kleine. Ich habe Gruntfiles gesehen, die dreimal so groß waren. Wenn ich mir diese großen Gruntfiles ansehe, bekomme ich Kopfschmerzen. Das Moduldesign wurde mir so sehr eingeprägt, dass mich eine so große Gruntfile aus dem Konzept bringt. Warum kann meine Gruntfile nicht mehr so aussehen?

module.exports = function(grunt) {
  var tasks = {scope: ['devDependencies', 'dependencies' ]};
  var options = {config: { src: "grunt/*.js" }};
  var configs = require('load-grunt-configs')(grunt, options);
  require('load-grunt-tasks')(grunt, tasks);
  grunt.initConfig(configs);
  grunt.registerTask('default', ['watch']);
};

Das kann sie! Ich zeige Ihnen, wie.

Um dies zu erreichen, werden wir zwei Grunt-Pakete installieren.

  1. load-grunt-tasks
  2. load-grunt-configs

Installieren Sie diese Pakete wie jedes andere Grunt-Paket.

$ npm install --save-dev load-grunt-tasks
$ npm install --save-dev load-grunt-configs

Nun sollte Ihre `package.json`-Datei die beiden Pakete wie folgt enthalten.

{
  "name": "your-project",
  "version": "1.0.0",
  "description": "",
  "main": "Gruntfile.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "grunt-contrib-cssmin": "^1.0.1",
    "load-grunt-configs": "^1.0.0",
    "load-grunt-tasks": "^3.5.0"
  }
}

Zu diesem Artikel habe ich auch grunt-contrib-cssmin aufgenommen. Ihre `package.json`-Datei sollte alle Grunt-Pakete enthalten, die Sie für Ihr Projekt benötigen.

Lassen Sie uns nun mit einer neuen `Gruntfile.js` beginnen. Erstellen Sie eine neue `Gruntfile.js`-Datei und fügen Sie Folgendes hinzu.

module.exports = function(grunt) {

}

Als Erstes richten wir load-grunt-tasks ein. Was load-grunt-tasks tut, ist, dass es alle Ihre `grunt.loadNpmTasks()` für Sie erstellt. Dies erspart Ihnen das mühsame Schreiben jeder einzelnen `grunt.loadNpmTasks()` von Hand.

Erstellen wir eine Variable `tasks`, die die Optionen für das load-grunt-tasks-Paket definiert. Wir definieren lediglich den Geltungsbereich und weisen es an, eine `grunt.loadNpmTasks()` für alle `devDependencies` und `dependencies`-Pakete zu erstellen, die in der `package.json`-Datei definiert sind.

module.exports = function(grunt) {
  var tasks = {scope: ['devDependencies', 'dependencies']};
}

Wir müssen es `require()` und die Variable `tasks` als zweites Argument hinzufügen. Fügen wir auch zwei weitere Variablen **options** und **configs** für load-grunt-configs hinzu.

module.exports = function(grunt) {
  var tasks = {scope: ['devDependencies', 'dependencies' ]};
  var options = {config: { src: "grunt/*.js" }};
  var configs = require('load-grunt-configs')(grunt, options);
  require('load-grunt-tasks')(grunt, tasks);
}

In der **options**-Variable teilen wir load-grunt-configs mit, wo es nach den Dateien suchen soll, die die Grunt-Aufgabenoptionen enthalten. Die Variable **configs** ist einfach das Einbinden von load-grunt-configs und das Hinzufügen von **options** als zweites Argument.

Schließlich fügen wir die Variable `configs` in die Funktion `grunt.initConfig()` ein und registrieren eine einfache Aufgabe, die grunt-contrib-cssmin ausführt.

module.exports = function(grunt) {
  var tasks = {scope: ['devDependencies', 'dependencies' ]};
  var options = {config: { src: "grunt/*.js" }};
  var configs = require('load-grunt-configs')(grunt, options);
  require('load-grunt-tasks')(grunt, tasks);
  grunt.initConfig(configs);
  grunt.registerTask('default', ['cssmin']);
}

Das ist alles, was wir in die Gruntfile aufnehmen werden. Die einzigen weiteren Dinge, die Sie hinzufügen möchten, wären zusätzliche Aufgaben, die Sie registrieren möchten. Wie eine **watch**-Aufgabe oder eine **build**-Aufgabe.

In der Variablen `options` haben wir den *src* als `grunt/*.js` definiert. Dies weist load-grunt-configs an, in einem Verzeichnis namens **grunt** zu suchen und alle darin enthaltenen JavaScript-Dateien einzuschließen.

Lassen Sie uns ein Verzeichnis namens **grunt** erstellen und die Aufgabenoptionen für cssmin hinzufügen, indem wir eine Datei namens `cssmin.js` erstellen. Ihre Projektverzeichnisstruktur sollte jetzt ähnlich aussehen.

Fügen wir die cssmin-Optionen zur Datei `cssmin.js` hinzu. Das Erste, was Sie hinzufügen möchten, ist die Grunt-Variable `module.exports`, genau wie in der Gruntfile, damit Grunt weiß, dass diese Datei beim Ausführen Ihrer Grunt-Aufgabe geladen werden soll. Fügen Sie dann die Optionen für cssmin hinzu.

module.exports = {
  target: {
    files: {
      'style.css': 'styles.css'
    }
  }
};

Wenn Sie bemerkt haben, habe ich die `cssmin: {}`-Klammern nicht hinzugefügt, wie Sie es in einer einfachen Gruntfile tun würden. Das liegt daran, dass load-grunt-configs den Dateinamen verwendet, um zu erkennen, welche Aufgabe ausgeführt wird. Wenn Sie zum Beispiel grunt-contrib-uglify verwenden, wäre der Dateiname `uglify.js`. Wenn Sie grunt-postcss verwenden, wäre der Dateiname `postcss.js`.

So fügen wir das Moduldesignkonzept zu unseren Grunt-Aufgaben hinzu. Jede Aufgabe erhält eine eigene Datei, die die Optionen der Aufgabe enthält. Das erleichtert das Hinzufügen neuer Aufgaben und ermöglicht es mehreren Entwicklern, Änderungen vorzunehmen, ohne sich Sorgen machen zu müssen, versehentlich eine andere Aufgabe in einer riesigen Gruntfile durcheinanderzubringen.

Wenn Sie nun Ihre Grunt-Aufgabe ausführen. Grunt sucht im Ordner `grunt`, findet alle Aufgabendateien und führt diese Aufgaben mit den Optionen aus, die Sie in jeder Datei definiert haben.

Dies war ein einfaches Beispiel für diese Technik. Die Pakete load-grunt-tasks und load-grunt-configs bieten weitere Optionen, die Ihnen noch mehr Kontrolle über Ihre Grunt-Aufgaben geben können.

Ich hoffe, das hilft Ihnen, Ihre Gruntfile in den Griff zu bekommen und Ihren Projekten mit Grunt mehr Flexibilität zu verleihen.