04.09.2018

Hilfe, ich muss JavaScript programmieren!

Hilfe, ich muss JavaScript programmieren!

Wer professionelle Webanwendungen bauen will, kommt an JavaScript nicht vorbei. Für viele Nicht-JavaScript-Entwicklerinnen und -Entwickler ist die Vorstellung, mit JavaScript programmieren zu müssen, aber immer noch ein Graus. Zum einen bringt die Sprache selber einige Fallstricke und „Kuriositäten“ mit. Darüber hinaus erscheint aber auch das Ökosystem, das um die Sprache herum existiert, also Frameworks, Libraries und Tools, unüberschaubar groß und wenig nachhaltig. Der richtige Einstieg ist dadurch oftmals sehr schwierig. Dieser Artikel soll eine Orientierung geben, in dem er die wichtigsten Werkzeuge grob vorstellt und einordnet.

Dieser Artikel erschien im "Java Aktuell"-Magazin, Ausgabe 05/2018". Die Ausgabe kann als PDF heruntergeladen werden

Das JavaScript Ökosystem ist sehr groß und sehr schnelllebig. Das macht es für Neulinge nicht einfach und selbst erfahrene JavaScript Entwicklerinnen und -Entwickler haben Mühe, darin die Orientierung zu behalten und mit der sehr schnellen Weiterentwicklung Schritt zu halten. Das hat sich in denen vergangenen Jahren in dem Ausdruck „JavaScript Fatique“, also „JavaScript Erschöpfung“ manifestiert. Bevor wir uns auf den Weg durch das Ökosystem machen, und ansehen, welche Tools wir wofür brauchen, wollen wir aber zunächst der Frage nachgehen, warum es sich überhaupt lohnt, diesen Weg zu gehen und sich mit JavaScript zu beschäftigen? Können wir nicht einfach bei unseren bekannten Verfahren, etwa Spring MVC oder JEE bleiben und Webanwendungen bauen, die mittels einer Template-Sprache auf dem Server gerendert werden? Hier kennen wir immerhin die Sprache, die Frameworks, die Tools samt ihrer Stärken und Schwächen. Die Antwort auf diese Frage ist mehrschichtig. Wir möchten Anwenderinnen und Anwender den bestmöglichen Nutzungskomfort bieten, im Optimalfall sollte sich eine Webanwendung, nicht von einer Desktopanwendung unterscheiden. Insbesondere soll die Anwendung sehr schnell auf Benutzerinteraktionen reagieren, auf diversen Geräten mit unterschiedlichen Betriebssystemen gut aussehen, und am besten auch dann noch funktionieren, wenn die Internet-Verbindung gerade nicht besteht. Moderne Web-Anwendungen, wie zum Beispiel Spotify , Outlook oder das Prototype-Tool Figma erfüllen diese Ansprüche. Solche Anwendungen sind aber nur denkbar, wenn sie direkt auf dem Client, also im Browser, ausgeführt werden. Und die Sprache im Browser ist JavaScript. Wenn wir also Anwendungen bauen wollen, die im Browser laufen, müssen wir uns wohl oder übel damit beschäftigen. Im übrigen wird der Browser zunehmen auch für Anwendungen interessant, die „früher“ klassischerweise im Desktop liefen. Die oben genannten Anwendungen sind ein Beispiel dafür, aber auch In-House-Anwendungen werden immer häufiger als Web-Anwendung implementiert. Auch hier macht es Sinn, sich mit JavaScript als der Sprache im Browser zu beschäftigen, da auch Java-basierte Ansätze wie JSF oder Vaadin nicht ohne JavaScript auskommen. Und die direkte Verwendung von JavaScript kann sogar einfacher sein, als eine Abstraktion zu benutzen.

Das JavaScript Ökosystem

Wenn wir uns Java anschauen, sehen wir, dass es dafür ein komplettes, „offizielles“ Entwicklerkit, das JDK, gibt. Das JDK bringt eine ganze Reihe von Bibliotheken und Tools mit, die alle aufeinander abgestimmt sind. Dazu gehört der Compiler, die Laufzeitumgebung (JRE), sehr umfangreiche Standardbibliotheken und Tools wie beispielsweise javadoc, apt oder sogar eine SQL Datenbank. Das alles gibt es bei JavaScript zunächst nicht. JavaScript ist zunächst „nur“ eine Sprache, alles andere – inklusive der Laufzeitumgebung, also in erster Linie den Browsern – müssen wir uns selbst zusammenstellen oder sogar selbst entwickeln. Noch vor wenigen Jahren reichte für die JavaScript Entwicklung ein einfacher Editor aus. Man schrieb seinen Code in eine Datei, bettete diese in eine HTML-Seite ein und lies sie vom Browser ausführen. Dieses Vorgehen eignete sich aber nur für eher kleinere Features, etwa das Validieren von Eingaben auf einer Webseite. Größere Anwendungen waren damit nicht oder nur sehr schwer umsetzbar. Aus dieser Situation heraus entwickelten sich unter anderem Libraries wie jQuery, die bestimmte Probleme adressierten und lösten. Im Laufe der Zeit wurden die Anforderungen an Webseiten aber immer komplexer, aus ehemals statischen Seiten wurden dynamische Seiten mit immer mehr Benutzerinteraktionen: „echte“ Anwendungen im Browser entstanden. Hierfür reichte aber auch jQuery irgendwann nicht mehr aus, es entstanden neue Lösungen, die wiederrum neue Innovationen hervorriefen, die wiederum neue Lösungen... und so weiter. Die entstandenden Lösungen wurden aber, von der Sprache JavaScript abgesehen, nicht – wie bei Java – von einem Konsortium (mit)entwickelt, spezifiziert und standardisiert sondern entstanden und entstehen weiterhin von der Community. So sind auch alle im folgenden vorgestellten Tools und Frameworks Open-Source Lösungen.

Die Sprache JavaScript

Ähnlich wie in Java gibt es mehrere Versionen der Sprach-Spezifikation (die ECMAScript heißt). Von den meisten Browsern implementiert ist die Version 5, das bedeutet, wenn meine Anwendung nach dieser Spezifikation implementiert ist, ist die Chance sehr hoch, dass sie in allen Browsern auch funktioniert. ECMAScript 5 wurde im Jahre 2009 veröffentlicht, danach gab es erst 2015 die nächste Version, die aber immer noch nicht von allen Browsern vollständig implementiert wird. Allerdings enthält Version „ECMAScript 2015“ sehr viele, teilweise auch gravierende Änderungen und Neuerungen die für die Entwicklung von Anwendungen sehr vorteilhaft sein können. So haben beispielsweise Klassen und Module Einzug in die Sprache erhalten und mit der Einführung von Block-Scoping und Arrow-Funktionen wurde auf einige der gravierendsten Unzulänglichkeiten in der Sprache reagiert. (Darüberhinaus wurde mit der Version auch der Releasezyklus für die Sprache verändert: seid 2015 gibt es nun jährliche Releases, die jeweils nach dem Erscheinungsjahr benannt sind und nicht mehr durchnummeriert sind, also ECMAScript 2015, ECMAScript 2016, ECMAScript 2017 usw). Wie erwähnt, betreffen diese Releases nur die Sprach-Spezifikation, nicht deren Umsetzungen in den Browsern. Zwar ist zu beobachten, dass die Browserhersteller bemüht sind, die neusten Spezifikationen schnell umzusetzen, in der Praxis dauert das jedoch immer einige Zeit. Außerdem lässt sich eine Anwendung mit neuem JavaScript nur dann sicher betreiben, wenn wirklich alle für die Zielgruppe relevanten Browser die verwendete ECMAScript-Version unterstützten. Um dieses Problem zu lösen, haben sich in der JavaScript Entwicklung Compiler etabliert. Mit JavaScript-Compilern wird allerdings nicht wie in Java Source-Code zu Byte-Code übersetzt, sondern JavaScript Code aus einer Versionen in eine ältere „zurück compiliert“. So lassen sich neue Features zeitnah nutzen, in dem diese in beispielsweise ECMAScript 5 zurückcompiliert werden, das von den allermeisten Browsern unterstützt wird.

Compiler und Polyfills

Der wohl am meisten eingesetzte Compiler ist Babel . Dieser Compiler kann nicht nur aktuellen JavaScript Code in ältere Versionen zurückübersetzen sondern kann dank modularem Aufbau, mit Plug-ins um weitere Features ergänzt und für den individuellen Bedarf konfiguriert werden. Oftmals stehen beispielsweise Plug-ins schon für zukünftige JavaScript Features zur Verfügung, die noch gar nicht endgültig spezifiziert worden sind. Mittels Babel lassen sie sich aber bereits vorab in eigenen Projekten ausprobieren. Eine alternative zu Babel ist der TypeScript Compiler, der von Microsoft entwickelt wird. TypeScript werden weiter unten noch näher betrachten. Mit einem Compiler werden aber nur die Sprache selber von einer Version zu einer anderen Version zurückübersetzt. Neben der Sprache gibt es aber noch einige Standard APIs, die ebenfalls zur Spezifikation gehören und von der Laufzeitumgebung zur Verfügung gestellt werden müssen. Dazu gehören beispielsweise die Funktionen die auf Object, String und Number definiert sind, die (neuen) Map und Sets, oder auch die DOM API. Hier ergibt sich dasselbe Problem wie bei der Sprache: fehlen die APIs in einem der gewünschten Ziel-Browser, können diese in der eigenen Anwendung nicht verwendet werden, da es ansonsten zur Laufzeitfehlern kommt. Abhilfe an dieser Stelle schaffen Polyfills: dabei handelt es sich um Bibliotheken, die eine oder mehrere der Standard APIs implementieren und in die eigene Anwendung eingebunden werden können. Die meisten Polyfills sind dabei so intelligent, dass sie sich selber nur dann aktivieren, wenn die von ihnen implementierten APIs zur Laufzeit wirklich nicht vorhanden sind. Wenn die API in einem Browser bereits vorhanden ist, wird dann von der Anwendung automatisch die nativ implementierte Variante verwendet. Polyfills für diverse APIs stellt beispielsweise corejs zur Verfügung. Hierbei lässt sich auch sehr feingranular auswählen, für welche konkreten APIs ein Polyfill benötigt wird, um den Anwendungscode nicht unnötig aufzublähen. Auch Babel bietet einen Polyfill Bibliothek.

Laufzeitumgebungen

Bislang haben wir als Laufzeitumgebung nur Browser betrachtet. Mittlerweile werden mit JavaScript aber auch Applikationen gebaut außerhalb eines Browsers laufen. Hierbei kommt dann in der Regel NodeJS zum Einsatz. NodeJS verwendet die JavaScript Implementierung V8 von Google, die auch die JavaScript-Engine von Chrome ist. Seit Anfang 2016 gibt es daneben eine NodeJS-Variante die mit Chakra Core, der JavaScript-Engine von Microsoft Edge arbeitet. Auf Basis von NodeJS werden sowohl Serverprozesse (zum Beispiel Webserver oder für eine REST API) implementiert. Andererseits dient NodeJS auch als Ausführungsumgebung für eine ganze Reihe von Tools, wie Compiler (oben genannten Compiler Babel und TypeScript sind in JavaScript implementiert), Package Manager oder Test-Tools. Das ist in gewisser Weise mit Java vergleichbar, wo die JRE auch nicht nur zum Ausführen von Server-Prozessen verwendet wird.

Modul Systeme

Unabhängig von der späteren Laufzeitumgebung müssen gerade größere Anwendungen gut strukturiert werden, damit der Code verständlich und wartbar bleibt. Eine Möglichkeit dazu bieten Module. Ein Modul in JavaScript technisch betrachtet eine Datei und damit eine sehr viel kleinere Einheit als die meisten Java Module, die in der Regel aus mehreren Klassen und Packages bestehen. In JavaScript ist es nicht ungewöhnlich, dass Module nur aus ein, oder zwei Funktionen bestehen. Im Laufe der Zeit haben sich insgesamt drei Modulsysteme etabliert. Es gibt CommonJS, das auch Grundlage für das in NodeJS verwendete Modulsystem ist und für den Einsatz außerhalb eines Browser konzipiert ist. Daneben gibt es das AMD Modulsystem, das für den Einsatz im Browser ausgelegt ist, und unter anderen in der Lage ist, Module asynchron nachzuladen, um beispielsweise den Start einer Anwendung zu beschleunigen. Mit ECMAScript 2015 wurde nun auch ein natives Modulsystem spezifiziert und in den Sprachstandard aufgenommen. Dieses Modulsystem wird zunehmend von den Browsern unterstützt und wird auch von NodeJS implementiert werden. Bis das Modulsystem überall unterstützt wird, können Babel oder TypeScript verwendet werden, um Code, der das native System verwendet, nach CommonJS oder AMD zu übersetzen. Mit dem nativen Modulsystem lassen sich aus Modulen (also Dateien) einzelne Bestandteile exportieren und damit für andere Module sichtbar machen. Alle Bestandteile eines Modules (Funktionen, Klassen, Konstanten etc), die nicht explizit exportiert werden bleiben für andere Module unsichtbar. Um etwas aus einem anderen Modul zu importieren, muss es explizit importiert werden. Das Listing 1 zeigt dafür ein Beispiel: das UserService-Modul exportiert eine Klasse UserService, die vom App-Modul importiert wird. Alle anderen Teile aus dem Modul (die Konstante database und die Funktion initDatabase) sind für andere Module nicht sichtbar und können auch nicht importiert werden.

Package Manager

Module lassen sich (ähnlich wie mit Maven in Java) in einem zentralen Repository veröffentlichen und von dort auch installieren. Das dafür zuständige Tool ist der „Node Package Manager“ (npm), der Bestandteil der NodeJS Distribution ist, aber auch einzeln installiert werden kann. Das Repository ist die npm Registry. Die dort veröffentlichten Artefakte werden Packages genannt und können aus mehreren Modulen und weiteren Source-Artefakten, etwa CSS-Dateien, bestehen. Packages, von denen das eigene Projekt abhängig ist, werden im Projekt in einer Beschreibungsdatei (package.json) hinterlegt, vergleichbar mit den Abhängigkeiten in der pom.xml von Maven. In JavaScript Projekten ist es übrigens auch üblich, über die Abhängigkeitsverwaltung die für die Entwicklung benötigten Tools zu installieren. So stehen beispielsweise Babel und TypeScript aber auch andere Build-Tools als npm Pakete zur Verfügung. Auf diese Weise kann jedes Projekt individuell festlegen welche Tools in genau welcher Version benötigt werden. Alle Mitglieder des Entwicklungsteams erhalten dann automatisch die benötigten Tools in den korrekten Versionen. Außerdem entfällt weitgehend die Notwendigkeit, Tools überhaupt global zu installieren und dadurch in Versionskonflikte zu geraten. Das Listing 2 zeigt einen Ausschnitt aus einer package.json-Datei, in der sowohl Abhängigkeiten definiert sind, die von der Anwendung selber benötigt werden (dependencies), als auch Abhängigkeiten, die nur für die Entwicklung notwendig sind (devDependencies). Für (In-House-)Module, die nicht in einem öffentlichen Repository veröffentlicht werden sollen, kann man neben der offiziellen npm Registry auch eigene Repositories betreiben. Sowohl Nexus und Artifactory beispielsweise unterstützen neben diversen anderen Formaten auch das npm Format.

