JavaScript für Java Enterprise-Entwickler – Teil 2 – Ein Buildprozess mit Grunt

Dieser Blogbeitrag basiert auf einem Vortrag, den Norman Erck und ich auf einer Veranstaltung der Java User Group Hamburg (JUGHH) gehalten haben.

Enterprise-Entwicklung ist in der Regel Teamarbeit. Eine umfangreiche Codebasis muss wartbar bleiben. Dies gilt auch für Projekte, in denen große Teile des Codes in JS entwickelt werden.

GRUNT

JS-Code gilt für viele Entwickler als nicht wartbar, was daran liegt, dass Konzepte, die im Java-Umfeld eigentlich als selbstverständlich gelten, für JS-Code missachtet werden. Zu diesen Konzepten gehören einfache Dinge wie Coding Conventions, Continous Integration und testgetriebene Entwicklung.

Ein Build-Systems dient dazu, wiederkehrende Aufgaben zu automatisieren. Dafür eignet sich theoretisch sogar ein einfaches Shell-Script. Im Java Enterprise-Umfeld haben sich jedoch Build-Systeme wie Maven durchgesetzt, mit dem sich auch Frontend-Artefakte integrieren lassen.

In einem Projekt, in dem sich der Frontend-Anteil entkoppelt vom Backend-Teil bauen lässt, kann man jedoch auch ein Build-System verwenden, das komplett auf JS aufsetzt, z.B. Grunt.

Grunt ist ein taskbasiertes Buildsystem, das über die Kommandozeile bedient wird. Es basiert auf Node.js und dem dazu gehörenden Package Manager NPM für Node Packaged Modules. Hat man Node.js installiert, lässt sich Grunt über NPM global (für alle Nutzer) installieren.

[bash]
sudo npm install –g grunt-cli
[/bash]

In einem Beispiel-Projekt ist ein sehr einfacher Build-Prozess exemplarisch implementiert.

Dieser Build-Prozess besteht nur aus drei Schritten:
Build-Prozess

  • Linting mit JSHint
  • Testing mit Jasmine
  • Dokumentieren mit JSDoc
WEAVE 03/2013
Ein Artikel, der Grunt für eine automatisierte Webperformance-Optimierung nutzt, ist in der aktuellen WEAVE 03/2013 abgedruckt. Dort zeige ich, wie man einer Webanwendung durch ein flinkes Build-Script Beine machen kann.

Linting findet mit JSHint statt. JSHint ist ein Community-Projekt, das dem Vorbild JSLint ähnelt. Beide Tools untersuchen JS-Quellen nach potentiellen Fehlern oder Problemverursachern. Darüber hinaus lassen sie sich einsetzen, um die Coding Conventions eines Teams durchzusetzen.

Jasmine ist ein Testframework, das den BDD-Ansatz verfolgt. Es basiert auf RSpec und JSpec. Da es keine Abhängigkeit zu einem Webbrowser hat, lässt es sich sehr gut in einem flinken Build einsetzen.

JsDoc Toolkit ist eine Applikation, die für JS-Code das leistet, was JavaDoc für Java-Code leistet: Es generiert eine Website auf Basis eines Templates, in welcher der Quellcode einer JS-Anwendung dokumentiert wird. Als Basis für die Dokumentation werden Kommentare im JS-Code verwendet.

Ein Build-Script ist in Grunt eine JS-Datei, ist also in der gleichen Sprache formuliert, in der auch der Quellcode des Projekts geschrieben ist. Grunt verzichtet also auf schlecht zu lesende XML-Dateien o.ä.

Das Build-Script eines Projekts befindet sich in der Datei Gruntfile.js.

[javascript]
module.exports = function(grunt) {

grunt.initConfig({
watch: {
files: [‚Gruntfile.js‘, ’spec/**/*js‘, ’src/**/*js‘],
tasks: [‚jshint‘, ‚jasmine‘]
},
jsdoc: {
dist: {
src: [’src/*.js‘, ‚test/*.js‘],
dest: ‚doc‘
}
},
jasmine: {
pivotal: {
src: ’src/**/*.js‘,
options: {
specs: ’spec/*Spec.js‘,
helpers: ’spec/*Helper.js‘
}
}

},
jshint: {
options: {
curly: true,
eqeqeq: true,
eqnull: true,
browser: true
},
all: [’src/*.js‘, ‚Gruntfile.js‘]
}
});

grunt.loadNpmTasks(‚grunt-contrib-jasmine‘);
grunt.loadNpmTasks(‚grunt-contrib-jshint‘);
grunt.loadNpmTasks(‚grunt-contrib-watch‘);
grunt.loadNpmTasks(‚grunt-jsdoc‘);

// Default task.
grunt.registerTask(‚default‘, [‚jshint‘, ‚jasmine‘, ‚jsdoc‘]);

};
[/javascript]

In dieser Datei werden im Task „default“ die genannten drei Build-Schritte registriert: grunt.registerTask('default', ['jshint', 'jasmine', 'jsdoc']);.
Jeder dieser Schritte wird zudem in einem eigenen Block konfiguriert. Exemplarisch betrachten wir die Konfiguration des JSHint-Tasks.

[javascript]
jshint: {
options: {
curly: true,
eqeqeq: true,
eqnull: true,
browser: true
},
all: [’src/*.js‘, ‚Gruntfile.js‘]
}
[/javascript]

JSHint wird mit einigen Regeln initialisert. Beispielsweise sollen Blöcke, die durch Bedingungen oder Schleifen angesprochen werden, immer in geschweiften Klammern stehen (curly: true) und Gleichheit soll ohne automatische Typanpassung überpüft werden (eqeqeq: true). Diese Regeln werden auf alle JS-Dateien im src-Verzeichnis und auf das Build-Script selbst, das eine gültige JS-Datei ist, angewendet (all: ['src/*.js', 'Gruntfile.js']).

Man startet das Build-Script, indem man auf der Kommandozeile grunt aufruft.

[bash]
$ grunt
Running "jshint:all" (jshint) task
>> 2 files lint free.

Running "jasmine:pivotal" (jasmine) task
Testing jasmine specs via phantom
2 specs, 0 failures in 0.001s.
>> 0 failures

Running "jsdoc:dist" (jsdoc) task
Documentation generated to /Users/simonox/js-workshop/grunt-jasmine-bar/doc
Done, without errors.
[/bash]

Neben dem Default-Task gibt es auch einen Watch-Task. Dieser lässt sich über grunt watch aufrufen. Wenn sich eine Datei im Projekt verändert, dann wird automatisch ein Build angestoßen. Im Watch-Modus werden hier allerdings lediglich JSHint und Jasmine, nicht jedoch JSDoc aufgerufen, um die Roundtrip-Zeit zu verkürzen.

[javascript]
watch: {
files: [‚Gruntfile.js‘, ’spec/**/*js‘, ’src/**/*js‘],
tasks: [‚jshint‘, ‚jasmine‘]
}
[/javascript]

Wie man an diesem einfachen Beispiel sieht, lässt sich ein geordneter Build, der hilft, die Softwarequalität zu verbessern, auch in JS umsetzen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.