Module für kleinere Script-Fragmente
Scripte und Programme sind einfacher in den Griff zu kriegen, wenn sie klein und überschaubar bleiben. Diese Binsenweisheit steckte schon in den frühen Tagen der Programmiersprachen hinter der Idee von Funktionen.
Wer von PHP kommt oder mit Server Side Includes vertraut ist, kennt bereits Mechanismen wie require und include.
PHP require('somefile.php'); SSI <!--#include virtual="/inc/base.inc" -->
Wir scollen rauf und runter im Script, suchen einen Variablennamen, rufen uns Objekte und Funktionen zurück ins Gedächtnis, und am nächsten Tag geht die Übersicht völlig in die Binsen. Javascript-Module beheben dieses Dilemma, indem sie das Script in kleinere Teile herunterbrechen und in separaten Dateien speichern. Dann werden die Module in das Original-Script zurückgeholt: Sie werden importiert.
Demo (Scroll)
const updateBookShelf = (update) => { let main = document.querySelector ("main"); main.innerHTML = markup (bookShelf); console.info (update); } const bookshelf = { name : "Arm und Reich", pages : 500, author : "Jared Diamond", image : "../book-arm.webp", status: { new : 2020, last : 2006 }, newStrapLength: function (lengthLeft, lengthRight) { this.strapLength.left = status.new; this.strapLength.right = status.last; updateBookShelf(`Strap lengths updated.`); }, } const markup = ( bookshelf ) => { return ` <div> <h3>Regal 117</h3> <ul> <li><img src="book-arm.webp"></li> <li>Titel: ${bookshelf.name} </li> <li>Seiten: ${bookshelf.pages} </li> <li>Autor: ${bookshelf.author} </li> </ul> </div> `; } const main = document.createElement ("main"); main.innerHTML = markup (bookshelf); document.body.appendChild (main);
export default bookshelf am Ende des Moduls exportiert das Objekt bookshelf
bookshelf.js (Scroll)
const updateBookShelf = (update) => {
let main = document.querySelector ("main");
main.innerHTML = markup (bookShelf);
console.info (update);
}
const bookshelf = {
name : "Arm und Reich",
pages : 500,
author : "Jared Diamond",
image : "../book-arm.webp",
status: {
new : 2020,
last : 2006
},
testChapter: function (neu, alt) {
this.strapLength.left = status.new;
this.strapLength.right = status.last;
updateBookShelf(`Neuauflage aufgenommen`);
},
}
export default bookshelf;
import bookshelf from "./bookshelf.js" am Anfang des Scripts import das Modul
script.js (Scroll)
import bookshelf from "./bookshelf.js"
const markup = ( bookshelf ) => {
return `
<div>
<h3>Regal 117</h3>
<ul>
<li><img src="book-arm.webp"></li>
<li>Titel: ${bookshelf.name} </li>
<li>Seiten: ${bookshelf.pages} </li>
<li>Autor: ${bookshelf.author} </li>
</ul>
</div>
`;
}
const main = document.createElement ("main");
main.innerHTML = markup (bookshelf);
document.body.appendChild (main);
Das script-Element der HTML-Datei und auch die importierten Module werden als type="module" eingebunden.
<script type="module" src="bookshelf.js"></script> <script type="module" src="script.js"></script>
Ohne type="module" gibt es ansonsten eine Fehlermeldung "expects exactly one argument" (Safari) oder Uncaught SyntaxError: Cannot use import statement outside a module (Chrome).
Block-Scope
Eine Variable item im globalen Scrope bleibt beim Import eines Moduls im Gültigkeitsbereich (Scope) des Moduls und ist nur innerhalb des Moduls verfügbar, in dem sie deklariert wurde. Was heißt das im Klartext? Die Werte eines importierten Objekts werden von der Console nicht angezeigt.
referenceerror: Can't find variable: bookshelf
Das ist ein guter Hinweis dafür, welche Objekte in Module gesetzt werden können oder besser nicht in ein Modul gesetzt werden. bookshelf als Javascript-Modul war also keine gute Idee.
Der Einsatz einer Javascript-Klasse, die ein Template für die Erzeugung von Objekten ist, wäre hier angebracht, denn dann würde die Referenz auf bookshelf in der Konsole die Informationen liefern.
import Syntax
Der Parameter name ist der Name des Modul-Objekts und wird zu einer Art Namensraum für Exporte. Der export-Parameter definiert individuelle Exporte, import * as name importiert alle Objekte.
Importiert wird vom relativen Pfad zur Javascript-Datei
import defaultExport from './module.js'; import * as name from './module.js'; import {square} from './module.js'; let content = import('./module.js');
./ : Dot (.) verweist auf dasselbe Verzeichnis und der Schrägstrich oder Slash gewährt den Zugriff auf das Verzeichnis.
export const add = (x, y) => { return x + y } export const subtract = (x, y) => { return x - y; }
import { add, subtract } from './data'; console.log(add(2, 3));
script.js – der Vorläufer der Module
Im Grunde genommen sind Scripte, die mit dem script-Element eingebunden werden, Module, die in den globalen Scrope geladen werden. Allerdings sind ihre globalen Variablen ungeschützt. Vorsichtige Entwickler packen ihre Scripte darum in IIFE – selbstausführende Funktionen.
Javascript Module importieren u.U. selber wieder Module, die sie brauchen. Das erspart das manuelle Laden von Scripten, von denen wiederum das Modul abhängig ist.
Darüber hinaus gibt es einen dynamischen import(), der Funktionen ähnelt, aber keine Scripte mit type="module" erfordert.
Ein dynamischer Import ist sinnvoll, wenn Module unter bestimmten Bedingungen geladen werden sollen. Die statische Form wird bei Abhängigkeiten für das initiale Laden vorgezogen.