Kolumne: The Good Parts

Paketverwaltung für den Browser
Kommentare

JavaScript-Projekte werden von Tag zu Tag komplexer und größer. Mit dieser Entwicklung geht die Notwendigkeit des Einsatzes externer Libraries sowie Frameworks einher. Diese ermöglichen es, den gewünschten Funktionsumfang schnell und effizient zu erzielen. Im JavaScript-Umfeld existiert eine geradezu aberwitzige Menge an unterschiedlichsten kleinen Bibliotheken, die die tägliche Arbeit erleichtern. Durch die Verwendung solcher Bibliotheken entsteht jedoch auch neue Komplexität: das Management dieser unterschiedlichen Pakete. Der Paketmanager Bower hilft dabei, damit dieser Prozess nicht in Arbeit ausartet.

Es existiert kaum eine Sprache im Bereich der Webentwicklung, die einen derart großen Fundus an Komponenten, Bibliotheken und kleinen Helferlein aufzuweisen hat, wie JavaScript. Viele dieser externen Ressourcen stehen unter Lizenzen bereit, die nahezu jedem Projekt – ob kommerziell oder Open Source – die Verwendung gestatten. Umso interessanter ist es, diese Pakete einzusetzen, um schneller an das gewünschte Entwicklungsziel zu gelangen. Häufig ist es einfach nicht erforderlich, das Rad neu zu erfinden.

Durch die schiere Anzahl an unterschiedlichen Bibliotheken und Codeschnipseln ergeben sich diverse neue Probleme. Oft sind die besagten JavaScript-Bibliotheken relativ kompakt und auf exakt einen Einsatzzweck spezialisiert. Natürlich gibt es auch größere Framework-ähnliche Vertreter wie Backbone, Angular, jQuery und Ember, jedoch verwendet man von diesen häufig nur ein einziges, während diverse Variationen unterschiedlichster sonstiger Hilfsmittel zum Einsatz kommen. Es gilt also den Überblick über aktuelle Versionen aller in Verwendung befindlicher Komponenten zu behalten, diese entsprechend bereit zu stellen und mit der eigenen Applikation zu verknüpfen. Diese Tätigkeit kann sehr schnell in Arbeit ausarten, die niemand gerne macht.

Das Ergebnis: Häufig wird der Einsatz externer Bibliotheken gescheut, es werden veraltete Versionen eingesetzt, die möglicherweise bekannte Sicherheitslücken haben, oder es wird freiwillig auf elementare neue Features verzichtet.

Die Lösung: Der Einsatz eines Systems, das derlei Verwaltungstätigkeiten übernimmt und dabei nahezu automatisch die lästige Arbeit erledigt. Bower [1] ist ein Paketmanager, der von Twitter genau zu diesem Zweck entwickelt wurde. Neben einem großen Repository an Paketen verfügt Bower außerdem über alle nötigen Mittel zur Definition, Installation und Verwaltung verschiedenster externer Abhängigkeiten.

Bower

Im Vergleich zu anderen Systemen dieser Art legt Bower seinen Schwerpunkt auf das Paketmanagement. Bower verwaltet externe Abhängigkeiten. Sonst tut es nichts. Es ist nicht dafür verantwortlich, Code zusammenzufügen oder gar zu minifizieren. Es löst auch nicht mittels require.js [2] oder ähnlichen Tools bibliotheksinterne Abhängigkeiten auf. Bower ist nur dafür zuständig, externe Abhängigkeiten in definierten Versionen zu beschaffen und bereit zu stellen. Für alles weitere sorgt der Entwickler selbst, ggf. mit anderen Tools wie Grunt [3].

Diese Herangehensweise hat große Vorteile gegenüber alternativen, ähnlich gelagerten Systemen. Denn hierdurch ist es Bower möglich, sich in nahezu jede bestehende Infrastruktur einzufügen. Es erlaubt die reibungslose Zusammenarbeit mit Build-Systemen wie Grunt, einer Abhängigkeitsverwaltung wie require.js und Minifyern wie UglifyJS [4].

