ES-Modules: Für ein schnelleres JavaScript?

ES Modules sind ein offizielles, standardisiertes Modulsystem für JavaScript. Aber was genau bedeutet das eigentlich, welche Probleme löst es und wie funktionieren ES Modules?


Anzeige

Modulsysteme sind nützlich. Sie bieten einen Weg, Code über verschiedene Anwendungen und Plattformen hinweg wiederzuverwenden. Über Im- und Exporte können sie beliebig in anderen Modulen verwendet werden. Sie sind modular, lassen sich unabhängig voneinander editieren und löschen, ohne dass damit die ganze Anwendung crasht.

Nix mehr verpassen: Die t3n Newsletter zu deinen Lieblingsthemen! Jetzt anmelden

ES Modules sind nicht der erste Anlauf, eine Modulfunktionalität zu JavaScript hinzuzufügen. CommonJS, ein Modulsystem für Node.js, gibt es schon seit Jahren. Es wurde entwickelt, um eben diese Lücke zu schließen. CommonJS ermöglicht genau diese Modularität. Nützliche Module können damit zu Packages zusammengefasst und über npm publiziert werden, sehr bekannte Beispiele für solche Packages sind zum Beispiel React, Lodash oder jQuery.

Für Browser gab es bis ECMAScript 6 kein Modulsystem. Mit ECMAScript 6 wurden ES Modules zur JS-Spezifikation hinzugefügt. Mittlerweile wird das Format von allen großen Browsern – Safari, Chrome, Edge und Firefox – unterstützt. Auch Node unterstützt ES Modules seit einiger Zeit.

Der Vorteil dabei: Mit ES Modules können JS-Module theoretisch so indiziert und gecached werden, dass von überall auf sie zugegriffen werden kann. Der Nutzwert ist offenkundig: Durch die Modularisierung wird theoretisch möglich, dass der Browser bei auftretenden Änderungen nur die betroffenen Dateien fetchen muss. Warum das relevant ist? Bis zu 90 Prozent des Codes einer Website stammen aus Open-Source-Packages (React, Lodash, jQuery), die bei jeder Änderung des Source-Codes erneut vom Browser geladen werden müssen.

Anzeige Was steckt dahinter?

Wer in JavaScript programmiert, jongliert viel mit Variablen. Es geht eigentlich einen Großteil der Zeit darum, Variablen Werte zuzuweisen, Zahlen hinzuzufügen oder Variablen zu kombinieren und sie in einer weiteren zu speichern. Weil das einen so großen Anteil an der Arbeit mit JavaScript ausmacht, hat die Art, wie ihr diese Variablen innerhalb einer Codebase organisiert, einen nicht unerheblichen Einfluss darauf, wie gut ihr euch darin zurechtfindet, wie gut ihr coden könnt und wie einfach oder auch weniger einfach ihr euren Code warten könnt.

Scope in JavaScript

Sich jeweils nur über ein paar wenige Variablen Gedanken machen zu müssen, ist hilfreich. In JavaScript wird das über ein Konzept namens Scope erreicht. Es verhindert, dass Funktionen auf Variablen zugreifen können, die in anderen Funktionen definiert wurden. An sich ist das eine gute Sache. Wenn ihr an einer Funktion arbeitet, müsst ihr nicht darüber nachdenken, was außerhalb des Scope passiert. Der offensichtliche Nachteil: von außerhalb des Scopes, in dem eine Variable definiert ist, auf sie zuzugreifen, geht nicht. Wer das machen will, muss diese Variable in einem höheren Scope definieren, zum Beispiel als globale Variable.

Illustrieren lässt sich das ganz gut mit jQuery: Um jQuery-Plugins zu laden, mussten Entwickler sicherstellen, dass jQuery im globalen Scope war. jQuery global zu definieren, funktioniert, aber daraus ergaben sich andere Schwierigkeiten: Ihr müsst aufpassen, dass alle Script-Tags in der richtigen Reihenfolge sind – und dass niemand diese Reihenfolge durcheinanderbringt. Wenn eine Funktion jQuery nicht dort findet, wo sie erwartet, es zu finden – im globalen Scope –, wird eure Anwendung nicht weiter ausgeführt und ihr bekommt eine Fehlermeldung.

Dieses Verhalten macht es schwierig, eine Codebase zu maintainen. Code zu löschen oder Script-Tags zu entfernen, wird zum Spießrutenlauf. Ihr wisst nie, was ihr mit solchen Änderungen vielleicht kaputt macht. Das ist so, weil die Abhängigkeiten zwischen eurem Code implizit – also nicht klar ersichtlich irgendwo ausformuliert – sind. Jede Funktion kann schließlich auf alle globalen Variablen zugreifen. Deshalb weiß man nie genau, welche Funktionen wovon abhängig sind. Grundsätzlich kann Code im globalen Scope Variablen, die ebenfalls global definiert sind, verändern. Das ist nicht immer gut. Globale Variablen bieten Angriffspunkte für bösartigen Code und generell mehr Möglichkeiten für die Entstehung von Bugs.

Module und der Module-Scope

Über Module könnt ihr diese global definierten Variablen und Funktionen zu Module-Scopes gruppieren. Der Module-Scope erlaubt es, Variablen unter den Funktionen, die sich in einem gemeinsamen Module-Scope befinden, gemeinsam zu verwenden. Die Variablen innerhalb eines Module-Scopes könnt ihr – anders als die innerhalb einer Funktion – auch für andere Module verfügbar machen. In einem Module-Scope kann explizit festgelegt werden, auf welche der darin befindlichen Variablen, Klassen oder Funktionen von außerhalb zugegriffen werden darf.

Den Vorgang des Verfügbarmachens nennt man einen Export. Ein solcher Export ermöglicht es anderen Modulen, explizit zu machen, dass sie von einer Variable, Klasse oder Funktion abhängig sind. Durch diese explizite Abhängigkeit wisst ihr dann genau, welche Module ihr kaputt macht, wenn ihr Variablen, Klassen oder Funktionen verändert oder wegnehmt. So wird es einfacher, Code in kleinere Teile zu splitten, die auch unabhängig von einander funktionieren. Und die sich dann beliebig zu unterschiedlichen Applikationen kombinieren lassen.

Und so funktionieren die Module

Verwendet ihr beim Entwickeln Module, entsteht dabei ein Abhängigkeits-Graph oder -Diagramm. Über Import-Statements werden die Verbindungen zwischen verschiedenen Dependencies hergestellt. Über diese Statements weiß der Browser genau, welcher Code geladen werden muss. Ihr gebt dem Browser quasi eine Datei, über die er in den Dependency-Graphen einsteigen kann. Von dort aus kann er über weitere Import-Statements weiteren Code finden.

Die ESM-Syntax

Die Syntax zum Importieren eines Moduls sieht so aus:


import module from 'module-name'

zum Vergleich, in CommonJS sieht sie so aus:

const module = require ('module-name')

Ein Modul ist eine JS-Datei, die einen oder mehrere Values – Funktionen, Variablen oder Objekte – mittels des export-Keywords exportiert. Zum Beispiel so:

//lowercase.js

export default str => str.toLowerCase()

Anzeige

Dateien sind aber nichts, was der Browser sofort nutzen kann. Vorher muss er all diese Dateien in Datenstrukturen umwandeln. Diese Datenstrukturen werden Module-Records genannt. Diese Module-Records kann der Browser verstehen – über diesen Zwischenschritt findet er heraus, was es mit einer Datei auf sich hat. In einem nächsten Schritt müssen die Module-Records zu Modulinstanzen umgewandelt werden

https://samplecic.ch/es-modules-fur-ein-schnelleres-javascript.html

Комментарии

Популярные сообщения из этого блога

Centered Logos Hurt Website Navigation

Wichtiges Entwickler-Tool: Homebrew für M1-Macs und MacOS 11 Big Sur erschienen

App-Entwicklung: Nein, ihr braucht wahrscheinlich keine künstliche Intelligenz