Ladezeiten Optimierung - Automatisierung mit Grunt

Ladezeiten Optimierung – Automatisierung mit Grunt

Im letzten Beitrag haben wir bereits über die Optimierungsmöglichkeiten durch das Minifizieren der verschiedenen Dateien gesprochen. Heute möchte ich an einem einfachen Beispiel zeigen, wie die Optimierung der Website mit dem JavaScript Task Runner Grunt nahezu komplett automatisiert werden kann.

Doch zunächst ein wenig Theorie: Grunt ist ein komplett in JavaScript geschriebener Task Runner, welcher mit node.js läuft und dafür verwendet werden kann, bestimmte Aufgaben (die Tasks) automatisiert auszuführen. Da sich die meisten Entwickler bereits mit JavaScript auskennen sollten, ist hier der Einstieg besonders einfach. Die Installation von node.js kann z. B. bei Ubuntu über den Paketmanager erfolgen:

sudo apt-get update
sudo apt-get install nodejs 

Für Grunt wird zusätzlich noch npm benötigt:

sudo apt-get install npm

Viele Open Source Projekte liefern bereits fertige Konfigurationen für npm mit. An dieser Stelle werde ich allerdings kein bestehendes Projekt nutzen, sondern ein komplett neues anlegen, um alle Schritte im Detail zu erklären. Die Konfiguration für ein Projekt ist in der Datei package.json hinterlegt. Diese enthält z. B. die Abhängigkeiten zu anderen Projekten wie jQuery oder zu speziell nötigen Plugins wie Grunt. Legen wir also zunächst eine neues Projekt mit dem Befehl npm init an:

dhemeier@dhemeier-pc:~/data/Git/GruntExample$ npm init
 This utility will walk you through creating a package.json file.
 It only covers the most common items, and tries to guess sane defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> –save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (GruntExample)
version: (0.0.0)
description: A demo package for grunt
entry point: (index.js) index.html
test command:
git repository:
keywords:
author: Dennis Hemeier <d.hemeier@mittwald.de>
license: (ISC) MIT
About to write to /home/dhemeier/data/Git/GruntExample/package.json:

{
„name“: „GruntExample“,
„version“: „0.0.0“,
„description“: „A demo package for grunt“,
„main“: „index.html“,
„scripts“: {
„test“: „echo \“Error: no test specified\“ && exit 1″
},
„author“: „Dennis Hemeier <d.hemeier@mittwald.de>“,
„license“: „MIT“
}
Is this ok? (yes)

Damit haben wir in unserem Projektverzeichnis eine package.json mit den grundlegenden Daten. Nun müssen wir natürlich noch Grunt hinzufügen, da wir dieses ja in unserem Projekt verwenden wollen. Weiterhin werde ich direkt einige andere Grunt Plugins hinzufügen, welche wir im späteren Verlauf noch benötigen:

npm install grunt --save-dev
npm install grunt-contrib-uglify grunt-contrib-concat grunt-contrib-compress grunt-contrib-cssmin grunt-contrib-watch grunt-contrib-connect --save-dev 

Damit wir nun anfangen können, diese Tools zu benutzen, benötigen wir natürlich erst mal Quelldateien. Als Beispiel verwende ich das html5 Boilerplate, welches hier heruntergeladen werden kann. Um nun mit Grunt zu arbeiten, wird eine Datei mit dem Namen Gruntfile.js angelegt. Diese beinhaltet die komplette Konfiguration aller auszuführenden Grunt Tasks:

"use strict";

module.exports = function (grunt) {

grunt.initConfig({
 pkg: grunt.file.readJSON('package.json'),

meta: {
 jsFiles: [
 'js/vendor/jquery-1.10.2.min.js',
 'js/plugins.js',
 'js/main.js'
 ]
 },

uglify: {
 javascript: {
 files : {
 'dist/js/script.js': ['dist/js/script.js']
 },
 options: {
 mangle: false
 }
 }
 },

concat: {
 options : {
 separator: ';'
 },
 javascript: {
 src : ['<%= meta.jsFiles %>'],
 dest: 'dist/js/script.js'
 }
 },

cssmin: {
 styles: {
 options: {
 banner : '/* My minified css file */'
 },
 files : {
 'dist/css/style.css': ['css/**/*.css']
 }
 }
 },

connect: {
 server: {
 options: {
 hostname: 'localhost',
 port : 9999
 }
 }
 },

watch: {
 dev: {
 files : ['js/**/*', 'css/**/*'],
 tasks : ['concat:javascript', 'cssmin:styles'],
 options: {
 atBegin: true
 }
 }
 }
 });

grunt.loadNpmTasks('grunt-contrib-concat');
 grunt.loadNpmTasks('grunt-contrib-connect');
 grunt.loadNpmTasks('grunt-contrib-uglify');
 grunt.loadNpmTasks('grunt-contrib-cssmin');
 grunt.loadNpmTasks('grunt-contrib-watch');

grunt.registerTask('css', ['cssmin:styles']);

grunt.registerTask('js', ['concat:javascript', 'uglify:javascript']);

grunt.registerTask('dev', ['connect:server', 'watch:dev']);
 };

Der Aufbau dieser Datei ist relativ simpel und es sollte nach kurzer Zeit ersichtlich sein, was genau wo konfiguriert wird. Zunächst einmal haben wir die grunt.initConfig, in welcher die komplette Konfiguration vorgenommen wird. Nach dieser werden die benötigten npm Pakete über grunt.loadNpmTasks(‚PAKETNAME‘); geladen. Zuletzt werden die über die Konsole ausführbaren Tasks bestimmt. Für das Optimieren einer Website beschränke ich mich hier auf zwei Tasks sowie einen während der Entwicklung genutzen Task, welcher nach geänderten Dateien schaut und danach automatisch die anderen beiden Tasks ausführt.

Zur Verdeutlichung möchte ich dieses genauer an dem Task css erklären:
Der Befehl grunt.registerTask(‚css‘, [‚cssmin:styles‘]); ermöglicht uns auf der Konsole, den Befehl grunt css zu nutzen. Schaut man sich nochmal die Konfiguration an, so findet man unter cssmin den Punkt styles mit den Einträgen settings und files. In den Einstellungen wurde lediglich ein Banner bestimmt, welches am Anfang der minifizierten css Datei steht. Unter files sind die zu minifizierenden Dateien angegeben, wobei als Key die Zieldatei bestimmt worden ist. Alle Einstellungen der jeweiligen npm Plugins können meist direkt auf der Plugin Seite nachgesehen werden. Für unser Beispiel sind diese hier zu finden. Das Ergebnis des Konsolenbefehls grunt css sieht danach wie folgt aus:

dhemeier@dhemeier-pc:~/data/Git/GruntExample$ grunt css
 Running "cssmin:styles" (cssmin) task
 File dist/css/style.css created: 15.33 kB → 3.92 kB
Done, without errors.

An diesem Beispiel ist schon ersichtlich, dass sich das Minifizieren von JavaScript und Stylesheets lohnt. Obwohl wir hier nur die Boilerplate Dateien haben und noch keine einzige Zeile eigene Styles geschrieben haben, konnten wir die Größe der resultierenden Datei um ca. 75 % reduzieren.

Der Task js ist ähnlich aufgebaut. Allerdings besteht dieser aus zwei Aktionen. Zunächst einmal werden die einzelnen JavaScript Dateien zu einer zusammengefügt (concat:javascript), anschließend wird diese Datei dann minifiziert (uglify:javascript):

dhemeier@dhemeier-pc:~/data/Git/GruntExample$ grunt js
 Running "concat:javascript" (concat) task
 File dist/js/script.js created.

Running „uglify:javascript“ (uglify) task
>> 1 file created.

Done, without errors.

Der letzte Task funktioniert etwas anders. Während die anderen beiden Tasks nur einmal laufen und danach der Prozess beendet ist, wird bei dem Task dev ein lokaler Server erstellt, in dem man sich den aktuellen Stand der Seite direkt anschauen kann. Weiterhin überwacht dieser Task die Dateien, sodass bei einer Änderung der Quelldateien auch die minifizierten Versionen aktualisiert werden. Dadurch entfällt während der Entwicklung das manuelle Ausführen dieser Schritte. Natürlich müssen wir nun noch die index.html anpassen, sodass hier nur noch die minifizierten Versionen der Dateien verwendet werden. Das komplette Beispiel habe ich auf GitHub veröffentlicht.

Arbeitet ihr mit Grunt? Nutzt ihr andere Automatisierungstools? Ich bin gespannt auf eure Antworten! :)

Kommentare

  1. Gravatar
    Thomas Kaiser am
    sehe ich genauso wie Tobi und Mario:

    npm, bower, grunt/gulp & ruby-sass sollten auf den VServern installierbar sein.
    Im jetzigen Zustand sind die Server zu verkrüppelt und leider nutzlos für einen Workflow mit mehreren developern. Wegen ruby-sass hatte ich auch mal für eine Installation durch Mittwald angefragt und wurde mit "mit unserem Sicherheitskonzept nicht vereinbar" abgewimmelt...

    In dem Zusammenhang ist die Aussage, "die Entwicklung findet meistens lokal statt und auf dem Server braucht man das nicht" schon ein bisschen armselig.

    Und wenn wir schon dabei sind: nano, ping, nslookup ... ??

    Viele Grüße, Thomas Kaiser



    Antworten
  2. Gravatar
    Mario Kowalski am

    Ein Install auf einem Server wäre auch auf meiner Wunschliste

    Antworten
  3. Gravatar
    Tobi am

    Hallo Dennis,

    Grunt/Gulp, npm und bower machen alle Sinn auf dem Server, wenn man einen vernünftigen Deployment-Prozess einsetzen möchte.
    Wir commiten zb. keine minifizierten oder konkatenierten Dateien in unsere Repositories. Sondern der Code wird auf den Servern (Staging oder Live) von unserem Deploy-Prozess ausgecheckt (in diesem Fall nutzen wir rocketeer) und dann alle notwendigen Dependencies für npm und bower aufgelöst und dann noch grunt ausgeführt.

    Daher wäre es schon schön wenn man zumindest ab den VServern Tools wie npm, bower und grunt/gulp nutzen könnte.
    Ihr seid sehr professionelle Hoster und könntet so einen professionelle Deployment-Ansätlze für professionelle Entwickler ermöglichen ;)

    Gruß
    Tobi

    Antworten
  4. Gravatar
    Jan am

    Grunt out und Gulp ftw?

    Wie war das nochmal: Wenn man keine Ahnung hat, …?

    Antworten
  5. Gravatar
    Peter am

    Ist ja schon ein bisschen fail… Grunt ist doch schon wieder out… Gulp ftw

    Antworten
  6. Gravatar
    Thomas Hydell am

    Persönlich nutze ich Grunt auf meinem Server. Ein Bekannter hat bei euch ein ManagedServer gemietet und würde es auch gerne nutzen. Wäre es möglich auch dort Grunt zu installieren?

    Antworten
    1. Dennis Hemeier am

      Hallo Thomas,

      die Entwicklung neuer Webseiten mithilfe von Grunt findet in der Regel in deiner lokalen Entwicklungsumgebung statt. Dort kannst du natürlich Grunt verwenden.
      Eine Installation auf dem Server ist für diesen Fall daher nicht notwendig.

      Viele Grüße
      Dennis vom Mittwald Team

      Antworten

Kommentar hinzufügen

    Hilfe & Kontakt

    Support-Hotline
    +49 (0) 800/440-3000

    E-Mail
    support@mittwald.de