Start / Seminare / JavaScript Grundlagen & Modernes ECMAScript

Modul

Module, Pakete und Projektstruktur

5 Kapitel in diesem Modul-Video · Laufzeit

Vertonung mit synthetischer Stimme · Inhalte redaktionell verantwortet · © 2026 HECKER CONSULTING, alle Rechte vorbehalten

Transkript

Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.

JavaScript — Module und Projektstruktur

0:00 Bisher lag unser Code in einer Datei. Zum Lernen ist das ideal — alles ist sichtbar, nichts versteckt sich. Für ein Projekt reicht es nicht. Ab einer gewissen Größe braucht Code Grenzen: klare Zuständigkeiten, sichtbare Abhängigkeiten, eine Stelle, an der alles zusammenläuft. Genau diese Grenzen zieht man mit Modulen. In diesem Modul lernen Sie, Code auf Dateien zu verteilen, fremde Pakete einzubinden und dabei die Frage zu stellen, die viele überspringen: Brauche ich dieses Paket überhaupt?

0:31 Der rote Faden ist einfach — eine Zuständigkeit je Datei, ein Einstiegspunkt, der koordiniert.

Aus einer Datei wird ein Projekt

0:37 Fünf Kapitel. Zuerst der Begriff selbst und die beiden Modulsysteme, die Ihnen begegnen — eines schreiben Sie, eines müssen Sie nur erkennen. Dann die zwei Arten, Werte freizugeben, mit einer klaren Faustregel. Danach die Projektstruktur: wie man ein gewachsenes Skript sinnvoll aufteilt. Das vierte Kapitel behandelt fremde Pakete, und dort sind vier Prüffragen der eigentliche Inhalt, nicht die Befehle.

1:01 Und zum Schluss ein neueres Sprachfeature, mit dem sich Daten direkt als Modul einbinden lassen.

Module verstehen

1:08 Beginnen wir mit dem Grundgedanken. Module machen Abhängigkeiten sichtbar, statt Werte heimlich über globale Variablen weiterzureichen. Zwei Systeme gibt es dafür — und die Rollenverteilung ist klar: Eines schreiben wir, das andere erkennen wir. Ein Modul ist eine Datei, die einzelne Werte nach außen sichtbar macht und Werte anderer Dateien hereinholt.

1:30 Zwei Richtungen also, und beide sind ausdrücklich — nichts geschieht automatisch. Modernes JavaScript nutzt dafür die Schlüsselwörter für Export und Import. Der ältere Stil, CommonJS, verwendet stattdessen eine Ladefunktion und ein Ausgabeobjekt. Der ist keineswegs ausgestorben; er steckt in unzähligen Paketen und in fast jedem gewachsenen Node-Projekt. Sie müssen ihn also lesen können.

1:53 Schreiben werden wir ausschließlich in der modernen Form. Vier Nutzen, und der erste ist der grundlegende: Jede Datei bekommt eine klare, benennbare Zuständigkeit. Wenn Sie den Zweck einer Datei nicht in einem Satz sagen können, ist sie vermutlich zu groß. Der zweite ist praktisch beim Lesen: Abhängigkeiten stehen sichtbar im Kopf der Datei — Sie sehen in drei Zeilen, wovon dieser Code abhängt.

2:18 Der dritte knüpft an das Testmodul an: Getestet und wiederverwendet wird, was gezielt exportiert wurde. Und der vierte beseitigt eine alte Unart — globale Werte als heimlicher Übergabeweg. Solche versteckten Verbindungen sind die Ursache vieler unerklärlicher Effekte. Oben die moderne Form, die wir schreiben. Darunter die alte, auskommentiert — nur zum Wiedererkennen.

2:41 Achten Sie auf die Unterschiede: Ladefunktion statt Import-Schlüsselwort, Ausgabeobjekt statt Export. Wenn Sie das einmal nebeneinander gesehen haben, erkennen Sie es in fremdem Code sofort. Der untere Block zeigt noch ein Detail, das viele nicht kennen: das Präfix vor eingebauten Modulen. Es macht auf einen Blick klar, dass hier kein Paket und keine eigene Datei gemeint ist, sondern etwas, das Node mitbringt.

3:06 Das ist keine Pflicht, aber gute Praxis — es verhindert Verwechslungen mit gleichnamigen Paketen. Benennen Sie an zwei Codeausschnitten das jeweilige Modulsystem — und dann die Einstellung, die Node dazu bringt, eine Datei als modernes Modul zu behandeln. Der Hinweis verrät sie: eine Typangabe in der Projektdatei. Diese eine Zeile ist erstaunlich folgenreich.

3:28 Ohne sie behandelt Node Ihre Dateien als alten Stil, und jeder Import scheitert mit einer Meldung, die auf einen Syntaxfehler hindeutet. Genau diese Fehlermeldung hat schon viele Menschen eine halbe Stunde gekostet — und jetzt kennen Sie die Ursache. Der Import ohne die Typangabe ist der eben beschriebene Fall und der häufigste Stolperstein beim Projektstart.

3:49 Beide Systeme in einer Datei zu mischen, geht schlicht nicht — man muss sich entscheiden. Das Präfix bei eingebauten Modulen wegzulassen, funktioniert zwar meistens, öffnet aber die Tür für Verwechslungen mit installierten Paketen. Und der letzte Punkt ist die alte Unart aus dem Warum-Abschnitt: Werte über globale Variablen auszutauschen, statt sie zu exportieren.

4:09 Das funktioniert und macht Ihren Code unlesbar, weil niemand mehr sieht, woher etwas kommt.

Werte exportieren und importieren

4:15 Jetzt die Mechanik: Es gibt zwei Arten, einen Wert freizugeben, und sie unterscheiden sich nicht nur in der Schreibweise. Eine Faustregel am Ende dieses Kapitels nimmt Ihnen die Entscheidung fast immer ab. Ein benannter Export gibt einen Wert unter seinem eigenen Namen frei — und wird in geschweiften Klammern importiert.

4:34 Ein Standard-Export benennt den einen Hauptwert eines Moduls und wird ohne Klammern importiert, wobei der Importierende den Namen frei wählen darf. Diese Freiheit klingt bequem und ist tatsächlich die größte Schwäche: Dasselbe Modul kann in zwei Dateien unter zwei verschiedenen Namen auftauchen. Beim benannten Export ist der Name verbindlich, und genau deshalb ist er der Normalfall in modernem Code.

4:56 Drei Dateien in einem Block. Oben ein Modul mit zwei benannten Exporten — beide Funktionen sind unter ihrem Namen freigegeben. In der Mitte ein Modul mit einem Standard-Export. Und unten die zugehörigen Importe: einmal mit geschweiften Klammern, einmal ohne. Der Fußtext enthält einen Punkt, der in der Praxis oft Ärger macht: In Node-Modulen gehört die Dateiendung in den Importpfad.

5:19 Wer aus Projekten mit Bundler kommt, ist das anders gewohnt und lässt sie weg — und bekommt dann eine Fehlermeldung, dass das Modul nicht gefunden wurde, obwohl die Datei offensichtlich da ist. Die Faustregel steht in der ersten Zeile: Bietet ein Modul mehrere verwandte Funktionen an, nehmen Sie benannte Exporte. Hat es genau einen Hauptwert — eine Klasse, eine zentrale Funktion —, ist der Standard-Export legitim.

5:44 Beides zu mischen ist möglich und selten hilfreich, weil man dann beim Importieren jedes Mal überlegen muss, was wie geholt wird. Der Fußtext nennt das entscheidende Argument für die benannte Variante: Sie macht im Importierenden sofort sichtbar, was benutzt wird. Man liest drei Zeilen und weiß, welche Fähigkeiten diese Datei von außen bezieht.

6:04 Verlagern Sie zwei zusammengehörende Funktionen in eine eigene Datei, exportieren Sie sie benannt und importieren Sie sie in der Hauptdatei — bei unverändertem Programmverhalten. Diese Auflage kennen Sie inzwischen: umbauen, ohne kaputtzumachen. Der Hinweis enthält den Entwurfsgedanken, der über die Mechanik hinausgeht: Exportieren Sie nur, was außerhalb wirklich gebraucht wird.

6:26 Was Sie nicht exportieren, gehört Ihnen allein und kann jederzeit geändert werden, ohne dass jemand anders es merkt. Diese Freiheit gibt man ungern leichtfertig auf. Die fehlende Dateiendung ist der Stolperstein aus dem Codebeispiel — häufig, ärgerlich, in zwei Sekunden behoben, wenn man ihn kennt. Beim Standard-Export geschweifte Klammern zu setzen, ergibt ein undefined, das erst später auffällt.