Installation

Bower selbst ist in JavaScript geschrieben. Unter Zuhilfenahme von Node.js [5] erledigt es seine Aufgaben gezielt von der Kommandozeile aus. Nachdem Node.js installiert ist, steht automatisch auch dessen Paketverwaltungssystem npm zur Verfügung. Mit diesem lässt sich Bower bequem und unkompliziert installieren:

npm install -g bower

Der Parameter -g bewirkt eine globale Installation. Dies bedeutet, dass Bower anschließend von überall im System erreichbar ist. Im Normalfall installiert npm seine Pakete lokal zum aktuellen Projekt, was natürlich in diesem Fall nicht gewünscht ist, da es sich um ein generelles Tool handelt, das systemweit installiert werden soll.

Bower einsetzen

Nach der Installation von Bower steht das Tool als gleichnamiges Kommandozeilenwerkzeug zur Verfügung:

$ bower  Usage: bower  [] []

Unterschiedlichste Aktionen sind durch entsprechende Kommandos abrufbar. Ein häufiger Fall ist das Durchsuchen von Bowers-Paket-Repository nach einem spezifischen Paket. Die Aktion search ist hierfür zuständig. Im folgenden Beispiel wird nach allen Paketen mit der Bezeichnung jquery im Namen gesucht:

$ bower search jquery  Search results: jquery git://github.com/components/jquery.git jquery-ui git://github.com/components/jqueryui jquery.cookie git://github.com/carhartl/jquery-cookie.git ...

Das Ergebnis ist eine längliche Liste aller verfügbaren jQuery-Pakete. Repräsentiert ist ein Paket immer durch einen eindeutigen Namen, der als Erstes in der Ergebnisliste auftaucht, gefolgt von der Adresse eines Git Repositorys, unter dem der Quelltext verfügbar ist. Wichtig ist hierbei, dass Bowers Repository selbst die Daten der jeweiligen Pakete nicht spiegelt, sondern lediglich für jede publizierte Version auf das Repository und einen spezifischen Commit verweist. Somit kann jede Version problemlos von Bower abgerufen werden, ohne dass ein großes Archiv mit unterschiedlichsten Quelltextversionen gepflegt werden muss. Auf dem eigenen Rechner legt Bower automatisch einen Cache an, damit Paketinhalte nicht dauerhaft erneut heruntergeladen werden müssen.

Neben der Kommandozeile existiert außerdem die Möglichkeit, im Browser [6] das Repository zu durchsuchen, um gewünschte Pakete zu entdecken. Zum Zeitpunkt der Drucklegung des Artikels existieren 3 336 Pakete im Repository – Tendenz steigend.

Aufmacherbild: Greek Ionic Column von Shutterstock / Radu Bercan

[ header = Pakete installieren ]

Pakete installieren

Ist der Paketname erst einmal bekannt, ist die Installation von Abhängigkeiten mit der install-Aktion ein Kinderspiel:

bower install jquery

In diesem Beispiel wird jQuery als Abhängigkeit installiert. Die Installation erfolgt lokal zum aktuellen Verzeichnis, in dem das bower-Kommando aufgerufen wurde. Im Normalfall sollte dies das Root-Verzeichnis des Projekts sein, an dem gearbeitet wird. Bower erstellt hier einen neuen Ordner mit dem Namen bower_components und installiert dort hinein das angeforderte Paket. Um jQuery anschließend zu verwenden, muss die Bibliothek z. B. nur noch mittels -Tag in das Projekt eingebettet werden:


Zur Erinnerung: Bower installiert und verwaltet lediglich Pakete; es ist nicht für das Laden oder Zusammenführen eben jener zuständig. Das bedeutet, für die Integration in die Software ist der Entwickler selbst verantwortlich. Dies kann auf den unterschiedlichsten Wegen passieren. Mittels -Tag, durch Verwendung von require.js, durch komplexe Build-Prozesse, die durch Grunt gesteuert werden, oder auf jede andere beliebige Art und Weise.

Neben eindeutigen Paketidentifikatoren ist Bower ebenfalls noch in der Lage, aus anderen Quellen Pakete zu installieren:

1. Durch Spezifikation eines Git-Repositorys:

bower install https://github.com/marionettejs/backbone.marionette.git

2. Durch Spezifikation eines Links zu einer einzelnen Datei:

bower install http://backbonejs.org/backbone.js

3. Durch Spezifikation eines lokalen Ordners, in dem sich ein Paket befindet:

bower install ~/development/another/cool/project

4. Durch Spezifikation eines Benutzer-, sowie Repositorynamens auf GitHub:

bower install jakobwesthoff/sprintf.js

Wie sich zeigt, ist es demnach ebenfalls recht leicht möglich, mit Bower Pakete zu verwalten, die nicht Bestandteil des offiziellen Repositorys sind. Es ist jedoch wichtig, darauf hinzuweisen, dass offiziell verfügbare Pakete solchen aus alternativen Quellen nahezu immer vorzuziehen sind, da diese eindeutige Versionsnummern sowie eine entsprechende Releasekontrolle mitbringen, die bei alternativen Quellen häufig fehlen.

Spezielle Versionen

Nicht immer ist die neueste Version einer Bibliothek die richtige. Häufig ist das aktuelle Projekt abhängig von einer speziellen Versionsnummer einer anderen Bibliothek. Bei Paketen aus dem Repository kann die gewünschte Versionsnummer einfach mittels einer Raute (#) an den Paketidentifikator angehängt werden. Somit weiß Bower, welche Version es installieren muss. Unterstützt wird hierbei die gesamte Palette an Versionsnummern, die durch node-semver [7] verarbeitet werden kann. Eine entsprechende Liste findet sich auf den Projektseiten.

Mithilfe einer solchen Angabe kann man von Bower z. B. verlangen, jQuery in der letzten Version vor 2.0 zu installieren, da noch die Kompatibilität mit älteren Browsern benötigt wird:

bower install jquery#1.x

Interessant wird dies natürlich besonders in Kombination mit automatischen Updates von externen Bibliotheken. Um zu erfahren, in welchen Versionen ein Paket überhaupt verfügbar ist, kommt die info-Aktion zum Einsatz. Diese listet fein säuberlich alle verfügbaren Versionen eines Pakets auf:

$ bower info jquery  jquery Versions: - 2.0.3 - 2.0.2 - 2.0.1 - 2.0.0 - 1.10.2 - 1.10.1 - 1.10.0 ...

Updates

Bower ist nicht nur im Stande, Bibliotheken einmalig zu installieren, sondern ebenfalls innerhalb definierter Versionsgrenzen automatisiert zu aktualisieren. Ein einfacher Aufruf der update-Aktion veranlasst das System, alle aktuell installierten Komponenten auf den neuesten zulässigen Stand zu bringen. Im Fall von Paketen, die ohne spezifische Versionsnummer installiert wurden, bedeutet dies, dass sie auf die aktuellste verfügbare Version angehoben werden. Häufig ist dies nicht wünschenswert, daher sollte mindestens die Major-Version, wenn nicht sogar die Minor-Version, festgelegt werden, um bei möglichen Brüchen der Abwärtskompatibilität einer Bibliothek selbst ein Auge auf den Updateprozess haben zu können. Das zuvor gezeigte Beispiel zur Installation von jQuery in der Version 1.x demonstriert diesen Prozess. Auch nach einem update-Aufruf ist jQuery immer noch garantiert in der Major-Version 1 installiert:

bower update

Allerdings wird Bower dafür Sorge tragen, dass Minor-Version sowie Patch-Level auf den neuesten möglichen Stand aktualisiert werden. Neben einem vollständigen Update aller Komponenten existiert durch Angabe eines Paketidentifikators außerdem die Möglichkeit, separat lediglich einzelne Pakete zu aktualisieren:

bower update jquery

Abhängigkeiten im Projektkontext

Obwohl alle bisher gezeigten Fähigkeiten von Bower äußerst nützlich sind, so scheint die manuelle Installation von Paketen auf der Kommandozeile doch wenig pragmatisch im Kontext eines größeren Projekts. Hierfür muss eine eindeutige Anlaufstelle für Abhängigkeiten geschaffen werden, von der aus Bower alle nötigen Verwaltungsinformationen beziehen kann, ohne dass diese bei jeder Aktualisierung einer externen Abhängigkeit ebenfalls direkt im Versionsverwaltungssystem der eigenen Software landet.

Glücklicherweise gibt es eine Lösung für dieses Problem: bower.json. Bower besitzt eine eigene Konfigurationssprache, die es ermöglicht, Abhängigkeiten bequem innerhalb einer JSON-Datei zu verwalten. Hierbei orientiert sich deren Inhalt stark an anderen Paketmanagern wie npm oder Composer. Der Inhalt der Datei selbst ist ein JSON-Objekt mit einem oder mehreren Schlüsseln. Der einzige hierbei Erzwungene ist der Name des Pakets (name). Alle weiteren Schlüssel wie version, location, description, authors und license sind optional. Eine vollständige Liste kann dem aktuellen Work-in-Progress der Bower-Spezifikation [7] entnommen werden.

Besonders interessant sind jedoch die beiden Schlüssel dependencies und devDependencies. Diese beinhalten wiederum selbst ein JSON-Objekt, das beliebige Abhängigkeiten sowie gewünschte Versionen beschreibt. Die zugehörige bower.json einer Backbone-Applikation sähe demnach der in Listing 1 abgedruckten Datei äußerst ähnlich.

{
  "name": "My Cool Backbone App",
  "version": "0.0.1",
  "dependencies": {
    "backbone": "~1.0.0",
    "underscore": "~1.5.1",
    "jquery": "~2.0.3",
    "marionette": "~1.0.4"
  }
}

Ist eine entsprechende Definition im Root-Verzeichnis des Projekts hinterlegt, so lassen sich alle nötigen Abhängigkeiten durch einen einfachen Aufruf von bower install bzw. bower update installieren bzw. auf den neuesten Stand bringen. Hierbei wird automatisch ein entsprechendes bower_components-Verzeichnis angelegt, in das alle Abhängigkeiten installiert werden.

Dabei sollte niemals das Verzeichnis mit den installierten Komponenten in das Versionsverwaltungssystem des aktuellen Projekts eingecheckt werden, sondern lediglich die entsprechende bower.json-Datei.[ header = Die Kommandozeile und bower.json ]

Die Kommandozeile und bower.json

Es ist nicht jedermanns Sache, direkt innerhalb der bower.json-Datei Einträge zu verändern. Hierzu muss nicht nur die Struktur bekannt sein, sondern ebenfalls noch die gewünschte Versionierung der einzelnen Pakete. Was aber, wenn zum Start eines Projekts lediglich die aktuellste Version einer Bibliothek hinzugefügt werden soll, ohne dass die Versionsnummer selbst wirklich relevant ist? Bower bringt einige nützliche Kommandozeilenbefehle mit, die bei der Erstellung und Verwaltung des bower.json-Manifests helfen. Zum Projektstart kann die init-Aktion ein neues Manifest erstellen, ohne dass der Entwickler selbst in Kontakt mit dem JSON-Format dieser Datei kommt:

$ bower init  [?] name: My Cool Backbone App [?] version: 0.0.1 [?] main file: [?] set currently installed components as dependencies? No [?] add commonly ignored files to ignore list? No

Nachdem Bower einige standardisierte Fragen abgearbeitet hat, erstellt es automatisch das passende Manifest. Sollten vor diesem Zeitpunkt bereits Abhängigkeiten mittels Bower installiert worden sein, so bietet die Aktion sogar an, diese in das Manifest zu übernehmen. Ist die Datei einmal angelegt, so kann Bower bei der Installation neuer Pakete direkt angewiesen werden, diese als Abhängigkeit zu hinterlegen und somit für die weitere Verwendung zu sichern. Signalisiert wird dieser Wunsch dem System durch Verwendung des –save-Arguments:

bower install backbone --save

Durch diesen Befehl wird nicht nur das Backbone-Paket installiert, sondern ebenfalls der dependencies-Schlüssel des bower.json-Manifests aktualisiert.

Konfiguration

Zusätzlich zu entsprechenden Kommandozeilenoptionen unterstützt Bower außerdem die Konfiguration mittels einer oder mehrerer Dateien mit dem Namen .bowerrc (der vorangestellte Punkt ist erforderlich, Bower wird die Datei ansonsten ignorieren). Bei jedem Aufruf macht Bower sich auf die Suche nach verschiedensten Ausprägungen dieser Konfigurationsdatei, wobei es alle gefundenen Optionen kombiniert. Hierbei wird die folgende Prioritätenreihenfolge zugrunde gelegt:

  • Konfigurationsoptionen, die mittels –config.* übergeben wurden.
  • Der Inhalt der .bowerrc-Datei im aktuellen Arbeitsverzeichnis.
  • Der Inhalt aller .bowerrc-Dateien auf dem Weg des Verzeichnisbaums nach oben.
  • Der Inhalt der .bowerrc-Datei im Home-Verzeichnis des Benutzers.

Es existiert eine Vielzahl unterschiedlicher Optionen, die mithilfe dieser Konfigurationsdateien beeinflusst werden können. So lässt sich z. B. mit der directory-Option das Zielverzeichnis für installierte Pakete verändern. Ist eine Installation von Abhängigkeiten in das vendor-Verzeichnis anstelle des bower_components-Verzeichnisses gewünscht, so lässt sich das z. B. durch folgende Konfiguration leicht bewerkstelligen:

{ directory: "vendor" }

Neben dieser Option existieren weitere, wie z. B. der Schlüssel registry, mit dem sich der URL des Standard-Paket-Repositorys überschreiben lässt. Auf diesem Wege kann leicht ein firmeninterner Paketserver betrieben werden, um auch interne Applikationsbibliotheken mittels Bower zu verwalten. Eine vollständige Liste aller möglichen Konfigurationsoptionen findet sich in der bereits erwähnten Bower-Spezifikation [7].

Fazit

Bower stellt eine saubere und funktionale Lösung zur Verwaltung von Paketen dar. Neben Systemen wie npm spezialisiert es sich hierbei nicht auf ein einziges System zum Management von Abhängigkeiten der Pakete untereinander, wie CommonJs-Module oder AMD, sondern überlässt die Integration vollständig dem Entwickler selbst. Hierdurch lässt es sich leicht in bestehende Infrastrukturen integrieren und ist auch in Zukunft eine sichere Bank in Sachen Paketverwaltung. Bowers größter Konkurrent, Component [8], geht hierbei einen etwas anderen Weg, indem es die Integration mit entsprechenden Systemen anbietet. Component installiert zudem sehr viel spezifischer nur die benötigten Komponenten einer Bibliothek, wohingegen Bower ein Abbild des zugehörigen Git Repositorys bereitstellt. Dies ermöglicht Bower die schnelle und einfache Integration in bereits bestehende Bibliotheken, wohingegen Component häufig die Anpassung existierender Strukturen erfordert.

Auf welches Paketverwaltungssystem letztlich die Entscheidung auch fallen mag, Bower stellt einen zukunftssicheren, pragmatischen und funktionalen Ansatz dar, der uns innerhalb der JavaScript-Welt sicherlich noch geraume Zeit erhalten bleiben wird.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -