So lösen Sie Node.js ES6 (ESM) Module mit dem TypeScript Compiler (TSC) auf. TSC gibt nicht die richtige Dateierweiterung aus

Lesezeit: 9 Minuten

Benutzer-Avatar
Chaos156

Ich versuche, mein TypeScript-Projekt in JavaScript zu transpilieren, aber irgendetwas scheint nicht richtig zu sein. Ich habe das Projekt so konfiguriert, dass es als ES6-Modul (auch bekannt als ESM) über die "module":"ES6" Einstellung, aber es löst das Problem nicht.

Das ist, was mein tsconfig.json Konfiguration sieht so aus:
  {
    "compilerOptions": {
      "module": "es6",
      "target": "es6",
      "lib": ["es6"],
      "sourceMap": true,
    }
  }

Testfall mit einem Modulpaar:

Ich habe ein einfaches Testfall-Senario mit zwei Modulen geschrieben.

  1. Das erste Modul — module1.ts — exportiert nur eine Konstante, wie unten gezeigt:

    •   export const testText = "It works!"; 
      
  2. Das zweite Modul – main.ts — importiert nur den Export aus dem ersten Modul:

    •   import { testText } from 'module1';
        alert(testText);
      

Die Ausgabedatei des zweiten Moduls (bzw main.js) ist in meine eingebettet index.html Dokument, und ich habe das Typattribut als hinzugefügt type="module" zum <script ...> -Tag, wie unten gezeigt:

    <script src="main.js" type="module"></script>

Wenn ich das mit beiden teste Feuerfuchs (dom.moduleScripts.enabled ist in about:config gesetzt) ​​oder Chrome Canary (Flag für experimentelle Webplattform ist gesetzt) ​​es funktioniert nicht.

Der Typescript-Compiler scheint den TS zu transpilieren import { testText } from 'module1';-Anweisung zur JS-Anweisung import { testText } from 'module1';. (Anmerkung: beide sind genau gleich)

Die korrekte ES6-Importanweisung wäre:
import { testText } from 'module1.js';
(Beachten Sie die Dateierweiterung .js) Wenn ich die Dateierweiterung manuell zum generierten Code hinzufüge, funktioniert es.

Habe ich was falsch gemacht oder funktioniert das Typescript "module": "es6" Die Einstellung funktioniert einfach nicht richtig? Gibt es eine Möglichkeit, den tsc so zu konfigurieren, dass den generierten Importanweisungen .js-Dateierweiterungen hinzugefügt werden?

  • Es ist ein bekanntes Problem, gemeldet als github.com/Microsoft/TypeScript/issues/13422 und github.com/Microsoft/TypeScript/issues/16577

    – artem

    7. Juli 2017 um 22:35 Uhr

  • Ich löse das gleiche Problem. Importieren *.js Datei ist eine nette Arbeit, aber dann hatte ich Probleme mit dem Refactoring in IDE (mit CLion) und dem Wechsel zu Deklaration, Definition usw. Also wechselte ich zurück zum Importieren ohne *.js Erweiterung und eigentlich verwende ich SystemJS, um ES6 JavaScript zu transpilieren (als temporäre Lösung während der Entwicklung). Ich habe Informationen zur Verwendung des TypeScript-Compilers gefunden API. Ich denke an ein “benutzerdefiniertes” Build-Tool für diese Situation, aber eigentlich bin ich ziemlich beschäftigt. Wenn jemand ein paar Ideen, Anmerkungen oder so etwas wie t hat

    – Martin

    30. August 2017 um 9:09 Uhr

Benutzer-Avatar
Keith

Das ist ein verwirrende Designauswahl in TypeScript.

Kurzfristig können Sie dies umgehen, indem Sie die Ausgabedatei angeben:

in main.ts Präzisiere das .js Erweiterung und Pfad:

import { testText } from './module1.js';
alert(testText);

Das wird abgeholt module.ts korrekt, aber mit der Ausgabe .js Verlängerung enthalten.