6:49 Der dritte Punkt ist die Entwurfsfrage aus der Aufgabe: Alles zu exportieren, statt eine bewusste Schnittstelle zu wählen, macht jede interne Änderung zu einer Änderung für alle. Und der vierte ist mechanisch interessant: Ein relativer Pfad ohne führenden Punkt wird nicht als Datei verstanden, sondern als Paketname — Node sucht dann im Paketordner und findet nichts.

Ein Projekt aus mehreren Dateien

7:10 Jetzt die eigentliche Strukturfrage: Wie zerlegt man ein gewachsenes Skript sinnvoll? Am Ende dieses Kapitels sprechen wir über ein Problem, das genau aus fehlender Struktur entsteht — und das man mit einer einfachen Regel vermeidet. Drei Aussagen. Erstens: Jede Datei trägt eine Zuständigkeit — nicht drei, nicht eine halbe. Zweitens: Der Einstiegspunkt führt die Teile zusammen.

7:33 Er ist der Dirigent, nicht der erste Geiger. Und drittens der Satz, der die meiste Struktur schafft: Die Hilfsmodule kennen einander möglichst nicht. Sie hängen alle am Einstiegspunkt und nicht aneinander. Das ist wie bei einem Sternnetz gegenüber einem Gewirr von Direktverbindungen — man kann jeden Teil einzeln austauschen, testen und verstehen, ohne den Rest mitzudenken.

7:57 Fünf Dateien, und das Prinzip dahinter ist wichtiger als die konkreten Namen. Beachten Sie die erste Zeile: Daten liegen getrennt von Logik, ohne jede Fachlogik darin. Die drei mittleren tragen je eine erkennbare Aufgabe — Darstellung, Prüfung, fachliche Einstufung. Und ganz unten der Einstiegspunkt, der koordiniert. Der Fußtext ist ehrlich: Das ist nicht die einzige mögliche Aufteilung. Das Kriterium ist ein anderes — jede Datei muss erklärbar bleiben.

8:26 Wenn Sie den Zweck einer Datei in einem Satz sagen können, stimmt der Schnitt. Wenn Sie „und außerdem" brauchen, nicht. Der rote Faden dieser fünf Schritte: erst die Rahmenbedingungen, dann die Trennung, dann die Koordination. Schritt eins ist die Typangabe, die wir kennengelernt haben — ohne sie funktioniert nichts. Schritt zwei ist das Startskript, und der Fußtext nennt die Folge: Danach startet das Projekt über einen Befehl, nicht über einen Dateipfad.

8:54 Das klingt nach einer Kleinigkeit und ist eine Schnittstelle — jeder im Team startet es gleich, egal wie die Datei heißt. Schritt drei trennt Daten von Logik. Schritt vier verteilt die Zuständigkeiten. Und Schritt fünf lässt den Einstiegspunkt den Ablauf steuern. Machen Sie aus einer Datei mindestens drei Module plus Einstiegspunkt — bei identischem Verhalten. Die entscheidende Auflage steht am Ende: Kein Hilfsmodul importiert ein anderes.

9:21 Das ist streng, und genau deshalb lehrreich. Der Hinweis sagt, was zu tun ist, wenn es nicht gelingt: Zieht ein Modul ein anderes hinter sich her, gehört die Grenze neu gezogen. Die Abhängigkeit ist dann nämlich ein Hinweis darauf, dass die beiden Dateien zusammengehören — oder dass ein gemeinsamer Teil in ein drittes Modul gehört.

9:41 Zirkuläre Abhängigkeiten führen die Liste an: Zwei Module importieren sich gegenseitig, und je nach Ladereihenfolge ist einer der beiden Werte noch nicht da. Die Fehlermeldung ist kryptisch, die Ursache strukturell. Der zweite Punkt ist die häufigste Verwässerung: Der Einstiegspunkt füllt sich mit Fachlogik, bis er selbst das größte Modul ist.

10:00 Beispieldaten in ein Logikmodul zu schreiben, macht dieses untestbar mit anderen Daten. Und der vierte ist eine Denkfalle: Dateien nach Typ zu schneiden — alle Funktionen hierhin, alle Konstanten dorthin — statt nach Zuständigkeit. Das sieht ordentlich aus und hilft niemandem.

Fremde Pakete einbinden

10:17 Jetzt zu den Paketen. Die Befehle sind in zwei Minuten erklärt — und sie sind nicht der Inhalt dieses Kapitels. Der eigentliche Inhalt sind vier Fragen, die man sich vor jeder Abhängigkeit stellen sollte und die viel zu selten gestellt werden. Ein Paket ist wiederverwendbarer Code, der ins Projekt installiert wird. Der Paketmanager lädt ihn herunter und verzeichnet ihn in der Projektdatei.

10:40 Interessant ist der Zusatz: Die exakten Versionen hält eine zweite Datei fest, die Sperrdatei. Warum zwei Dateien? Weil in der Projektdatei meist ein Versionsbereich steht — ungefähr diese Version oder neuer. Die Sperrdatei hält fest, welche es beim letzten Mal tatsächlich war. Erst dadurch bekommen alle im Team und der Server dieselben Versionen. Ohne sie läuft es bei Ihnen und bricht beim Kollegen — der Klassiker.

11:06 Drei Befehle. Der erste legt die Projektdatei an, ohne Rückfragen. Der zweite installiert eine Laufzeitabhängigkeit — etwas, das die fertige Anwendung braucht. Der dritte installiert mit einem zusätzlichen Schalter eine Entwicklungsabhängigkeit: Werkzeuge, die nur beim Arbeiten gebraucht werden, wie das Test-Framework aus Modul elf.

11:26 Der Fußtext erklärt die Trennlinie, und sie ist wichtiger, als sie aussieht: Sie entscheidet, was am Ende mit ausgeliefert wird. Ein Testwerkzeug in der Produktionsumgebung ist zusätzlicher Ballast — und im Zweifel zusätzliche Angriffsfläche. Drei Zeilen, eine sehr klare Regel. Projektdatei und Sperrdatei gehören in die Versionsverwaltung — beide, ohne Ausnahme. Der Paketordner nicht, und zwar nie. Warum?

11:51 Er enthält Tausende von Dateien, die sich jederzeit aus den beiden anderen wiederherstellen lassen. Ihn einzuchecken bläht das Repository um Größenordnungen auf, ohne einen einzigen Vorteil. Der Fußtext nennt den Mechanismus: Auf einem anderen Rechner stellt ein einziger Installationsbefehl den Stand wieder her. Und von Hand ändern sollte man dort ebenfalls nichts — die Änderung ist beim nächsten Installationslauf weg.

12:17 Das sind die angekündigten vier Fragen, und ich halte sie für den wichtigsten Inhalt dieses Kapitels. Erstens: Brauche ich das wirklich, oder kann die Sprache das inzwischen selbst? Erstaunlich oft lautet die Antwort ja — JavaScript hat in den letzten Jahren viel nachgeholt, was früher Pakete leisteten. Zweitens: Wird es gepflegt, und wie verbreitet ist es?

12:40 Ein verwaistes Paket wird irgendwann Ihr Problem. Drittens: Rechtfertigt der Nutzen die Abhängigkeit? Und viertens die Sicherheitsfrage. Jedes Paket, das Sie einbinden, wird Teil Ihrer Anwendung — mitsamt allem, was es selbst mitbringt. Installieren Sie ein Paket, verwenden Sie es im Code, ordnen Sie es korrekt als Laufzeit- oder Entwicklungsabhängigkeit ein — und beantworten Sie dann die vier Prüffragen dazu.

13:05 Der letzte Teil ist der eigentliche. Der Hinweis nennt die Reihenfolge: Prüfen Sie zuerst, ob Node die Aufgabe bereits eingebaut löst. Diese Prüfung dauert fünf Minuten und erspart Ihnen manchmal eine Abhängigkeit, die Sie jahrelang mitschleppen. Es ist übrigens dieselbe Denkweise wie bei den regulären Ausdrücken: das einfachste Werkzeug nehmen, das die Aufgabe löst.

13:27 Den Paketordner einzuchecken, ist der Klassiker bei den ersten eigenen Projekten und bläht alles unnötig auf. Die Sperrdatei nicht mitzuchecken, ist subtiler und in der Wirkung schlimmer: Die Installationen laufen dann auseinander, und irgendwann funktioniert es bei einem im Team nicht mehr — ohne dass jemand etwas geändert hätte.

13:45 Entwicklungswerkzeuge als Laufzeitabhängigkeit zu installieren, ist ein Ordnungsfehler mit realen Folgen für die Auslieferung. Und der letzte Punkt ist die Zusammenfassung der vier Fragen: ein Paket einbinden, wo drei Zeilen eigener Code gereicht hätten.

JSON-Module und Import-Attribute

13:59 Zum Abschluss ein neueres Sprachfeature, mit dem sich Daten direkt als Modul einbinden lassen. Und daran anschließend eine Dreiteilung, die das ganze Modul abrundet — nämlich die Frage, woher Ihre Daten eigentlich kommen. Eine JSON-Datei lässt sich importieren wie eine JavaScript-Datei — mit einem Zusatz: einem Import-Attribut, das den Typ angibt. Warum dieser Zusatz? Aus Sicherheitsgründen.

14:24 Ohne ihn könnte ein Server eine als JSON angeforderte Datei als ausführbaren Code ausliefern, und die würde dann laufen. Das Attribut macht Ihre Erwartung ausdrücklich. Der zweite Satz nennt den praktischen Gewinn: Der importierte Wert ist bereits ausgewertetes JSON — ein fertiges Array oder Objekt. Sie sparen sich also den Umwandlungsschritt, den wir seit Modul drei kennen.

14:48 Die erste Zeile zeigt die Schreibweise mit dem Attribut am Ende. Und direkt darunter der Beweis für den Gewinn: Sie greifen sofort auf die Länge zu, ohne Umwandlung. Der auskommentierte Block darunter zeigt die Alternative, die wir aus dem letzten Modul kennen — lesen und dann umwandeln. Die brauchen Sie, sobald der Pfad variabel ist oder der Inhalt sich zur Laufzeit ändern kann.

15:10 Der Fußtext ist die inzwischen vertraute Mahnung: neueres Sprachfeature, also Laufzeitumgebung und Werkzeugkette vorher prüfen. Sie merken, dass diese Prüfung sich durch den ganzen Kurs zieht. Diese Tabelle rundet das ganze Modul ab, und der Fußtext enthält die Pointe: Am Ende entstehen in allen drei Fällen gewöhnliche JavaScript-Objekte.

15:30 Nur die Herkunft unterscheidet sich — und mit ihr die Fehlerquellen. Beim statischen Import kann eigentlich nichts schiefgehen; die Daten sind Teil des Projekts. Beim Lesen zur Laufzeit haben Sie die zwei Fehlerquellen aus dem letzten Modul: Datei fehlt, Inhalt ungültig. Und bei der HTTP-Antwort kommen Netzwerkfehler, Statuscodes und eine fremde Struktur hinzu. Je weiter weg die Quelle, desto mehr Prüfung.

15:55 Binden Sie eine JSON-Datei als Modul ein und begründen Sie, warum hier kein Lesen zur Laufzeit nötig ist. Die Begründung ist wieder das Eigentliche — es geht um die Unterscheidung zwischen Daten, die zum Projekt gehören, und Daten, die sich ändern können. Der Hinweis nennt die typischen Fälle: feste Nachschlagetabellen und Beispieldaten.

16:15 Postleitzahlenbereiche, Kategorien, Übersetzungen — Dinge, die sich mit dem Code ändern und nicht unabhängig davon. Alles, was sich unabhängig ändert, gehört zur Laufzeit gelesen. Das fehlende Import-Attribut führt zu einem Fehler beim Laden — immerhin eindeutig, und jetzt kennen Sie auch den Grund dafür. Der zweite Punkt ist der praktisch relevanteste: Veränderliche Daten statisch zu importieren, hält den Stand vom Programmstart fest.

16:40 Änderungen an der Datei bemerkt Ihr Programm nicht — und die Fehlersuche geht in die falsche Richtung, weil die Datei ja offensichtlich stimmt. Der dritte Punkt ist eine harmlose Verwirrung: Der Import ist schon ausgewertet, eine zweite Umwandlung scheitert. Und der vierte ist der Verfügbarkeitscheck.

Aus Dateien wird ein Projekt

16:58 Drei Sätze zum Mitnehmen. Erstens das Strukturprinzip, das den größten Unterschied macht: eine Zuständigkeit je Modul, ein Einstiegspunkt, der koordiniert — und Hilfsmodule, die einander nicht kennen. Zweitens ein handfestes Detail, das Ihnen sonst eine halbe Stunde kostet: In Node-Modulen gehört die Dateiendung in den Importpfad.

17:17 Und drittens die Regel für die Versionsverwaltung: Projektdatei und Sperrdatei gehören eingecheckt, der Paketordner nicht. Im nächsten Modul verlassen die Daten dann endgültig den Speicher — es geht um Dateizugriff, Datenaustausch und Datenbanken.

Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →