Angular 2: Warum Node-Module und webpack das Leben drastisch vereinfachen

Zum Darstellen von Modulen unter JavaScript haben sich in den letzten Jahren ein paar wenige Modulsysteme etabliert, welche derzeit nebeneinander co-existieren. Dazu gehören unter anderen CommonJS-Module, die Asynchronous Module Definition (AMD) oder das System-Format. Daneben liegt mit der Universal Module Definition (UMD) seit einiger Zeit ein Vorschlag zum Exportieren von Modulen in einer zu AMD und CommonJS kompatiblen Weise vor. Das Modul-System, welches ab EcmaScript 2015 vorherrscht, wird in der Regel mittels Transpilierung in eines der zuvor genannten übergeführt, damit der geschriebene Code in handelsüblichen Browsern läuft.

CommonJS als defacto-Standard (auf der Serverseite)

Serverseitig werden vor allem CommonJS-Module genutzt. Das liegt auch daran, dass das NodeJS-Modulsystem auf diesem defacto-Standard basiert. Eine wichtige Eigenschaft von NodeJS-Modulen ist, dass diese selbstbeschreibend sind. Über die Datei package.json beschreiben sie unter anderem ihre Abhängigkeiten. Dies versetzt den weit verbreitenden Package-Manager npm in die Lage, sämtliche Abhängigkeiten beim Beziehen eines Paketes mitzuladen. Dies gilt auch für die Abhängigkeiten der Abhängigkeiten usw.

Für das Auflösen dieser Abhängigkeiten zur Laufzeit existieren klare Regeln, die davon ausgehen, dass sich die benötigten Bibliotheken im Ordner node_modules des aktuellen Paketes oder eines übergeordneten Paketes befinden. Dies macht Konfigurationsdateien, aus denen die Positionen der einzelnen Abhängigkeiten hervorgehen, überflüssig. Genausowenig muss der Anwendungsentwickler über diese Interna Bescheid wissen. Stattdessen kann er via npm geladene Bibliotheken im Sinne der OOP und Komponentenorientierung als Blackbox betrachten.

Herausforderungen beim NodeJS-Modulsystem

Bei all dem Lobgesang auf das NodeJS-Modulsystem sollen auch seine Nachteile nicht verheimlicht werden: Eine Herausforderung, die unter Windows-Systemen zu Tage tritt, sind lange Pfad-Namen. Diese ergeben sich durch hierarchische Schachtelung von Modulen. Ein Paket kann in seinem Ordner node_modules Abhängigkeiten haben, welche wieder in ihren Ordnern node_modules Abhängigkeiten haben können usw. Da die Pfadlänge bei Windows-Systemen leider begrenzt ist, führt dies ggf. zu Problemen. Eine weitere Herausforderung ist die Tatsache, dass das zugrundeliegende CommonJS-Modul-System davon ausgeht, dass die Laufzeitumgebung Abhängigkeiten synchron laden kann. Serverseitig ist das auch kein Problem aber in Browser-Anwendungen kommt man damit nicht weit. Diese fordern nämlich weitere Pakete in der Regel asynchron an, um das Einfrieren der GUI zu vermeiden.

Für beide Herausforderungen gibt es glücklicherweise Lösungen. Die Pfadlänge versucht npm seit Version 3 zu minimieren, indem es Abhängigkeiten möglichst weit oben in der Ordnerstruktur platziert. Das ist möglich, weil Abhängigkeiten, wie zuvor erwähnt, auch im Ordner node_modules von übergeordneten Modulen gefunden werden. Solange es keine zwei Module gibt, die die selbe Abhängigkeit in gänzlich unterschiedlichen nicht zueinander kompatiblen Versionen benötigen, können Abhängigkeiten also auf oberster Ebene platziert werden. Informationen zur Organisation von Bibliotheken ab npm 3 findet man hier.

Für die Diskrepanz zwischen asynchronem Laden in Browser-Anwendungen und synchronem Laden mittels CommonJS existieren zwei Lösungen: Zum einen erlauben Module-Loader das dynamische Umschreiben von Paketen, sodass diese Abhängigkeiten doch asynchron auflösen. Ein populäres Beispiel hierfür ist RequireJS. Zum anderen erlauben Werkzeuge, wie browserify und webpack, ein Bundling von NodeJS-Modulen in einer Art und Weise, die sich direkt im Browser ausführen lässt. Da moderne Web-Anwendungen aus Gründen der Performance sowieso auf Bundling setzen, stellt der Einsatz solcher Werkzeuge ohnehin eine Notwendigkeit dar.

webpack

Unter den verfügbaren Bundlern sticht webpack hervor. Es bietet einige nette Möglichkeiten, wie das Aufteilen des Bundles auf mehrere Teile (Chunks). Diese können bei Bedarf von der Browser-Anwendung asynchron nachgeladen werden. Darüber hinaus spielt webpack den Bundling-Gedanken sehr weit und erlaubt sogar das Aufnehmen unterschiedlicher Dateitypen, wie HTML-Templates sowie CSS-Dateien, in ein und das selbe Bundle. Möglich macht das die Umwandlung sämtlicher Formate in JavaScript. Auch das Transpilieren von TypeScript und anderen Sprachen nach JavaScript übernimmt webpack über Komponenten, die sich Loader nennen. Generell kann webpack viele Aufagaben von Build-Lösungen, wie Gulp oder Grunt, übernehmen. Während der Entwickler mit letzteren in imparativer Manier die einzelnen Aufgaben Schritt für Schritt festlegen muss, arbeitet er mit webpack auf deklarativer Weise. Dies macht die Konfiguration kürzer und einfacher. In Fällen, in denen der deklarative Ansatz nicht ausreicht, kann webpack in Gulp- und Grunt-Tasks eingebunden werden.

Zusammenfassung und Ausblick

NodeJS-Module bieten einige Vorteile:

  • Sie basieren auf dem CommonJS-Standard
  • Sie sind selbstbeschreibend und erlauben dem Entwickler, Pakete als Blackbox zu betrachten
  • Abhängigkeiten (und deren Abhängigkeiten etc.) können via npm automatisch bezogen werden
  • Abhängigkeiten können aufgrund von Konventionen zur Laufzeit automatisch geladen werden

Dank Bundling kann das für die Serverseite entwickelte NodeJS-Modul-System auch in Browseranwendungen genutzt werden. Ein vielversprechender Bundler ist webpack. Jene, die nun Neugierig auf den Einsatz von Angular 2 mit webpack sind, finden Infos dazu in einem meiner nachfolgenden Beiträge.

 

Schulung und Beratung

Angular 2

Datenbindung, Formulare, Validierung, Routing, HTTP, Komponenten, ...

Details

Migration auf Angular 2

Bestehende Projekte auf Angular 2 migrieren, ngUpgrade, ...

Details

Progressive Web-Apps mit Angular 2

InHouse-Schulung und/oder Beratung maßgeschneidert für Ihre Lernziele

Details

Architektur-Workshop

Interaktiver Prototyp-Workshop für Ihre Anwendung

Details

Entity Framework (EF)

Datenzugriff mit Entity Framework, Mapping-Szenarien, CRUD, Transaktionen, Migrations, Stored Procedures, Vererbung, Neuerungen in Version 7

Details

Angular 2: Deep Dive

Erweiterte Aspekte von Angular 2

Details

ASP.NET WebAPI

Web APIs mit ASP.NET, HTTP, REST, Security, Formatter, Tracing, OData, Streaming

Details

Web APIs mit ASP.NET MVC 6

Web APIs mit ASP.NET, HTTP, REST, Security, Formatter, Tracing, OData, Streaming

Details

Moderne Security-Szenarien für Web APIs

OAuth 2, OpenId Connect, JWT, Spielarten und Flows, ...

Details

Weitere Schulungen ...