Beachten Sie, dass Sie auch lokalen Dateien das Präfix voranstellen müssen ./ da „nackte“ Modulnamen für die zukünftige Verwendung reserviert sind.

  • Wirklich clevere Problemumgehung für solch einen schlimmen TS-Fehler;) danke.

    – Fabio

    22. Februar 2019 um 13:10 Uhr

  • github.com/microsoft/TypeScript/issues/40878 ist wegen “Funktioniert wie vorgesehen” geschlossen. Also eine Fehlfunktion und kein Bug?

    – Alter Badman Grey

    15. Oktober 2020 um 17:05 Uhr

  • Gute Antwort, ich möchte nur erwähnen, dass die baseUrl Die Eigenschaft wurde Typescript v3.5 als tsconfig-Option hinzugefügt. Wenn Sie es auf das Stammverzeichnis aller Ihrer Typoskript-Quelldateien setzen, können Sie das weglassen ./ aus lokalen Importen

    – Schnapp

    31. Januar 2021 um 1:41 Uhr

  • @MuhammedAydogan – Leider ist das Update, dass das TypeScript-Team dies als “funktioniert wie erwartet” betrachtet und das Verhalten nicht ändern wird.

    – TJ Crowder

    7. Mai 2021 um 15:34 Uhr

  • Auch wenn Sie das Suffix .js auslassen, wird der Code trotzdem kompiliert, sodass Sie Laufzeitfehler erhalten, was gelinde gesagt nicht großartig ist.

    – matt helliwell

    10. Dezember 2021 um 16:09 Uhr

Benutzer-Avatar
j D3V

HINWEIS DES AUTORS: „Das Datum, an dem diese Antwort veröffentlicht wurde, unterscheidet sich von dem Datum, an dem die Antwort ursprünglich erstellt wurde. Aufgrund von Änderungen in TypeScript musste ich zweimal eine neue Antwort schreiben. Da Daten in diesem Beitrag äußerst relevant sind, habe ich sie aufgenommen an einigen Stellen, für den Fall, dass die Antwort veraltet ist. Dies wird den Lesern helfen zu wissen, wann ich auf bestimmte Versionen von Technologien verwiesen habe, über die ich unten geschrieben habe.

Ursprünglich verfasst im Dezember 2022

Das “es-module-specifier” Flag-Fix für TS-, ESM- und NODE-Stacks


ESM war keine einfache Technologie, die in Node integriert werden konnte. Und als es darum ging, Node ES-Module in der TypeScript-Sprache zu schreiben, nun, das sah zu einem bestimmten Zeitpunkt tatsächlich so aus, als würde es niemals passieren. Meiner Meinung nach wollten bestimmte Projekte nicht das tun, was sie jetzt getan haben, um den Standard im Node-Back-End-RTE zu unterstützen. Wie auch immer, lass uns weitermachen…

Als ich diese Frage beantwortete, schlug ich zunächst vor, dass Personen, bei denen dieses Problem auftritt, das folgende Flag verwenden:

node --es-module-specifier-resolution=node
(FYI: Die Lösung kam von dem Link, der an das Snippet angehängt ist)

Die Flagge hat funktioniert, oder hat bis zu diesem Punkt als beste Lösung funktioniert (oder bis zu TS 4.7 Nightly Release). ES SOLLTE NOTIERT WERDEN Je nach Umgebung und Projekt, in dem Sie arbeiten, ist dies vorerst immer noch die beste Lösung.

Es wurde jedoch eine bessere Lösung verfügbar gemacht.


Zu diesem Zeitpunkt hat sich viel geändert:

Während der Nightly-Versionen von v4.6 TypeScript wurde Unterstützung für neue Modul- und moduleResolution-Spezifizierer hinzugefügt, die sind (“offensichtlich”) setzen in die tsconfig.json. Sie wurden während der freigelassen v4.6 Nächtliche Builds, kurz bevor v4.6 Beta veröffentlicht wurde, und 4.7 wurde zum nächtlichen Build. Jetzt, v4.7 ist Beta und v4.8 ist der neue nächtliche Build (ich erwähne all diese Versionskram, nur um sicherzustellen, dass Sie auf dem neuesten Stand sind).

Dies sind die neuen Spezifizierer/Einstellungen, die uns TS gegeben hat
  1. "module": "NodeNext"
  2. "moduleResolution": "NodeNext"
Es wurde angekündigt, dass v4.7 die neuen Einstellungen enthalten wird

Der Grund, warum ich das sage, ist, dass die neuen TSC-Flags (alias tsconfig-Einstellungen) in verfügbar waren v4.6, was ich, wenn Sie sich erinnern, vor ein paar Absätzen gesagt habejedoch; Typoskript beschlossen, sie nicht in der aktuellen neuesten Version zu veröffentlichen (typescript@latest) Version, die ist v4.6. Sie werden also offiziell in TypeScript aufgenommen, wenn v4.7 befindet sich nicht mehr in der Beta-Phase und wird zur neuesten Version.

Sie sollten immer mit verwendet werden "esModuleInterop": true(es sei denn, es ändert sich etwas an der “Node.js” Seite der Dinge. Das “esModuleInterop” Die Einstellung vereinfacht die Unterstützung für ESM, und einige der Knotenmodule benötigen sie, um ordnungsgemäß mit dem neuen ESM-Import/Export-Modulsystem zu funktionieren.

Das ist der ESM tsconfig.*.json Konfigurationsvorlage, die ich jedem neuen Projekt als Ausgangspunkt hinzufüge.

    "compilerOptions": {
        // Obviously you need to define your file-system
        "rootDir": "source",
        "outDir": "build", 

        // THE SETTINGS BELOW DEFINE FEATURE SUPPORT, MODULE SUPPORT, AND ES-SYNTAX SUPPORT
        "lib": ["ESNext"],
        "target": "ES2020",
        "module": "NodeNext",
        "moduleResolution": "NodeNext", 
        "esModuleInterop": true, // Eases ESM support
        "types": ["node"],
        "allowSyntheticDefaultImports": true,
    }

Geschrieben am: 22. MAI 2022 8:50 Uhr PST

Gewinnung von Unterstützung für die module & moduleResolution Spezifizierer


Sie haben also ein paar verschiedene TS-Versionen, die Sie verwenden können, um die neuen Konfigurationen zu unterstützen. Sie können entweder verwenden Beta oder Nächtlich. Unten ist eine Tabelle, die die 3 verfügbaren Versionen zeigt. Stand jetzt, typescript@latest ist @ v4.6und unterstützt die neuen Konfigurationen nicht.


TS-FREIGABE AUSFÜHRUNG NPM-BEFEHL ZUM AUSFÜHREN HAT UNTERSTÜTZUNG?
TS Neueste v4.6 npm i -D typescript@latest NEIN
TS-Beta v4.7 npm i -D typescript@beta JAWOHL
TS Nacht v4.8 npm i -D typescript@next JAWOHL

Konfigurieren Sie Ihre Entwicklungsumgebung für die Verwendung der neuesten Ver

Sie müssen Ihre Umgebung für die Verwendung der neuen TypeScript-Version konfigurieren. Ich kann natürlich nicht die Konfiguration jedes Editors dokumentieren, aber VS-Code scheint am gebräuchlichsten zu sein Typoskriptund GEGEN 2022 verwendet eine ähnliche Konfiguration.

Im VS-Codefügen Sie Ihrem Arbeitsbereich die folgende Konfiguration hinzu ./.vscode/settings.json Datei.

  // "./.vscode/settings.json"
  { "typescript.tsdk": "./node_modules/typescript/lib",}

Konfigurieren Ihrer Laufzeitumgebung

(Was für diese Antwort Node.js ist)


Aber warum jD3V? Warum muss ich meine RTE konfigurieren? Was ist das Problem??? Macht die RTE jetzt nicht alles?

  • Nein, die RTE weiß nicht einfach automatisch alles. Es muss irgendeine Art von Anweisungen oder Hinweisen haben.

**Aber haben wir das nicht schon konfiguriert tsconfig.json Datei?

  • Ja, aber das ist für TypeScript, jetzt müssen wir sicherstellen, dass der Knoten für unsere TS-Konfiguration bereit ist.

Wir müssen dem Knoten mitteilen, dass wir ein ECMAScript-Modul und kein CommonJS-Modul ausführen werden. Wir können dies auf zwei verschiedene Arten tun.

  1. Die erste besteht darin, unsere zu konfigurieren package.json Datei mit der package.json Feld “Typ” der Konfigurationsdatei.
    // @file "package.json" 

    {
        "name": "project-name",
        "version: "2.4.16",
        "type": "module", // <-- Lets env know this project is an ESM

        // the rest of your package.json file configuration...
    }
  1. Alternativ können Sie etwas wie oben tun, aber indem Sie die verwenden --input-type "module" Flagge

  2. Schließlich können Sie tun, was ich bevorzuge, und einfach jede Datei mit dem erstellen ESM Dateierweiterungen. In js ist es .ejsund in Typoskript ist es .ets.

Zum Beispiel wird Ihre Indexdatei sein index.ets und TSC wird emittieren index.ejs.

Schließlich ist es WICHTIG dass Sie verstehen, wie Importe beim Schreiben von an funktionieren “ES-Modul”. Ich werde einige Notizen auflisten, ich denke, das wird das beste Format für diese Informationen sein.

  1. Beim Importieren von Dateien müssen Sie JavaScript-Dateierweiterungen verwenden.

  2. ESM-Importe werden mit importiert URIs, und nicht durch die Verwendung von “possix filepaths”. Das Gegenteil war bei CJS-Modulen der Fall.

  3. Sonderzeichen müssen prozentkodiert sein, wie # mit %23 und ? mit %3F.

  4. TypeScript lässt Sie MimeType nicht voranstellen, aber ESM verwendet vorangestellte Datentypen, daher ist dies eine bewährte Vorgehensweise.

Beispielsweise ist es eine bewährte Methode, aus Knoten-APIs und Bibliotheken mit dem folgenden URI-Format zu importieren:

import EventEmitter from 'node:events';

const eEmit = new EventEmitter();

  • Super unterschätzte Antwort. Dieses Flag ist meiner Meinung nach die beste Lösung – stellt sicher, dass Sie nicht allen Importen die Erweiterung „.js“ hinzufügen müssen, es funktioniert mit nodemon und Supervisor UND es funktioniert mit Jest (ich bin auf eine Situation gestoßen, in der ich die Erweiterung „.js“ hinzugefügt habe beim Ausführen des Servers, aber die .js-Erweiterung brach meine Tests beim Ausführen von Scherz – dieses Knoten-Flag löst dies).

    – Alex Lord

    19. April um 21:11 Uhr


  • Hinweis: moduleResolution: “nodenext” erfordert einen nächtlichen Build, andernfalls erhalten Sie diesen Fehler: error TS4124: Compiler option 'module' of value 'nodenext' is unstable. Use nightly TypeScript to silence this error. Try updating with 'npm install -D typescript@next'.. Ein Upgrade von TypeScript auf 4.6 reicht nicht aus. Mehr Info: github.com/microsoft/TypeScript/issues/…

    – Johnny Oshika

    5. Mai um 23:50 Uhr


  • Vielen Dank @JohnnyOshika, Sie können diese Art von Details gerne in Antworten bearbeiten, wenn Sie sie bemerken. Ich dachte eigentlich, ich hätte das eingeschlossen.

    – j D3V

    10. Mai um 1:18 Uhr

  • Hier ist ein Beitrag, der die gemeinsame Verwendung von TypeScript ESM und Node über die neuen TypeScript v4.7-Modul- und moduleResolution-Werte behandelt NodeNext stackoverflow.com/questions/72213760/…

    – j D3V

    12. Mai um 12:25 Uhr

Benutzer-Avatar
YJDev

Keith hat richtig geantwortet.

In deiner main.tsAnstatt von:

    import { testText } from 'module1';

Versuche Folgendes:

    import { testText } from 'module1.js';

In meinem Fall funktioniert vscode intellisense + ich bekomme die gewünschte Ausgabedatei main.js auch.

1015400cookie-checkSo lösen Sie Node.js ES6 (ESM) Module mit dem TypeScript Compiler (TSC) auf. TSC gibt nicht die richtige Dateierweiterung aus

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy