| [ Web Proxy ] |
| Viewing: https://developer.mozilla.org/de/docs/Web/JavaScript/Guide/Modules | [Back] [Original] |
Get to know MDN better
Dieser Inhalt wurde automatisch aus dem Englischen bersetzt, und kann Fehler enthalten. Erfahre mehr ber dieses Experiment.
Dieser Leitfaden gibt Ihnen alles, was Sie bentigen, um mit der JavaScript-Modulsyntax zu beginnen.
JavaScript-Programme begannen ziemlich klein in den frhen Tagen wurde es hauptschlich fr isolierte Skriptaufgaben verwendet, um ein wenig Interaktivitt zu Ihren Webseiten hinzuzufgen, wo ntig, daher waren groe Skripte im Allgemeinen nicht erforderlich. Einige Jahre spter haben wir nun vollstndige Anwendungen, die in Browsern mit viel JavaScript ausgefhrt werden, sowie JavaScript, das in anderen Kontexten verwendet wird (Node.js, zum Beispiel).
Komplexe Projekte erfordern einen Mechanismus, um JavaScript-Programme in separate Module aufzuteilen, die bei Bedarf importiert werden knnen. Node.js verfgt schon lange ber diese Fhigkeit, und es gibt eine Reihe von JavaScript-Bibliotheken und -Frameworks, die die Nutzung von Modulen ermglichen (zum Beispiel andere CommonJS- und AMD-basierte Modulsysteme wie RequireJS, webpack und Babel).
Alle modernen Browser untersttzen Modulfunktionen nativ, ohne dass eine Transpilierung erforderlich ist. Das kann nur eine gute Sache sein Browser knnen das Laden von Modulen optimieren, was effizienter ist, als eine Bibliothek verwenden zu mssen, um all diese zustzliche clientseitige Verarbeitung und zustzliche Anfragen durchzufhren. Es macht jedoch Bundler wie webpack nicht obsolet Bundler leisten immer noch gute Arbeit bei der Partitionierung von Code in angemessen groe Stcke und sind in der Lage, weitere Optimierungen wie Minimierung, Entfernung von nicht genutztem Code und Tree-Shaking durchzufhren.
Um die Nutzung von Modulen zu demonstrieren, haben wir ein Set von Beispielen erstellt, die Sie auf GitHub finden. Diese Beispiele zeigen eine Reihe von Modulen, die ein <canvas>-Element auf einer Webseite erstellen und dann (und Informationen darber berichten) verschiedene Formen auf der Leinwand zeichnen.
Diese sind ziemlich trivial, wurden jedoch absichtlich einfach gehalten, um Module klar zu demonstrieren.
Hinweis: Wenn Sie die Beispiele herunterladen und lokal ausfhren mchten, mssen Sie sie ber einen lokalen Webserver ausfhren.
In unserem ersten Beispiel (siehe basic-modules) haben wir eine Dateistruktur wie folgt:
index.html
main.js
modules/
canvas.js
square.js
Hinweis: Alle Beispiele in diesem Leitfaden haben grundstzlich die gleiche Struktur; das obige sollte ziemlich vertraut werden.
Die zwei Module im Verzeichnis modules werden unten beschrieben:
canvas.js enthlt Funktionen, die mit der Einrichtung der Leinwand zu tun haben:
create() erstellt eine Leinwand mit einer bestimmten Breite und Hhe innerhalb eines Wrappers <div> mit einer bestimmten ID, die selbst in ein bestimmtes bergeordnetes Element eingefgt wird. Gibt ein Objekt zurck, das den 2D-Kontext der Leinwand und die ID des Wrappers enthlt.createReportList() erstellt eine ungeordnete Liste, die in einem bestimmten Wrapper-Element eingefgt wird und zur Ausgabe von Berichterstellungsdaten verwendet werden kann. Gibt die ID der Liste zurck.square.js enthlt:
name eine Konstante, die den String 'square' enthlt.draw() zeichnet ein Quadrat auf eine angegebene Leinwand mit einer bestimmten Gre, Position und Farbe. Gibt ein Objekt zurck, das die Gre, Position und Farbe des Quadrats enthlt.reportArea() schreibt die Flche eines Quadrats in eine bestimmte Berichtsliste, basierend auf seiner Lnge.reportPerimeter() schreibt den Umfang eines Quadrats in eine bestimmte Berichtsliste, basierend auf seiner Lnge.In diesem Artikel haben wir .js-Erweiterungen fr unsere Moduldaten verwendet, aber in anderen Ressourcen sehen Sie mglicherweise die Erweiterung .mjs statt. V8s Dokumentation empfiehlt dies, zum Beispiel. Die angegebenen Grnde sind:
Wir haben uns jedoch entschieden, vorerst .js zu verwenden. Um Module im Browser korrekt zu verwenden, mssen Sie sicherstellen, dass Ihr Server sie mit einem Content-Type-Header ausliefert, der einen JavaScript MIME-Typ wie text/javascript enthlt. Andernfalls erhalten Sie einen strengen MIME-Typ-Fehler wie "Der Server hat mit einem Nicht-Javascript-MIME-Typ geantwortet", und der Browser fhrt Ihr JavaScript nicht aus. Die meisten Server stellen den richtigen Typ fr .js-Dateien bereits ein, jedoch noch nicht fr .mjs-Dateien. Server, die .mjs-Dateien bereits korrekt bereitstellen, sind unter anderem GitHub Pages und http-server fr Node.js.
Dies ist in Ordnung, wenn Sie bereits eine solche Umgebung verwenden oder wenn nicht, Sie wissen, was Sie tun und Zugriff haben (d.h. Sie knnen Ihren Server so konfigurieren, dass er den richtigen Content-Type fr .mjs-Dateien setzt). Es knnte jedoch zu Verwirrung fhren, wenn Sie den Server, von dem Sie Dateien bereitstellen, nicht kontrollieren oder Dateien fr die ffentliche Nutzung verffentlichen, wie wir es hier tun.
Fr Lern- und Portabilittszwecke haben wir uns entschieden, bei .js zu bleiben.
Wenn Sie wirklich Wert auf die Klarheit legen, .mjs fr Module zu verwenden, im Gegensatz zu .js fr regulre JavaScript-Dateien, aber das oben beschriebene Problem vermeiden mchten, knnten Sie .mjs whrend der Entwicklung verwenden und sie whrend Ihres Build-Schritts in .js konvertieren.
Es ist auch erwhnenswert, dass:
.mjs untersttzen.<script type="module"> wird verwendet, um anzugeben, wann auf ein Modul verwiesen wird, wie unter Anwenden des Moduls auf Ihr HTML beschrieben.Der erste Schritt, um Zugriff auf Modulfunktionen zu erhalten, ist deren Export. Dies wird mit der export-Anweisung durchgefhrt.
Die einfachste Mglichkeit, es zu verwenden, besteht darin, es vor alle Elemente zu setzen, die Sie aus dem Modul exportieren mchten, zum Beispiel:
export const name = "square";
export function draw(ctx, length, x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, length, length);
return { length, x, y, color };
}
Sie knnen Funktionen, var, let, const und wie wir spter sehen werden Klassen exportieren. Sie mssen Top-Level-Elemente sein: Zum Beispiel knnen Sie export nicht innerhalb einer Funktion verwenden.
Eine bequemere Mglichkeit, alle Elemente, die Sie exportieren mchten, zu exportieren, besteht darin, am Ende Ihrer Moduldaten eine einzige Exportanweisung zu verwenden, gefolgt von einer durch Kommas getrennten Liste der Funktionen, die Sie exportieren mchten, eingeschlossen in geschweifte Klammern. Zum Beispiel:
export { name, draw, reportArea, reportPerimeter };
Sobald Sie einige Funktionen aus Ihrem Modul exportiert haben, mssen Sie sie in Ihr Skript importieren, um sie nutzen zu knnen. Der einfachste Weg, dies zu tun, ist wie folgt:
import { name, draw, reportArea, reportPerimeter } from "./modules/square.js";
Sie verwenden die import-Anweisung, gefolgt von einer durch Kommas getrennten Liste der Funktionen, die Sie importieren mchten, eingeschlossen in geschweifte Klammern, gefolgt vom Schlsselwort from, gefolgt vom Modulspezifikator.
Der Modulspezifikator liefert einen String, den die JavaScript-Umgebung in einen Pfad zur Moduldaten umwandeln kann.
In einem Browser knnte dies ein relativer Pfad zum Site-Stamm sein, der fr unser basic-modules-Beispiel /js-examples/module-examples/basic-modules wre.
Hier verwenden wir jedoch die Punkt-Syntax (.), um "den aktuellen Ort" zu bedeuten, gefolgt vom relativen Pfad zu der Datei, die wir finden mchten. Dies ist viel besser, als jedes Mal den gesamten absoluten Pfad zu schreiben, da relative Pfade krzer sind und die URL portabel machen das Beispiel funktioniert auch, wenn Sie es an einen anderen Ort in der Site-Hierarchie verschieben.
Zum Beispiel:
/js-examples/module-examples/basic-modules/modules/square.js
wird zu
./modules/square.js
Sie knnen solche Zeilen in main.js in Aktion sehen.
Hinweis:
In einigen Modulsystemen knnen Sie einen Modulspezifikator wie modules/square verwenden, der kein relativer oder absoluter Pfad ist und keine Dateiendung hat.
Diese Art von Spezifikator kann in einer Browserumgebung verwendet werden, wenn Sie zuerst eine Importkarte definieren.
Sobald Sie die Funktionen in Ihr Skript importiert haben, knnen Sie diese genauso verwenden, als wren sie im selben File definiert. Das Folgende findet sich in main.js, unterhalb der Importzeilen:
const myCanvas = create("myCanvas", document.body, 480, 320);
const reportList = createReportList(myCanvas.id);
const square = draw(myCanvas.ctx, 50, 50, 100, "blue");
reportArea(square.length, reportList);
reportPerimeter(square.length, reportList);
Hinweis:
Die importierten Werte sind schreibgeschtzte Ansichten der exportierten Funktionen. hnlich wie const-Variablen knnen Sie die importierte Variable nicht neu zuweisen, aber Sie knnen weiterhin Eigenschaften von Objektwerten ndern. Der Wert kann nur vom Modul, das ihn exportiert hat, neu zugewiesen werden. Siehe die import Referenz fr ein Beispiel.
Oben haben wir gesehen, wie ein Browser ein Modul mit einem Modulspezifikator importieren kann, der entweder eine absolute URL oder eine relative URL ist, die mit der Basis-URL des Dokuments aufgelst wird:
import { name as circleName } from "https://example.com/shapes/circle.js";
import { name as squareName, draw } from "./shapes/square.js";
Importkarten erlauben es Entwicklern, fast jeden Text, den sie wollen, im Modulspezifikator beim Importieren eines Moduls zu spezifizieren; die Karte liefert einen entsprechenden Wert, der den Text beim Auflsen der Modul-URL ersetzt.
Zum Beispiel definiert der imports-Schlssel in der Importkarte unten ein "Modulspezifikator-Karten"-JSON-Objekt, bei dem die Eigenschaftsnamen als Modulspezifikatoren verwendet werden knnen, und die entsprechenden Werte beim Auflsen der Modul-URL ersetzt werden.
Die Werte mssen absolute oder relative URLs sein.
Relative URLs werden zu absoluten URL-Adressen aufgelst, wobei die Basis-URL des Dokuments verwendet wird, das die Importkarte enthlt.
<script type="importmap">
{
"imports": {
"shapes": "./shapes/square.js",
"shapes/square": "./modules/shapes/square.js",
"https://example.com/shapes/square.js": "./shapes/square.js",
"https://example.com/shapes/": "/shapes/square/",
"../shapes/square": "./shapes/square.js"
}
}
</script>
Die Importkarte wird mit einem JSON-Objekt innerhalb eines <script>-Elements definiert, bei dem das type-Attribut auf importmap gesetzt ist.
Beachten Sie, dass eine Importkarte nur auf das Dokument angewendet wird die Spezifikation behandelt nicht, wie eine Importkarte in einem Worker- oder Worklet-Kontext angewendet wird.
Mit dieser Karte knnen Sie nun die obigen Eigenschaftsnamen als Modulspezifikatoren verwenden. Wenn im Modulspezifikator-Schlssel kein Schluss-Schrgstrich vorhanden ist, wird der gesamte Modulspezifikator-Schlssel abgeglichen und ersetzt. Beispielsweise stimmen wir unten bereinstimmungen von nackten Modulnamen ab und mappen eine URL auf einen anderen Pfad um.
// Bare module names as module specifiers
import { name as squareNameOne } from "shapes";
import { name as squareNameTwo } from "shapes/square";
// Remap a URL to another URL
import { name as squareNameThree } from "https://example.com/shapes/square.js";
Wenn der Modulspezifikator einen Schluss-Schrgstrich hat, muss der Wert ebenfalls einen haben, und der Schlssel wird als "Pfad-Prfix" behandelt. Dies ermglicht die Umleitung ganzer Klassen von URLs.
// Remap a URL as a prefix ( https://example.com/shapes/)
import { name as squareNameFour } from "https://example.com/shapes/moduleshapes/square.js";
Es ist mglich, dass mehrere Schlssel in einer Importkarte gltige bereinstimmungen fr einen Modulspezifikator sind.
Wenn ein Modulspezifikator beispielsweise shapes/circle/ lautet, knnte er auf die Modulspezifikatorschlssel shapes/ und shapes/circle/ bereinstimmen.
In diesem Fall whlt der Browser den spezifischsten (lngsten) passenden Modulspezifikatorschlssel aus.
Importkarten ermglichen es, Module mit nackten Modulnamen zu importieren (wie in Node.js), und knnen auch das Importieren von Modulen aus Paketen simulieren, sowohl mit als auch ohne Dateierweiterungen. Obwohl oben nicht gezeigt, erlauben sie auch, bestimmte Versionen einer Bibliothek zu importieren, basierend auf dem Pfad des Skripts, das das Modul importiert. Sie lassen Entwickler im Allgemeinen ergonomischeren Importcode schreiben und erleichtern die Verwaltung der verschiedenen Versionen und Abhngigkeiten von Modulen, die von einer Website verwendet werden. Dies kann den Aufwand verringern, dieselben JavaScript-Bibliotheken sowohl im Browser als auch auf dem Server zu verwenden.
Die folgenden Abschnitte erweitern die oben beschriebenen verschiedenen Funktionen.
Sie knnen die Untersttzung von Importkarten mit der statischen Methode HTMLScriptElement.supports() prfen (die selbst breit untersttzt wird):
if (HTMLScriptElement.supports?.("importmap")) {
console.log("Browser supports import maps.");
}
In einigen JavaScript-Umgebungen, wie z.B. Node.js, knnen Sie nackte Namen fr den Modulspezifikator verwenden. Das funktioniert, weil die Umgebung Modulnamen auf einen Standardstandort im Dateisystem auflsen kann. Zum Beispiel knnten Sie die folgende Syntax verwenden, um das "square"-Modul zu importieren.
import { name, draw, reportArea, reportPerimeter } from "square";
Um nackte Namen in einem Browser zu verwenden, bentigen Sie eine Importkarte, die dem Browser die Informationen liefert, die er bentigt, um Modulspezifikatoren in URLs aufzulsen (JavaScript wirft einen TypeError, wenn es versucht, einen Modulspezifikator zu importieren, der nicht in einen Modulspeicherort aufgelst werden kann).
Unten sehen Sie eine Karte, die einen square-Modulspezifikatorschlssel definiert, der in diesem Fall einer relativen Adresswert zugeordnet ist.
<script type="importmap">
{
"imports": {
"square": "./shapes/square.js"
}
}
</script>
Mit dieser Karte knnen wir nun einen nackten Namen verwenden, wenn wir das Modul importieren:
import { name as squareName, draw } from "square";
Eintrge in der Modulspezifikatorkarte, bei denen sowohl der Spezifikatorschlssel als auch sein zugehriger Wert einen Endschrgstrich (/) haben, knnen als Pfad-Prfix verwendet werden.
Dies ermglicht die Umleitung eines gesamten Sets von Import-URLs von einem Standort zu einem anderen.
Es kann auch verwendet werden, um das Arbeiten mit "Paketen und Modulen" zu emulieren, wie Sie es in einem Node-kosystem sehen knnten.
Hinweis:
Der Schluss-/ zeigt an, dass der Modulspezifikatorschlssel als Teil eines Modulspezifikators ersetzt werden kann.
Wenn das nicht vorhanden ist, wird der Browser nur den gesamten Modulspezifikatorschlssel abgleichen (und ersetzen).
Die folgende JSON-Importkartendefinition ordnet lodash als nackten Namen zu und den Modulspezifikator-Prfix lodash/ auf den Pfad /node_modules/lodash-es/ (aufgelst zur Basis-URL des Dokuments):
{
"imports": {
"lodash": "/node_modules/lodash-es/lodash.js",
"lodash/": "/node_modules/lodash-es/"
}
}
Mit dieser Zuordnung knnen Sie sowohl das gesamte "Paket" mit dem nackten Namen als auch Module innerhalb davon importieren (mithilfe des Pfadmappings):
import _ from "lodash";
import fp from "lodash/fp.js";
Es ist mglich, fp ohne die .js-Dateierweiterung zu importieren, aber Sie mssten einen nackten Modulspezifikatorschlssel fr diese Datei erstellen, wie z.B. lodash/fp, anstatt den Pfad zu verwenden.
Das mag fr nur ein Modul vernnftig sein, skaliert jedoch schlecht, wenn Sie viele Module importieren mchten.
Ein Modulspezifikatorschlssel braucht kein Pfad zu sein er kann auch eine absolute URL (oder ein URL-hnlicher relativer Pfad wie ./, ../, /) sein.
Dies kann ntzlich sein, wenn Sie ein Modul umleiten mchten, das absolute Pfade zu einem Ressourcen hat, mit Ihren eigenen lokalen Ressourcen.
{
"imports": {
"https://www.unpkg.com/moment/": "/node_modules/moment/"
}
}
kosysteme wie Node verwenden Paketmanager wie npm, um Module und deren Abhngigkeiten zu verwalten. Der Paketmanager sorgt dafr, dass jedes Modul von anderen Modulen und ihren Abhngigkeiten getrennt ist. Infolgedessen enthlt eine komplexe Anwendung mglicherweise dasselbe Modul mehrfach mit verschiedenen Versionen in verschiedenen Teilen des Modulgrafen, aber die Benutzer mssen sich keine Gedanken ber diese Komplexitt machen.
Hinweis: Sie knnen das Versionsmanagement auch mit relativen Pfaden erreichen, aber das ist suboptimal, weil es unter anderem eine bestimmte Struktur auf Ihr Projekt zwingt und Sie daran hindert, nackte Modulnamen zu verwenden.
Importkarten ermglichen es Ihnen hnlich, mehrere Versionen von Abhngigkeiten in Ihrer Anwendung zu haben und auf sie mit demselben Modulspezifikator zu verweisen.
Sie implementieren dies mit dem scopes-Schlssel, der es Ihnen ermglicht, Modulspezifikatorkarten bereitzustellen, die je nach Pfad des Skripts, das den Import durchfhrt, verwendet werden.
Das folgende Beispiel zeigt dies.
{
"imports": {
"cool-module": "/node_modules/cool-module/index.js"
},
"scopes": {
"/node_modules/dependency/": {
"cool-module": "/node_modules/some/other/location/cool-module/index.js"
}
}
}
Mit dieser Zuordnung, wenn ein Skript mit einer URL, die /node_modules/dependency/ enthlt, cool-module importiert, wird die Version in /node_modules/some/other/location/cool-module/index.js verwendet.
Die Karte in imports wird als Fallback verwendet, wenn kein bereinstimmender Scope in der gescopten Karte vorhanden ist oder die bereinstimmenden Scopes keinen bereinstimmenden Spezifikator enthalten. Wenn cool-module zum Beispiel von einem Skript mit einem nicht bereinstimmenden Scopes-Pfad importiert wird, wird stattdessen die Modulspezifikatorkarte im imports-Schlssel verwendet, die zur Version in /node_modules/cool-module/index.js fhrt.
Beachten Sie, dass der Pfad, der verwendet wird, um einen Scope auszulsen, die Adresse, die aufgelst wird, nicht beeinflusst. Der Wert im gemappten Pfad muss nicht mit dem Scopes-Pfad bereinstimmen, und relative Pfade werden immer noch auf die Basis-URL des Skripts aufgelst, das die Importkarte enthlt.
Genauso wie fr Modulspezifikatorkarten, knnen Sie viele Scopes-Schlssel haben, und diese knnen sich berlappende Pfade enthalten.
Wenn mehrere Scopes zu der Referrer-URL passen, wird zuerst der spezifischste Scope-Pfad geprft (der lngste Scopes-Schlssel) auf einen passenden Specifikator.
Die Browser fallen auf den nchst spezifischsten bereinstimmenden gescopten Pfad zurck, wenn kein bereinstimmender Specifikator vorhanden ist, und so weiter.
Wenn es keinen bereinstimmenden Specifikator in einem der bereinstimmenden Scopes gibt, prft der Browser auf eine bereinstimmung in der Modulspezifikatorkarte im imports-Schlssel.
Skriptdateien, die von Websites verwendet werden, haben oft gehashte Dateinamen, um das Caching zu vereinfachen. Der Nachteil dieses Ansatzes ist, dass, wenn sich ein Modul ndert, auch alle Module, die es mit seinem gehashten Dateinamen importieren, aktualisiert/regeneriert werden mssen. Dies kann zu Kaskadenaktualisierungen fhren, das ist eine Verschwendung von Netzwerkressourcen.
Importkarten bieten eine praktische Lsung fr dieses Problem. Anstatt sich auf spezifische gehashte Dateinamen zu verlassen, verlassen sich Anwendungen und Skripte auf eine unangeschlossene Version des Modulnamens (der Adresse). Eine Importkarte wie die untenstehende stellt dann eine Zuordnung zur tatschlichen Skriptdatei bereit.
{
"imports": {
"main_script": "/node/srcs/application-fg7744e1b.js",
"dependency_script": "/node/srcs/dependency-3qn7e4b1q.js"
}
}
Wenn sich dependency_script ndert, ndert sich auch sein Hash, der im Dateinamen enthalten ist. In diesem Fall mssen wir nur die Importkarte aktualisieren, um den genderten Namen des Moduls widerzuspiegeln.
Wir mssen den Quelltext von JavaScript-Code, der davon abhngt, nicht aktualisieren, da der Spezifikator in der Importanweisung nicht gendert wurde.
Ein aufregendes Feature, das eine einheitliche Modularchitektur mit sich bringt, ist die Mglichkeit, nicht-JavaScript-Ressourcen als Module zu laden. Zum Beispiel knnen Sie JSON als JavaScript-Objekt importieren oder CSS als CSSStyleSheet-Objekt importieren.
Sie mssen explizit angeben, welche Art von Ressource Sie importieren. Standardmig geht der Browser davon aus, dass es sich bei der Ressource um JavaScript handelt und wird einen Fehler werfen, wenn die aufgelste Ressource etwas anderes ist. Um JSON, CSS oder andere Ressourcentypen zu importieren, verwenden Sie die Import-Attribute-Syntax:
import colors from "./colors.json" with { type: "json" };
import styles from "./styles.css" with { type: "css" };
Browser werden auch eine Validierung des Modultyps durchfhren und fehlschlagen, wenn zum Beispiel ./data.json nicht in eine JSON-Datei aufgelst wird. Dies stellt sicher, dass Sie nicht versehentlich Code ausfhren, wenn Sie nur Daten importieren mchten. Sobald erfolgreich importiert, knnen Sie den importierten Wert jetzt als normales JavaScript-Objekt oder CSSStyleSheet Objekt verwenden.
console.log(colors.map((color) => color.value));
document.adoptedStyleSheets = [styles];
Nun mssen wir nur noch das main.js-Modul auf unsere HTML-Seite anwenden. Dies ist sehr hnlich wie bei einem regulren Skript, mit einigen bemerkenswerten Unterschieden.
Erstens mssen Sie type="module" im <script>-Element einfgen, um dieses Skript als Modul zu deklarieren. Um das main.js-Skript zu importieren, verwenden Sie dies:
<script type="module" src="main.js"></script>
Sie knnen das Modul-Skript auch direkt in die HTML-Datei einbetten, indem Sie den JavaScript-Code innerhalb des <script>-Elements platzieren:
<script type="module">
/* JavaScript module code here */
</script>
Sie knnen import- und export-Anweisungen nur innerhalb von Modulen verwenden, nicht in regulren Skripten. Ein Fehler wird ausgelst, wenn Ihr <script>-Element nicht das type="module"-Attribut hat und versucht, andere Module zu importieren. Zum Beispiel:
<script>
import _ from "lodash"; // SyntaxError: import declarations may only appear at top level of a module
//
</script>
<script src="a-module-using-import-statements.js"></script>
<!-- SyntaxError: import declarations may only appear at top level of a module -->
Sie sollten im Allgemeinen alle Ihre Module in separaten Dateien definieren. Module, die inline in HTML deklariert werden, knnen nur andere Module importieren, aber alles, was sie exportieren, wird von anderen Modulen nicht zugnglich sein (weil sie keine URL haben).
Hinweis:
Module und ihre Abhngigkeiten knnen vorab geladen werden, indem sie in <link>-Elementen mit rel="modulepreload" angegeben werden.
Dies kann die Ladezeit erheblich reduzieren, wenn die Module verwendet werden.
file://-URL) zu laden, stoen Sie auf CORS-Fehler aufgrund der Sicherheitsanforderungen von JavaScript-Modulen. Sie mssen Ihre Tests ber einen Server durchfhren.defer-Attribut (siehe <script>-Attribute) zu verwenden, wenn ein Modulskript geladen wird; Module werden automatisch verzgert geladen.<script>-Tags referenziert wurden.Module-definierte Variablen sind auf das Modul beschrnkt, es sei denn, sie sind explizit an das globale Objekt angehngt. Andererseits sind global-definierte Variablen im Modul verfgbar. Zum Beispiel, bei folgendem Code:
<!doctype html>
<html lang="en-US">
<head>
<meta charset="UTF-8" />
<title>Example page</title>
<link rel="stylesheet" href="" />
</head>
<body>
<div id="main"></div>
<script>
// A var statement creates a global variable.
var text = "Hello";
</script>
<script type="module" src="./render.js"></script>
</body>
</html>
/* render.js */
document.getElementById("main").innerText = text;
Die Seite wrde trotzdem Hello rendern, weil die globalen Variablen text und document im Modul verfgbar sind. (Beachten Sie auch in diesem Beispiel, dass ein Modul nicht unbedingt eine Import-/Export-Anweisung bentigt das Einzige, was bentigt wird, ist, dass der Einstiegspunkt type="module" hat.)
Die Funktionalitt, die wir bisher exportiert haben, bestand aus benannten Exporten jedes Element (sei es eine Funktion, const, usw.) wurde beim Export mit seinem Namen bezeichnet, und dieser Name wurde auch beim Import dafr verwendet.
Es gibt auch einen Exporttyp, der Standardexport genannt wird dieser wurde entwickelt, um es einfach zu machen, eine Standardfunktion bereitzustellen, die von einem Modul angeboten wird, und hilft auch, JavaScript-Module mit bestehenden CommonJS- und AMD-Modulsystemen zu interagieren (wie gut erklrt in ES6 In Depth: Modules von Jason Orendorff; suchen Sie nach "Default exports").
Schauen wir uns ein Beispiel an, whrend wir erklren, wie es funktioniert. In unserem square.js in den basic-modules finden Sie eine Funktion namens randomSquare(), die ein Quadrat mit zuflliger Farbe, Gre und Position erstellt. Wir mchten dies als unseren Standardexport durchfhren, daher schreiben wir am Ende der Datei dies:
export default randomSquare;
Beachten Sie das Fehlen von geschweiften Klammern.
Wir knnten stattdessen export default an die Funktion anheften und sie als anonyme Funktion definieren, wie folgt:
export default function (ctx) {
//
}
In unserer main.js-Datei importieren wir die Standardfunktion mit dieser Zeile:
import randomSquare from "./modules/square.js";
Auch hier das Fehlen von geschweiften Klammern. Das liegt daran, dass pro Modul nur ein Standardexport erlaubt ist, und wir wissen, dass es randomSquare ist. Die obige Zeile ist im Grunde eine Abkrzung fr:
import { default as randomSquare } from "./modules/square.js";
Hinweis: Die Syntax "as", um exportierte Elemente umzubenennen, wird im Abschnitt Umbenennen von Importen und Exporten unten erklrt.
Bisher scheinen unsere Module zum Zeichnen von Formen auf der Leinwand gut zu funktionieren. Aber was passiert, wenn wir versuchen, ein Modul hinzuzufgen, das sich mit dem Zeichnen einer anderen Form wie einem Kreis oder Dreieck befasst? Diese Formen htten wahrscheinlich auch zugehrige Funktionen wie draw(), reportArea(), usw.; wenn wir versuchen, verschiedene Funktionen mit demselben Namen in die gleiche oberste Moduldaten zu importieren, wrden wir auf Konflikte und Fehler stoen.
Zum Glck gibt es eine Reihe von Mglichkeiten, dies zu umgehen. Wir werden uns diese in den folgenden Abschnitten ansehen.
Innerhalb der geschweiften Klammern Ihrer import- und export-Anweisung knnen Sie das Schlsselwort as zusammen mit einem neuen Funktionsnamen verwenden, um den identifizierenden Namen zu ndern, den Sie fr eine Funktion innerhalb des obersten Moduls verwenden werden.
Zum Beispiel, beide der folgenden wrden die gleiche Aufgabe erfllen, wenn auch auf leicht unterschiedliche Weise:
// -- module.js --
export { function1 as newFunctionName, function2 as anotherNewFunctionName };
// -- main.js --
import { newFunctionName, anotherNewFunctionName } from "./modules/module.js";
// -- module.js --
export { function1, function2 };
// -- main.js --
import {
function1 as newFunctionName,
function2 as anotherNewFunctionName,
} from "./modules/module.js";
Schauen wir uns ein echtes Beispiel an. In unserem renaming-Verzeichnis werden Sie dasselbe Modulsystem wie im vorherigen Beispiel sehen, auer dass wir die Module circle.js und triangle.js hinzugefgt haben, um Kreise und Dreiecke zu zeichnen und darber zu berichten.
In jedem dieser Module haben wir Funktionen mit denselben Namen, die exportiert werden, und daher hat jeder das gleiche export Statement am Ende:
export { name, draw, reportArea, reportPerimeter };
Wenn wir sie in main.js importieren und versuchen,
import { name, draw, reportArea, reportPerimeter } from "./modules/square.js";
import { name, draw, reportArea, reportPerimeter } from "./modules/circle.js";
import { name, draw, reportArea, reportPerimeter } from "./modules/triangle.js";
wrde der Browser einen Fehler wie "SyntaxError: redeclaration of import name" werfen (Firefox).
Stattdessen mssen wir die Importe umbenennen, damit sie eindeutig sind:
import {
name as squareName,
draw as drawSquare,
reportArea as reportSquareArea,
reportPerimeter as reportSquarePerimeter,
} from "./modules/square.js";
import {
name as circleName,
draw as drawCircle,
reportArea as reportCircleArea,
reportPerimeter as reportCirclePerimeter,
} from "./modules/circle.js";
import {
name as triangleName,
draw as drawTriangle,
reportArea as reportTriangleArea,
reportPerimeter as reportTrianglePerimeter,
} from "./modules/triangle.js";
Beachten Sie, dass Sie das Problem auch in den Moduldaten lsen knnten, z.B.
// in square.js
export {
name as squareName,
draw as drawSquare,
reportArea as reportSquareArea,
reportPerimeter as reportSquarePerimeter,
};
// in main.js
import {
squareName,
drawSquare,
reportSquareArea,
reportSquarePerimeter,
} from "./modules/square.js";
Und es wrde genauso funktionieren. Welche Stilrichtung Sie verwenden, liegt bei Ihnen, allerdings macht es mehr Sinn, Ihren Modulcode unangetastet zu lassen und die nderungen in den Importen vorzunehmen. Das macht besonders dann Sinn, wenn Sie aus Drittanbieter-Modulen importieren, ber die Sie keine Kontrolle haben.
Die obige Methode funktioniert okay, aber sie ist ein wenig unordentlich und langwierig. Eine noch bessere Lsung ist, die Funktionen jedes Moduls innerhalb eines Modulobjekts zu importieren. Die folgende Syntax macht das:
import * as Module from "./modules/module.js";
Dies greift alle verfgbaren Exporte im module.js und stellt sie als Mitglieder eines Objekts Module bereit, es gibt ihm effektiv seinen eigenen Namensraum. Zum Beispiel:
Module.function1();
Module.function2();
Wieder einmal schauen wir uns ein echtes Beispiel an. Wenn Sie in unser module-objects-Verzeichnis gehen, sehen Sie dasselbe Beispiel erneut, aber umgeschrieben, um diesen neuen Syntaxvorteil zu nutzen. In den Modulen sind die Exporte alle in der folgenden einfachen Form:
export { name, draw, reportArea, reportPerimeter };
Die Importe andererseits sehen so aus:
import * as Canvas from "./modules/canvas.js";
import * as Square from "./modules/square.js";
import * as Circle from "./modules/circle.js";
import * as Triangle from "./modules/triangle.js";
In jedem dieser Flle knnen Sie jetzt auf die Importe des Moduls unterhalb des angegebenen Objektnamens zugreifen, z.B.:
const square = Square.draw(myCanvas.ctx, 50, 50, 100, "blue");
Square.reportArea(square.length, reportList);
Square.reportPerimeter(square.length, reportList);
So knnen Sie den Code genauso wie zuvor schreiben (solange Sie die Objektnamen dort einfgen, wo ntig), und die Importe sind viel aufgerumter.
Wie wir zuvor angedeutet haben, knnen Sie auch Klassen exportieren und importieren; das ist eine weitere Mglichkeit, Konflikte in Ihrem Code zu vermeiden und ist besonders ntzlich, wenn Sie Ihren Modulcode bereits in einem objektorientierten Stil geschrieben haben.
Sie knnen ein Beispiel unseres Modul zum Zeichnen von Formen mit ES-Klassen umgeschrieben in unserem classes-Verzeichnis finden. Als Beispiel enthlt die square.js-Datei jetzt alle seine Funktionalitt in einer einzigen Klasse:
class Square {
constructor(ctx, listId, length, x, y, color) {
//
}
draw() {
//
}
//
}
die wir dann exportieren:
export { Square };
In main.js importieren wir es so:
import { Square } from "./modules/square.js";
Und dann benutzen wir die Klasse, um unser Quadrat zu zeichnen:
const square = new Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, "blue");
square.draw();
square.reportArea();
square.reportPerimeter();
Es wird Zeiten geben, in denen Sie Module zusammenfassen mchten. Vielleicht haben Sie mehrere Ebenen von Abhngigkeiten, bei denen Sie Dinge vereinfachen mchten, indem Sie mehrere Untermodule zu einem bergeordneten Modul kombinieren. Dies ist mit Export-Syntax in der folgenden Form im bergeordneten Modul mglich:
export * from "x.js";
export { name } from "x.js";
Fr ein Beispiel sehen Sie unser module-aggregation-Verzeichnis. In diesem Beispiel (basierend auf unserem frheren Klassenbeispiel) haben wir ein zustzliches Modul namens shapes.js, das alle Funktionen von circle.js, square.js und triangle.js zusammenfasst. Wir haben auch unsere Untermodule in ein Unterverzeichnis im modules-Verzeichnis namens shapes verschoben. Die Modulstruktur in diesem Beispiel ist:
modules/
canvas.js
shapes.js
shapes/
circle.js
square.js
triangle.js
In jedem der Untermodule ist der Export in der gleichen Form, z.B.:
export { Square };
Der nchste Schritt ist der Aggregationsteil. In shapes.js fgen wir diese Zeilen ein:
export { Square } from "./shapes/square.js";
export { Triangle } from "./shapes/triangle.js";
export { Circle } from "./shapes/circle.js";
Diese greifen die Exporte der einzelnen Untermodule und machen sie effektiv vom shapes.js-Modul verfgbar.
Hinweis:
Die Exporte, die in shapes.js referenziert werden, werden im Grunde genommen ber die Datei umgeleitet und existieren dort nicht wirklich, also knnen Sie dort keine ntzlichen verwandten Codes schreiben.
Also knnen wir jetzt im main.js-File auf alle drei Modulklassen zugreifen, indem wir
import { Square } from "./modules/square.js";
import { Circle } from "./modules/circle.js";
import { Triangle } from "./modules/triangle.js";
mit der folgenden Einzelzeile ersetzen:
import { Square, Circle, Triangle } from "./modules/shapes.js";
Eine aktuelle Ergnzung zur JavaScript-Modulfunktionalitt ist das dynamische Laden von Modulen. Dies ermglicht es, Module dynamisch nur dann zu laden, wenn sie bentigt werden, anstatt alles im Voraus laden zu mssen. Dies hat einige offensichtliche Leistungsvorteile; lesen wir weiter und sehen, wie es funktioniert.
Diese neue Funktionalitt ermglicht es Ihnen, import() als Funktion aufzurufen und den Pfad zum Modul als Parameter zu bergeben. Es gibt ein Promise zurck, das mit einem Modulobjekt erfllt wird (siehe Creating a module object), das Ihnen Zugriff auf die Exporte dieses Objekts gibt. Zum Beispiel:
import("./modules/myModule.js").then((module) => {
// Do something with the module.
});
Hinweis:
Dynamischer Import ist im Haupt-Thread des Browsers, sowie in geteilten und dedizierten Workern erlaubt.
Jedoch wird import() ein Fehler auslsen, wenn es in einem Service-Worker oder Worklet aufgerufen wird.
Schauen wir uns ein Beispiel an. In dem Verzeichnis dynamic-module-imports haben wir ein weiteres Beispiel, das auf unserem Klassenbeispiel basiert. Diesmal zeichnen wir jedoch nichts auf der Leinwand, wenn das Beispiel geladen wird. Stattdessen haben wir drei Schaltflchen "Circle", "Square" und "Triangle" die, wenn sie gedrckt werden, das erforderliche Modul dynamisch laden und dann verwenden, um die zugehrige Form zu zeichnen.
In diesem Beispiel haben wir nur nderungen an unseren index.html- und main.js-Dateien gemacht die Modulausfuhrungen bleiben wie zuvor.
In main.js haben wir eine Referenz zu jeder Schaltflche mit einem document.querySelector()-Aufruf erhalten, zum Beispiel:
const squareBtn = document.querySelector(".square");
Wir fgen dann jedem Button einen Ereignis-Listener hinzu, sodass beim Drcken das relevante Modul dynamisch geladen und zur Zeichnung der Form verwendet wird:
squareBtn.addEventListener("click", () => {
import("./modules/square.js").then((Module) => {
const square = new Module.Square(
myCanvas.ctx,
myCanvas.listId,
50,
50,
100,
"blue",
);
square.draw();
square.reportArea();
square.reportPerimeter();
});
});
Beachten Sie, dass, weil die Promise-Erfllung ein Modulobjekt zurckgibt, die Klasse dann ein Subfeature des Objekts wird, daher mssen wir jetzt mit vorangestellten Module. auf den Konstruktor zugreifen, z.B., Module.Square( /* */ ).
Ein weiterer Vorteil von dynamischen Importen ist, dass sie immer verfgbar sind, auch in Skript-Umgebungen. Daher, wenn Sie ein vorhandenes <script>-Tag in Ihrem HTML haben, das nicht type="module" hat, knnen Sie den als Module verteilten Code dennoch dynamisch importieren.
<script>
import("./modules/square.js").then((module) => {
// Do something with the module.
});
// Other code that operates on the global scope and is not
// ready to be refactored into modules yet.
var btn = document.querySelector(".square");
</script>
Top-Level-Await ist eine Funktion, die innerhalb von Modulen verfgbar ist. Dies bedeutet, dass das await-Schlsselwort verwendet werden kann. Es ermglicht Module, wie groe asynchrone Funktionen zu agieren, was bedeutet, dass der Code vor der Nutzung in bergeordneten Modulen ausgewertet werden kann, ohne dass andere Module am Laden gehindert werden.
Betrachten wir ein Beispiel. Sie finden alle in diesem Abschnitt beschriebenen Dateien und Code im Verzeichnis top-level-await, das von den vorherigen Beispielen ausgeht.
Zunchst deklarieren wir unsere Farbpalette in einer separaten Datei colors.json:
{
"yellow": "#F4D03F",
"green": "#52BE80",
"blue": "#5499C7",
"red": "#CD6155",
"orange": "#F39C12"
}
Anschlieend erstellen wir ein Modul namens getColors.js, das eine Fetch-Anfrage verwendet, um die Datei colors.json zu laden und die Daten als Objekt zurckzugeben.
// fetch request
const colors = fetch("../data/colors.json").then((response) => response.json());
export default await colors;
Beachten Sie die letzte Exportzeile hier.
Wir verwenden das Schlsselwort await, bevor wir die Konstante colors angeben, die exportiert wird. Das bedeutet, dass alle anderen Module, die dieses enthalten, warten, bis colors heruntergeladen und geparst wurde, bevor sie es verwenden.
Lassen Sie uns dieses Module in unserer main.js Datei einbinden:
import colors from "./modules/getColors.js";
import { Canvas } from "./modules/canvas.js";
const circleBtn = document.querySelector(".circle");
//
Wir verwenden colors anstelle der zuvor verwendeten Strings, wenn wir unsere Formfunktionen aufrufen:
const square = new Module.Square(
myCanvas.ctx,
myCanvas.listId,
50,
50,
100,
colors.blue,
);
const circle = new Module.Circle(
myCanvas.ctx,
myCanvas.listId,
75,
200,
100,
colors.green,
);
const triangle = new Module.Triangle(
myCanvas.ctx,
myCanvas.listId,
100,
75,
190,
colors.yellow,
);
Das ist ntzlich, weil der Code in main.js nicht ausgefhrt wird, bis der Code in getColors.js gelaufen ist. Es wird jedoch das Laden anderer Module nicht blockieren. Zum Beispiel wird unser Modul canvas.js weiterhin geladen, whrend colors abgerufen wird.
Import-Deklarationen werden gehoben. In diesem Fall bedeutet das, dass die importierten Werte im Code des Moduls verfgbar sind, noch bevor sie an der Stelle deklariert werden, und dass die Nebeneffekte des importierten Moduls vor dem Start des restlichen Modulcodes erzeugt werden.
Zum Beispiel wrde das Importieren von Canvas in der Mitte des Codes in main.js trotzdem funktionieren:
//
const myCanvas = new Canvas("myCanvas", document.body, 480, 320);
myCanvas.create();
import { Canvas } from "./modules/canvas.js";
myCanvas.createReportList();
//
Dennoch wird empfohlen, all Ihre Importe am Anfang des Codes zu platzieren, was es einfacher macht, Abhngigkeiten zu analysieren.
Module knnen andere Module importieren, und diese Module knnen andere Module importieren, und so weiter. Dies bildet einen gerichteten Graphen, der als "Abhngigkeitsgraph" bezeichnet wird. In einer idealen Welt ist dieser Graph azyklisch. In diesem Fall kann der Graph mit einem Tiefen-First-Durchgang ausgewertet werden.
Zyklen sind jedoch oft unvermeidlich. Zyklischer Import entsteht, wenn Modul a Modul b importiert, aber b direkt oder indirekt von a abhngt. Zum Beispiel:
// -- a.js --
import { b } from "./b.js";
// -- b.js --
import { a } from "./a.js";
// Cycle:
// a.js > b.js
// ^
//
Zyklische Importe schlagen nicht immer fehl. Der Wert der importierten Variable wird nur dann abgerufen, wenn die Variable tatschlich verwendet wird (wodurch lebende Bindungen ermglicht werden), und nur wenn die Variable zu diesem Zeitpunkt nicht initialisiert ist, wird ein ReferenceError ausgelst.
// -- a.js --
import { b } from "./b.js";
setTimeout(() => {
console.log(b); // 1
}, 10);
export const a = 2;
// -- b.js --
import { a } from "./a.js";
setTimeout(() => {
console.log(a); // 2
}, 10);
export const b = 1;
In diesem Beispiel werden sowohl a als auch b asynchron verwendet. Daher wird zur Zeit der Modulauswertung weder b noch a tatschlich gelesen, wodurch der Rest des Codes normal ausgefhrt wird, und die beiden export-Deklarationen die Werte von a und b erzeugen. Danach, nach dem Timeout, sind sowohl a als auch b verfgbar, daher werden die beiden console.log-Anweisungen ebenfalls normal ausgefhrt.
Wenn Sie den Code ndern, um a synchron zu verwenden, schlgt die Modulauswertung fehl:
// -- a.js (entry module) --
import { b } from "./b.js";
export const a = 2;
// -- b.js --
import { a } from "./a.js";
console.log(a); // ReferenceError: Cannot access 'a' before initialization
export const b = 1;
Das liegt daran, dass, wenn JavaScript a.js auswertet, es zuerst b.js, die Abhngigkeit von a.js, auswerten muss. Aber b.js verwendet a, was noch nicht verfgbar ist.
Andererseits, wenn Sie den Code ndern, um b synchron, aber a asynchron zu verwenden, wird die Modulauswertung erfolgreich sein:
// -- a.js (entry module) --
import { b } from "./b.js";
console.log(b); // 1
export const a = 2;
// -- b.js --
import { a } from "./a.js";
setTimeout(() => {
console.log(a); // 2
}, 10);
export const b = 1;
Das liegt daran, dass die Auswertung von b.js normal abgeschlossen wird, sodass der Wert von b verfgbar ist, wenn a.js ausgewertet wird.
In Ihrem Projekt sollten Sie zyklische Importe in der Regel vermeiden, da sie Ihren Code fehleranflliger machen. Einige gngige Methoden zur Zyklenbeseitigung sind:
Zyklische Importe knnen jedoch auftreten, wenn die Bibliotheken voneinander abhngen, was schwieriger zu beheben ist.
Mit der Einfhrung von Modulen wird das JavaScript-kosystem ermutigt, Code modular zu vertreiben und wiederzuverwenden. Das bedeutet jedoch nicht unbedingt, dass ein JavaScript-Code in jeder Umgebung ausgefhrt werden kann. Angenommen, Sie haben ein Modul entdeckt, das SHA-Hashes des Passworts Ihrer Benutzer generiert. Knnen Sie es im Frontend des Browsers verwenden? Knnen Sie es auf Ihrem Node.js-Server verwenden? Die Antwort lautet: es hngt davon ab.
Module haben nach wie vor Zugriff auf globale Variablen, wie bereits gezeigt. Wenn das Modul auf globale Variablen wie window verweist, kann es im Browser ausgefhrt werden, wird jedoch einen Fehler auf Ihrem Node.js-Server werfen, da window dort nicht verfgbar ist. Ebenso, wenn der Code Zugriff auf process bentigt, um zu funktionieren, kann er nur in Node.js verwendet werden.
Um die Wiederverwendbarkeit eines Moduls maximal zu erhhen, wird oft empfohlen, den Code "isomorph" zu gestalten das heit, er zeigt in jeder Laufzeitumgebung das gleiche Verhalten. Dies wird blicherweise auf drei Weisen erreicht:
Trennen Sie Ihre Module in "Core" und "Binding". Fr den "Core" konzentrieren Sie sich auf die reine JavaScript-Logik wie das Berechnen des Hashs, ohne DOM-, Netzwerk- oder Dateisystemzugriff und stellen Sie Dienstfunktionen bereit. Fr den "Binding"-Teil knnen Sie aus dem globalen Kontext lesen und schreiben. Zum Beispiel knnte das "Browser-Binding" whlen, den Wert aus einem Eingabefeld zu lesen, whrend das "Node-Binding" es eventuell aus process.env liest, aber die aus beiden Stellen gelesenen Werte werden an dieselbe Core-Funktion bergeben und auf die gleiche Weise behandelt. Der Core kann in jeder Umgebung importiert und auf die gleiche Weise verwendet werden, whrend nur das Binding, das normalerweise leichtgewichtig ist, plattformspezifisch sein muss.
Prfen Sie, ob ein bestimmtes Global existiert, bevor Sie es verwenden. Zum Beispiel, wenn Sie testen, dass typeof window === "undefined", wissen Sie, dass Sie sich wahrscheinlich in einer Node.js-Umgebung befinden und nicht auf den DOM zugreifen sollten.
// myModule.js
let password;
if (typeof process !== "undefined") {
// We are running in Node.js; read it from `process.env`
password = process.env.PASSWORD;
} else if (typeof window !== "undefined") {
// We are running in the browser; read it from the input box
password = document.getElementById("password").value;
}
Dies ist vorzuziehen, wenn die beiden Zweige tatschlich mit demselben Verhalten enden ("isomorph"). Wenn es unmglich ist, dieselbe Funktionalitt bereitzustellen, oder wenn dies das Laden betrchtlicher Mengen an Code mit sich bringt, whrend ein groer Teil davon ungenutzt bleibt, nutzen Sie besser unterschiedliche "Bindings".
Verwenden Sie einen Polyfill, um eine Alternative fr fehlende Funktionen bereitzustellen. Zum Beispiel, wenn Sie die fetch-Funktion verwenden mchten, die in Node.js nur ab v18 untersttzt wird, knnen Sie eine hnliche API verwenden, wie sie von node-fetch bereitgestellt wird. Sie knnen dies bedingt durch dynamischen Import tun:
// myModule.js
if (typeof fetch === "undefined") {
// We are running in Node.js; use node-fetch
globalThis.fetch = (await import("node-fetch")).default;
}
//
Die globalThis-Variable ist ein globales Objekt, das in jeder Umgebung verfgbar ist und ntzlich ist, wenn Sie globale Variablen innerhalb von Modulen lesen oder erstellen mchten.
Diese Praktiken sind nicht einzigartig fr Module. Dennoch werden Sie mit dem Trend zur Wiederverwendbarkeit von Code und Modularisierung ermutigt, Ihren Code plattformbergreifend zu gestalten, damit er von so vielen Menschen wie mglich genutzt werden kann. Laufzeiten wie Node.js implementieren auch aktiv Web-APIs, wo dies mglich ist, um die Interoperabilitt mit dem Web zu verbessern.
Hier sind ein paar Tipps, die Ihnen helfen knnen, wenn Sie Schwierigkeiten haben, Ihre Module zum Laufen zu bringen. Fhlen Sie sich frei, zur Liste hinzuzufgen, wenn Sie mehr entdecken!
.mjs-Dateien mssen mit einem MIME-Typ von text/javascript (oder einem anderen JavaScript-kompatiblen MIME-Typ, aber text/javascript wird empfohlen) geladen werden, ansonsten erhalten Sie ein striktes MIME-Typ-berprfungs-Fehler, wie "Der Server antwortete mit einem Nicht-JavaScript-MIME-Typ".file://-URL), stoen Sie aufgrund der Sicherheitsanforderungen von JavaScript-Modulen auf CORS-Fehler. Sie mssen Ihre Tests ber einen Server durchfhren. GitHub Pages ist ideal, da es auch .mjs-Dateien mit dem korrekten MIME-Typ bereitstellt..mjs eine nicht standardmige Dateierweiterung ist, erkennen einige Betriebssysteme sie mglicherweise nicht, oder versuchen, sie durch etwas anderes zu ersetzen. Zum Beispiel haben wir festgestellt, dass macOS stillschweigend ein .js ans Ende von .mjs-Dateien angefgt hat und dann automatisch die Dateierweiterung versteckt. So kamen all unsere Dateien tatschlich als x.mjs.js heraus. Sobald wir das automatische Verstecken von Dateiendungen abgeschaltet und es antrainiert hatten, .mjs zu akzeptieren, war es ok.Der Bauplan fr ein besseres Internet.
Teile dieses Inhalts sind 19982026 von einzelnen mozilla.org-Mitwirkenden. Inhalte sind verfgbar unter einer Creative-Commons-Lizenz.
| Web Proxy Viewer | New URL | Original Page |