NodeJS plant die Unterstützung von Import / Export-ES6-Modulen (ES2015)

275

Ich habe im ganzen Internet nach einer klaren Antwort darauf gesucht.

Derzeit verwendet NodeJS nur die CommonJS-Syntax zum Laden von Modulen. Wenn Sie die Standard-ES2015-Modulsyntax wirklich verwenden möchten, müssen Sie sie entweder vorher transpilieren oder zur Laufzeit einen externen Modullader verwenden.

Derzeit bin ich nicht zu sicher, eine dieser beiden Methoden zu verwenden. Planen die NodeJS-Betreuer überhaupt, ES2015-Module zu unterstützen, oder nicht? Ich habe überhaupt keinen Hinweis darauf gefunden.

Derzeit gibt NodeJS 6.x an, 96% der ES2015-Funktionen zu unterstützen, es gibt jedoch keinen Verweis auf Module ( NodeJS ES2105-Supportlink ).

Wissen Sie, ob NodeJS diese Module in naher Zukunft sofort unterstützen wird?

Zorgatone
quelle
2
Beim Googeln node es2015 moduleswird Folgendes als eines der Top-Ergebnisse angezeigt : github.com/nodejs/node/wiki/ES6-Module-Detection-in-Node .
Felix Kling
6
Persönlich würde ich dafür stimmen, diese Frage als "zu lokalisiert" zu schließen, aber dieser enge Grund existiert nicht mehr. Angenommen, Node schafft es morgen, ES6-Module zu implementieren. Werden Sie Ihre Frage dann löschen, weil sie nicht mehr relevant ist? Oder werden Sie es zumindest aktualisieren? Ich denke nicht, dass eine Frage für SO geeignet ist, wenn Sie bereits wissen, dass sie veraltet ist oder "bald" aktualisiert werden muss. Aber das ist nur meine Meinung und es scheint andere zu geben, die das Gegenteil denken, was für mich in Ordnung ist :) (fwiw, an sich ist die Frage natürlich wichtig und interessant)
Felix Kling
2
Ich wünschte, es gäbe einen Platz im Stapeluniversum für Fragen wie diese. Es mag hier technisch nicht passen, aber ich weiß nicht, dass ich damit einverstanden bin, dass es auch wirklich "meinungsbasiert" ist. OP sucht nach einer bestimmten Antwort auf eine bestimmte Frage, die jedoch (irgendwann) veraltet sein wird.
Wonko der Vernünftige
5
Alternative Formulierung dieser Frage: "Wie ist der Stand der Unterstützung von node.js für ES6-Module?" Die Antwort auf viele SO-Fragen ändert sich im Laufe der Zeit, wenn sich die Technologie weiterentwickelt. Auch ich hatte Probleme, die Antwort zu finden, bis ich hier landete.
Joe Lapp
4
@FelixKling Ich denke, dass Sie diese Frage schließen wollten, wäre eine sehr falsche Entscheidung gewesen, da es ein Problem ist. 211 Personen haben sich bisher als problematisch genug erwiesen, um abzustimmen.
Muhammad Umer

Antworten:

302

Knoten 13.2.0 und höher

NodeJS 13.2.0 unterstützt jetzt ES-Module ohne Flag. 🎉 Die Implementierung ist jedoch weiterhin als experimentell gekennzeichnet. Verwenden Sie sie daher in der Produktion mit Vorsicht.

Fügen Sie Folgendes hinzu, um die ESM-Unterstützung in 13.2.0 zu aktivieren package.json:

{
  "type": "module"
}

Alle .js, .mjs(oder Dateien ohne Erweiterung) als ESM behandelt werden.

Neben dem gesamten package.jsonOpt-In gibt es eine Reihe verschiedener Optionen , die alle in der Dokumentation zu 13.2.0 aufgeführt sind .

Knoten 13.1.0 und darunter

Diejenigen, die noch ältere Versionen von Node verwenden, sollten den esm-Modullader ausprobieren , der eine produktionsbereite Implementierung der ES-Modulspezifikation für NodeJS ist:

node -r esm main.js

Detaillierte Updates ...

23. April 2019

Ein PR ist kürzlich gelandet, um die Art und Weise zu ändern, in der ES-Module erkannt werden: https://github.com/nodejs/node/pull/26745

Es befindet sich immer noch hinter der --experimental-modulesFlagge, aber es gibt wesentliche Änderungen in der Art und Weise, wie Module geladen werden können:

  • package.typedas kann entweder moduleoder seincommonjs
    • type: "commonjs"::
      • .js wird als commonjs analysiert
      • Standard für Einstiegspunkt ohne Erweiterung ist commonjs
    • type: "module"::
      • .js wird als esm analysiert
      • unterstützt standardmäßig nicht das Laden von JSON oder Native Module
      • Standard für Einstiegspunkt ohne Erweiterung ist esm
  • --type=[mode]Damit können Sie den Typ am Einstiegspunkt festlegen. Wird package.typefür den Einstiegspunkt überschrieben .
  • Eine neue Dateierweiterung .cjs.
    • Dies dient speziell zur Unterstützung des Imports von CommonJs in den moduleModus.
    • Dies ist nur im esm-Loader der Fall, der commonjs-Loader bleibt unberührt, aber die Erweiterung funktioniert im alten Loader, wenn Sie den vollständigen Dateipfad verwenden.
  • --es-module-specifier-resolution=[type]
    • Optionen sind explicit(Standard) undnode
    • Standardmäßig lässt unser Loader keine optionalen Erweiterungen beim Import zu. Der Pfad für ein Modul muss die Erweiterung enthalten, falls vorhanden
    • Standardmäßig erlaubt unser Loader nicht den Import von Verzeichnissen mit einer Indexdatei
    • Entwickler können --es-module-specifier-resolution=nodedamit den Commonjs Specifier Resolution-Algorithmus aktivieren
    • Dies ist kein „Feature“, sondern eine Implementierung zum Experimentieren. Es wird erwartet, dass es sich ändert, bevor das Flag entfernt wird
  • --experimental-json-loader
    • die einzige Möglichkeit, json zu importieren, wenn "type": "module"
    • Wenn diese Option aktiviert import 'thing.json'ist, durchlaufen alle den experimentellen Loader unabhängig vom Modus
    • basierend auf whatwg / html # 4315
  • Mit können Sie package.maineinen Einstiegspunkt für ein Modul festlegen
    • Die in main verwendeten Dateierweiterungen werden je nach Modultyp aufgelöst

17. Januar 2019

Knoten 11.6.0 listet ES-Module weiterhin als experimentell hinter einem Flag auf.

13. September 2017

NodeJS 8.5.0 wurde mit Unterstützung für MJS-Dateien hinter einem Flag veröffentlicht:

node --experimental-modules index.mjs

Hierfür ist geplant, das Flag für die Version 10.0 LTS zu entfernen.

- Veraltete Informationen. Wird hier aus historischen Gründen aufbewahrt.

8. September 2017

Der NodeJS-Hauptzweig wurde mit anfänglicher Unterstützung für ESM-Module aktualisiert:
https://github.com/nodejs/node/commit/c8a389e19f172edbada83f59944cad7cc802d9d5

Dies sollte spätestens in der Nacht verfügbar sein (dies kann über nvm installiert werden , um zusammen mit Ihrer vorhandenen Installation ausgeführt zu werden):
https://nodejs.org/download/nightly/

Und hinter der --experimental-modulesFlagge aktiviert :

package.json

{
  "name": "testing-mjs",
  "version": "1.0.0",
  "description": "",
  "main": "index.mjs" <-- Set this to be an mjs file
}

Dann renne:

node --experimental-modules .

Februar 2017:

https://medium.com/@jasnell/an-update-on-es6-modules-in-node-js-42c958b890c#.6ye7mtn37

Die NodeJS-Leute haben entschieden, dass die am wenigsten schlechte Lösung die Verwendung der .mjsDateierweiterung ist. Das Mitnehmen daraus ist:

Mit anderen Worten, da zwei Dateien foo.jsund bar.mjsunter Verwendung import * from 'foo'behandeln wird foo.jsals Commonjs während import * from 'bar' behandeln bar.mjsals ES6 Modul

Und was die Zeitpläne betrifft ...

Zum gegenwärtigen Zeitpunkt gibt es noch eine Reihe von Spezifikations- und Implementierungsproblemen, die auf der Seite von ES6 und Virtual Machine auftreten müssen, bevor Node.js überhaupt mit der Ausarbeitung einer unterstützbaren Implementierung von ES6-Modulen beginnen kann. Die Arbeiten sind im Gange, aber es wird einige Zeit dauern - wir sehen derzeit mindestens ein Jahr .

Oktober 2016:

Einer der Entwickler von Node.JS hat kürzlich an einem TC-39-Meeting teilgenommen und einen hervorragenden Artikel über die Blocker für die Implementierung für Node.JS verfasst:

https://hackernoon.com/node-js-tc-39-and-modules-a1118aecf95e

Das grundlegende Mitnehmen davon ist:

  • ES-Module werden statisch analysiert, CommonJS ausgewertet
  • CommonJS-Module ermöglichen den Export von Affen-Patches, ES-Module derzeit nicht
  • Es ist schwierig zu erkennen, was ein ES-Modul und was CommonJS ist, ohne irgendeine Benutzereingabe, aber sie versuchen es.
  • *.mjs scheint die wahrscheinlichste Lösung zu sein, es sei denn, sie können ein ES-Modul ohne Benutzereingabe genau erkennen

- Ursprüngliche Antwort -

Dies ist seit geraumer Zeit eine heiße Kartoffel. Fazit: Ja, Node wird möglicherweise die ES2015-Syntax zum Importieren / Exportieren von Modulen unterstützen - höchstwahrscheinlich, wenn die Spezifikation zum Laden von Modulen fertiggestellt und vereinbart ist.

Hier ist ein guter Überblick darüber, was NodeJS aufhält. Im Wesentlichen müssen sie sicherstellen, dass die neue Spezifikation für Node funktioniert, bei dem es sich hauptsächlich um bedingtes synchrones Laden handelt, und für HTML, das hauptsächlich asynchron ist.

Derzeit weiß niemand genau Bescheid, aber ich kann mir vorstellen, dass Node das import/exportstatische Laden zusätzlich zum neuen System.importfür das dynamische Laden unterstützt - und dabei den alten requireCode beibehält.

Hier sind einige Vorschläge, wie Node dies erreichen könnte:

CodingIntrigue
quelle
38
Über die .mjsErweiterung : We have affectionately called these “Michael Jackson Script” files in the past. Nur für den Fall, dass Sie während des JS-Gesprächs jemanden über Popkünstler sprechen hören.
Jeewes
1
Ich verstehe nicht, warum das Ändern der Importsyntax nicht ausreicht. Eine Syntax zum Importieren von es (die 'richtige') und eine zum Importieren von cjs? Mit anderen Worten, wenn zwei Dateien foo.js und bar.js gegeben sind, import * from 'foo'wird foo.js als CommonJS import * as bar from 'bar'behandelt. Bar.js wird als ES6-Modul behandelt. Kann jemand erklären?
Corey Alix
1
Die @ CoreyAlix-Syntax wird im Allgemeinen nicht geändert, um eine Umgebung zu unterstützen. Das betrifft doch wirklich nur Node. Auch die Syntax ist etwas nicht intuitiv. Wie greife ich in Ihrer vorgeschlagenen Syntax auf die Exporte zu?
CodingIntrigue
Um klar zu sein, es ist nicht "mein" Vorschlag, ich kopiere, was Typoskript bereits tut. Um Ihre Frage zu beantworten, greifen Sie mit "bar" auf die Exporte zu: bar.foobar () import {foo as Foo} von "./foo" ist der Mechanismus zur Identifizierung eines ES6-Moduls. var Foo = require ("./ foo") ist der Mechanismus zur Identifizierung des CJS-Moduls. In Typescript sieht die Ausgabe von commonjs folgendermaßen aus: var mod1_1 = require ("./ mod1"); exports.mod1 = mod1; Die ES6-Ausgabe sieht folgendermaßen aus: {mod1} aus "./mod1" importieren; export {mod1}
Corey Alix
1
Ich wäre wirklich interessant in einem Node 10-Update zu dieser Antwort. Hat das Feature den Schnitt gemacht oder befindet es sich immer noch hinter einer Flagge?
dcorking