Neben npm zum installieren und deployen von Packages gibt es mit dem von Facebook entwickelten yarn eine Alternative. Yarn verwendet dieselbe Abhängigkeitsbeschreibung in der package.json wie npm und kann außerdem auch dieselbe Registry verwenden. Vom Funktionsumfang unterscheiden die beiden Tools sich mittlerweile ebenfalls nicht mehr wesentlich, allerdings sind sie hinsichtlich der Bedienung verschieden. Der Vollständigkeit halber sei erwähnt, dass aus früheren Frontend-Projekten noch bower bekannt ist, mit dem sich ebenfalls Abhängigkeiten verwalten lassen. Dieses Tool wird zwar noch gepflegt, aber die Entwickler raten selber dazu, stattdessen auf npm/yarn und Webpack (s.u.) zu setzen.

Module Bundler

Wir haben nun einen Eindruck davon bekommen, wie sich mit JavaScript Module erstellen, in Form von Packages veröffentlichen und in ein eigenes Projekt einbinden lassen. Zum Ausführen einer Anwendung im Browser reicht das allerdings leider noch nicht aus, denn die Browser unterstützen beispielsweise das NodeJS Modulsystem nicht (und auch das native Modulsystem wird noch nicht von allen Browsern unterstützt). Wenn eine Anwendung also selber das NodeJS Modulsystem verwendet oder mittels npm ein externes Package verwendet, das mit dem NodeJS Modulsystem gebaut ist, brauchen wir dafür eine Lösung. Und an dieser Stelle kommen Module Bundler ins Spiel. Ein Module Bundler ist ein Tool, das die Abhängigkeiten einer Anwendung zur Laufzeit analysiert und aus allen referenzierten Modulen eine vom Browser verwendbare JavaScript-Datei erstellt. Der Bundler ist dabei so schlau, dass er die Sichtbarkeiten und Scopings der Original-Module berücksichtigt, so dass es in der erzeugten Ausgabe-Datei nicht zu Namenskollisionen kommen kann. Der wohl prominenteste Module Bunder ist Webpack . Webpack kann mit allen drei Modulsystemen umgehen und bietet diverse Optimierungsmöglichkeiten für den erzeugten Code. Webpack selber lässt ist modular aufgebaut und lässt sich für das eigene Projekt sehr gut anpassen. So kann Webpack beispielsweise vor dem Erzeugen des „Bundles“, also der fertigen Ausgabedatei, die eingelesenen Module zuvor noch mit Babel oder TypeScript compilieren. Dabei ist Webpack nicht auf JavaScript beschränkt, sondern kann zum Beispiel auch mit CSS-Dateien umgehen. Wenn diese im Code referenziert werden, findet Webpack die Referenzen und kann die Dateien je nach Konfiguration behandeln, zum Beispiel den CSS-Code komprimieren. Auf Wunsch erzeugt Webpack dabei auch immer SourceMaps. Dabei handelt es sich um Informationen für den Browser, die den compilierten Code zurück auf den Source-Code mappen, so dass der Browser im Debugger den originalen, Code anzeigen kann, den wir selber programmiert haben. Auch dieses Verhalten ist ähnlich wie in Java, wo im Debugger zum Beispiel in der IDE ja ebenfalls der Source-Code und nicht der erzeugte Byte-Code angezeigt wird. Andere bekannte Module Bundler neben Webpack sind Browserify und Rollup .

Testen und Qualitätssicherung

Mit den bis hierher gezeigten Werkzeugen können wir Anwendungen bauen, die entweder im Browser oder mittels NodeJS auch außerhalb des Browsers laufen können. Genau wie in Java können wir dabei auf externe Bibliotheken (npm Packages) zugreifen und auch eigene Packages in einer Registry ablegen. Im Folgenden wollen wir uns nun ansehen, wie wir unsere Anwendung mit Tests und anderen Maßnahmen gegen Fehler absichern können. Eine erste Möglichkeit besteht darin, einen Type-Checker zu verwenden, der dabei helfen kann, eine ganze Reihe typischer JavaScript Fehler zu vermeiden, so wie wir das auch aus Java gewohnt sind (eine Zahl keinem String zuweisen etc, falsche Anzahl und/oder Typen von Parametern einer Funktion übergeben, unsichere Zugriffe auf potentielle null-Werte etc). Prominente Vertreter sind hier Flow von Facebook oder TypeScript von Microsoft. Beiden gemeinsam ist, dass die Angabe von Typen optional ist, das heißt, man muss nur dort Typ-Angaben hinschreiben, wo man sie auch wirklich benötigt. An vielen Stellen leiten die Type Checker die korrekten Typen automatisch ab. Während Flow ausschließlich ein Type Checker ist, ist TypeScript eine eigene Sprache, die allerdings auf JavaScript aufbaut. So ist jeder gültige JavaScript Code zunächst auch gültiger TypeScript Code. Mit TypeScript lässt sich der Code einerseits um Typ-Angaben ergänzen. Andererseits fügt TypeScript der Sprache aber auch noch einige neue Features hinzu, wie Sichtbarkeiten (protected und private in Klassen) oder Aufzählungstypen (enum). Insgesamt ist TypeScript sehr weit verbreitet (unter anderem wurde Angular damit entwickelt und auch die neue Outlook Webanwendung) und es gibt mittlerweile Typ-Beschreibungen für fast alle bestehendenen JavaScript Bibliotheken. Auch der IDE Support insbesondere mit der IntelliJ Produktfamilie und Visual Studio Code ist sehr gut. Aus diesem Grunde setze ich in Projekten eher TypeScript als Flow ein. Listing 3 zeigt exemplarisch wie Typ-Informationen in TypeScript hingeschrieben werden (die Syntax sieht in Flow übrigens sehr ähnlich aus) und in Abbildung 1 ist exemplarisch zu sehen, wie in Visual Studio Code von TypeScript gefundene Fehler angezeigt werden. Alternativ oder zusätzlich zu einem Type-Checker lassen sich Linter zur Sicherstellung der Code-Qualität einsetzen. Dabei handelt es sich um Tools, die über statische Code-Analyse typische Probleme aufdecken. Außerdem lassen sich darüber selbstdefinierte Code-Konventionen überprüfen. Der am häufigsten eingesetzte Linter ist ESLint oder TSLint für TypeScript Code. Beide Linter lassen sich auch im Rahmen des Webpack Builds ausführen, so dass Webpack abbricht, wenn eines der Tools ein Problem meldet. (Zum Einhalten identischer Type-Checker und Linter ersetzen (leider?) keine Tests für die eigene Anwendung und genau wie in Java gibt es auch für JavaScript Anwendungen diverse Test-Tools und -Frameworks für Tests auf allen möglichen Ebenen. Leider gibt es aus meiner Sicht zurzeit keinen „Standard“, was die Auwahl der Test-Frameworks angeht. Im Wesentlichen gibt es drei Optionen: Mocha , Jasmine und Jest . Mocha ist dabei nur ein Test-Runner, der es erlaubt, einzelne Tests und Testsuites zu definieren und auszuführen. Für Dinge wie Assertions oder Mocks muss man allerdings zusätzliche Module installieren – kann diese dafür aber nach eigenen Vorlieben frei auswählen. Jasmine und Jest hingegen bringen diese Dinge von Haus aus schon mit („Batteries included“), Jest bringt sogar Code Coverage und eine headless Implementierung eines DOMs mit, so dass man dort auch Code testen kann, der zur Laufzeit die DOM API benötigt. Mit dem „Snapshot Testing“ bringt Jest außerdem eine interessante Möglichkeit mit, JSON-basierte APIs (und auch React-Komponenten) zu testen. Listing 4 zeigt einen einfachen Unit-Test mit Jest.

Automatisierung

Mit dem bis hier gezeigten Technologie Stack lassen sich echte Anwendungen entwickeln, testen und betreiben. Gerade zur Entwicklungszeit müssen aber wie wir gesehen haben, einige Dinge immer wieder durchgeführt werden, insbesondere muss der Compiler und/oder Bundler ausgeführt werden, die Tests müssen laufen und eventuell auch der Linter. Das möchten wir natürlich nicht immer und immer wieder von Hand machen, weswegen es Tools zur Automatisierung dieser Vorgänge gibt. Zum einen gibt es mit Gulp und Grunt zwei Tools, die wiederkehrende Tasks ausführen können. Dazu werden Tasks definiert, die bestimmte Aufgaben übernehmen (zum Beispiel das Ausführen des Compilers) und deren Auslöser (Änderung im Source-Verzeichnis) und Abhängigkeiten untereinander (nach dem compilieren den Linter ausführen). Damit lassen sich ähnlich wie mit Maven oder Gradle auch komplexe Build-Prozesse umsetzen. Eine andere, leichtgewichtigere und meist aber ausreichende Alternative sind die npm scripts. In der package.json-Datei eines Projektes lassen sich neben den Abhängigkeiten auch Scripte hinterlegen, die dann mit npm ausgeführt werden können. Die angegebenen Scripte werden von npm dann über die Betriebssystem-spezifische Kommandozeile (z.B. Bash) ausgeführt. Das Besondere daran ist, dass dabei sämtliche lokal von npm installierten Tools (z.B. TypeScript oder Webpack) automatisch im Path vorhanden sind und somit einfach aufgerufen werden können. In der Praxis spielt das Problem, dass die Scripte Betriebssystem-abhängig sind, daher selten eine Rolle und für häufige Probleme, wie das Setzen von Umgebungsvariablen, gibt es bereits auch fertige Lösungen. Bevor man in seinem JavaScript-Projekt mit Gulp oder Grunt arbeitet, sollte man auf jeden Fall prüfen, ob npm scripts ausreichend sind.

Zusammenfassung

Damit sind wir nun am Ende unseres Weges angekommen. Wir haben gesehen, dass einen funktionierenden Technologie Stack für die JavaScript Entwicklung gibt, mit dem sich auch ernsthafte Anwendungen professionell entwickeln lassen:

  • die Sprache JavaScript wurde 2015 um viele wichtige Features, insbesondere einem Modul-System erweitert.
  • Module bzw Packages können mit npm veröffentlicht und eingebunden werden
  • um Anwendungen, die mit neueren Sprachversionen geschrieben werden, in älteren Browsern ausführbar zu machen, verwenden wir einen Compiler (Babel oder TypeScript) und Polyfills
  • für unterschiedlichen Modul-Systeme gibt es Bundles (Webpack), die aus einer modularisierten Code-Basis eine für den Browser ausführbare JavaScript-Datei erstellen
  • zur Erfüllung von Qualitätsanforderungen, Wartbarkeit und Tests gibt es Type Checker (Flow und TypeScript), statische Code Analyse Tools (Linter) und natürlich Test-Frameworks (Mocha, Jasmine, Jest)
  • Um die während der Entwicklung anfallenden Aufgaben zu automatisieren, lassen sich Task Runner einsetzen, deren einfachste Form die npm scripts sind

Im Gegensatz zum JDK gibt es allerdings keine zentrale Instanz, die Tools und Frameworks für uns auswählt und als fertiges Development Kit bereitstellt. Stattdessen werden die meisten Lösungen auf Eigeninitiative entwickelt und bereitgestellt – und dann von der Community angenommen, verworfen oder weiterentwickelt. Das bedeutet, dass wir einerseits eine sehr hohe Innovationsgeschwindigkeit haben, die das Arbeiten mit JavaScript sehr spannend macht, weil wir immer mehr Dinge mit JavaScript umsetzen können. Auf der anderen Seite kann das Tempo aber auch nervenaufreibend sein kann, wenn man versuchen will, Schritt zu halten. Aus meiner Sicht sollte man deshalb auch nicht jedem Trend hinterherrennen. Es ist völlig legitim, beim Erscheinen neuer Frameworks, Tools und Bibliotheken erst einmal abzuwarten, wie diese sich entwickeln und vor allem zu verstehen, welche konkreten Probleme sie lösen. Denn nur wenn das Problem verstanden wurde, kann geprüft werden, ob das Problem für das eigene Projekt überhaupt relevant ist.