Typescript: Stellen Sie eine Möglichkeit bereit, die Dateierweiterung „.js“ am Ende von Modulbezeichnern hinzuzufügen

Erstellt am 16. Juni 2017  ·  273Kommentare  ·  Quelle: microsoft/TypeScript

Um es6-Module im Browser verwenden zu können, benötigen Sie eine .js-Dateierweiterung. Die Ausgabe fügt es jedoch nicht hinzu.

In ts:
import { ModalBackground } from './ModalBackground';
In der ES2015-Ausgabe:
import { ModalBackground } from './ModalBackground';

Idealerweise möchte ich, dass dies ausgegeben wird
import { ModalBackground } from './ModalBackground.js';

Auf diese Weise kann ich die Ausgabe in Chrome 51 verwenden

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Webpack boilerplate</title>
  <script type="module" src="index.js"></script>
</head>
<body></body>
</html>

image

Bezogen auf https://github.com/Microsoft/TypeScript/issues/13422

ES Modules Needs Proposal Suggestion

Hilfreichster Kommentar

Um dieses Problem ein wenig zu verallgemeinern, denke ich nicht, dass es tatsächlich darum geht, eine .js -Erweiterung hinzuzufügen, sondern den Modulbezeichner in einen tatsächlichen Pfad aufzulösen, unabhängig von der Erweiterung.

Alle 273 Kommentare

Es hat nicht nur mit #13422 zu tun, es ist das gleiche Problem. Aber die Antworten waren ziemlich negativ, obwohl ich denke, dass es ein wichtiges Thema ist, also hoffe ich, dass Ihr Problem besser aufgenommen wird.

Nun, ich hoffe, es wurde hinzugefügt, wir haben uns wirklich darauf gefreut, meinen POC in meinem nächsten TypeScript-Podcast zu diskutieren, aber es sieht so aus, als müssten wir warten, bis wir TypeScript ohne Build-Tools verwenden können.

Im Moment schreibt TypeScript keine Pfade um. Es ist definitiv ärgerlich, aber Sie können die Erweiterung .js derzeit selbst hinzufügen.

@justinfagnani @rictic

Danke für den Tipp, ich werde dazu ein Shell/Node-Skript schreiben.

@DanielRosenwasser wäre es sinnvoll, die Probleme mit dem nativen ES6-Modul unter einem Label zu sammeln?

Um dieses Problem ein wenig zu verallgemeinern, denke ich nicht, dass es tatsächlich darum geht, eine .js -Erweiterung hinzuzufügen, sondern den Modulbezeichner in einen tatsächlichen Pfad aufzulösen, unabhängig von der Erweiterung.

Ich bin auf ein anderes Problem gestoßen, das nicht wirklich die Domäne von Typoskript ist, aber für meinen Anwendungsfall.

Ich bin mir nicht sicher, wie ich mit node_modules umgehen soll. Normalerweise bündelt Webpack sie über den ts-Loader in den Code, aber offensichtlich wird dies vom Browser nicht verstanden:

import { KeyCodes } from 'vanilla-typescript;
https://github.com/quantumjs/vanilla-typescript/blob/master/events/KeyCodes.ts#L3

Das Hinzufügen einer js-Erweiterung hier ist bedeutungslos.

Ich denke, es müsste eine Pfaderweiterung per Typoskript oder einen URL-Resolver geben, der auf dem Server ausgeführt wird.

Ich schätze, es ist eher ein Nischenfall, aber ich denke, es wäre eine Möglichkeit, wie TS in diesem Bereich früh glänzen könnte. Vielleicht könnte es ein Plugin für den tsc-Compiler sein?

Für alle, die dazu kommen und eine Zwischenlösung wünschen, habe ich ein Skript geschrieben, um eine js-Dateierweiterung zum Importieren von Anweisungen hinzuzufügen:

"use strict";

const FileHound = require('filehound');
const fs = require('fs');
const path = require('path');

const files = FileHound.create()
  .paths(__dirname + '/browserLoading')
  .discard('node_modules')
  .ext('js')
  .find();


files.then((filePaths) => {

  filePaths.forEach((filepath) => {
    fs.readFile(filepath, 'utf8', (err, data) => {


      if (!data.match(/import .* from/g)) {
        return
      }
      let newData = data.replace(/(import .* from\s+['"])(.*)(?=['"])/g, '$1$2.js')
      if (err) throw err;

      console.log(`writing to ${filepath}`)
      fs.writeFile(filepath, newData, function (err) {
        if (err) {
          throw err;
        }
        console.log('complete');
      });
    })

  })
});

Ich könnte dies zu einem CLI-Tool machen.

Der Kommentar von @justinfagnani trifft den Nagel auf den Kopf.

Um dieses Problem ein wenig zu verallgemeinern, denke ich nicht, dass es eigentlich darum geht, eine .js-Erweiterung hinzuzufügen, sondern den Modulbezeichner in einen tatsächlichen Pfad aufzulösen, unabhängig von der Erweiterung.

wenn du schreibst

import { KeyCodes } from 'vanilla-typescript';

oder was das angeht

import { KeyCodes } from 'vanilla-javascript';

Sie importieren aus einem Modulbezeichner, es kann sich um eine Datei handeln oder auch nicht, aber das Hinzufügen .js am Ende führt in diesem Fall wahrscheinlich nicht zu einer gültigen Auflösung.

Wenn Sie eine NodeJS-Anwendung schreiben, versucht der NodeJS-Require-Algorithmus verschiedene Auflösungen, aber er wird wahrscheinlich _nicht_ versuchen, sie in 'vanilla-typescript.js' aufzulösen, da sie auf einen abstrakten Namen verweist und gemäß Konvention und Konfiguration aufgelöst wird ( vielleicht über verschiedene Versuche) zu etwas wie '../../../node_modules/vanilla_typescript/index.js' .

Andere Umgebungen wie AMD unterscheiden sich darin, wie sie diese Auflösung ausführen, aber eine Sache, die alle diese Umgebungen gemeinsam haben, ist die Vorstellung eines abstrahierten Modulspezifizierers.

Ich erwähne dies, weil die ES-Modul-Implementierungen, die in verschiedenen Browsern ausgeliefert werden, etwas Unvollständiges implementieren. Wenn wir auch nur unsere einfachsten Abhängigkeiten betrachten, und sobald wir das Thema der transitiven ansprechen, wird klar, dass es einen Weg geben muss, das verdammte Ding zu konfigurieren.

Das mag weit entfernt sein, aber wie Sie feststellen, ist es nicht realistisch, zu diesem (höflichen) Proof-of-Concept-Implementierung zu schreiben, der uns gegeben wurde.

Außerdem sehe ich nicht, wie TypeScript hier möglicherweise helfen könnte, da das Problem umgebungsspezifisch ist.

@QuantumInformation Ihr Programm zum Hinzufügen .js zu Pfaden sieht nett, leichtgewichtig und sogar elegant aus, aber Sie implementieren letztendlich Ihren eigenen Modulbündelr. Das macht Spaß und ist eine interessante Arbeit, aber sie zeigt die Mängel in den aktuellen Implementierungen, die in Browsern verfügbar sind. Selbst wenn Sie in reinem JavaScript schreiben, brauchen Sie dennoch etwas, um Ihre transitiv importierten Abhängigkeiten zu kompilieren und zu packen.

Ich schimpfe im Grunde nur darüber, dass die Implementierung der veröffentlichten ES-Module bei weitem nicht angemessen ist.

Auch NodeJS, RequireJS AMD, Dojo AMD, Sea Package Manager, CommonJS, Browserify, Webpack, SystemJS haben alle ihre eigenen unterschiedlichen Vorgehensweisen, aber sie alle bieten eine abstrakte Namensauflösung. Sie müssen es bereitstellen, weil es _grundlegend_ ist.

Danke, dass du meinen Rant gelesen hast.

Ich bin mir nicht sicher, welche Version von TS es hinzugefügt hat, aber Importe wie ' ./file.js' funktionieren jetzt (auch wenn die Datei tatsächlich file.ts ist).
TypeScript löst die Datei gut auf und gibt den vollständigen .js -Import an das Ziel aus.
lit-html verwenden: https://github.com/PolymerLabs/lit-html/blob/master/src/lib/repeat.ts#L15

Es ist seit TS 2.0 möglich. Aber Tools wie Webpack unterstützen es nicht, also ist es am Ende nutzlos.

Es ist nutzlos, wenn man ts-loader auf Quellen verwendet (der häufigste Anwendungsfall).
Es ist immer noch möglich, das Ziel (normalerweise "dist"-Ordner) zu bündeln, da die eigentliche js-Datei dort existiert und durch den Auflösungsprozess gefunden werden kann.

Ich frage mich, ob ich eine schnelle Transformation in ts-loader implementieren könnte, die .js -Erweiterungen aus dem Zielcode entfernt, sodass man sie direkt aus den Quellen bündeln kann.

Mach das gerne, das wäre toll. Ich habe das Problem vor ein paar Monaten auf den wichtigsten Webpack-TS-Ladern wie ts-loader gepostet, und ich wurde ziemlich schlecht aufgenommen ...

Zur Information, es gibt kein Problem mit dem Rollup-Typoskript-Plugin, als Beweis, dass es machbar ist.

Ich sehe nicht, was das bringt, bis Browser-Loader-Implementierungen und die WGATWG-Loader-Spezifikation zumindest _einige_ Konfigurationen unterstützen, da die meisten Abhängigkeiten nicht korrekt geladen werden.

Aus meiner Sicht ist nichts davon von Bedeutung, bis es praktikabel ist, den nativen Loader für einen Import zu verwenden, der auf einen beliebigen String-Literal-Bezeichner verweist, etwas, das möglicherweise noch keine URL ist, und das durch eine Transformation gehen lässt, die das ergibt eigentliche URL.

Bis dahin bleiben wir auf Tools wie SystemJS und Webpack angewiesen.

Ich habe einen winzigen Transformator erstellt, der die '.js' aus Import-/Exportanweisungen entfernt.
Ich habe tsutils Type Guards verwendet, also yarn add tsutils --dev . (Das Paket wird normalerweise sowieso installiert, wenn Sie tslint in Ihrem Projekt haben, also zusätzliche Abhängigkeit)

https://gist.github.com/AviVahl/40e031bd72c7264890f349020d04130a

Auf diese Weise kann man ts-Dateien bündeln, die Importe aus Dateien enthalten, die mit .js enden (unter Verwendung webpack und ts-loader ), und dennoch Quellen in esm-Module transpilieren, die geladen werden können Browser (mit tsc ).

Es gibt wahrscheinlich eine begrenzte Anzahl von Anwendungsfällen, in denen dies nützlich ist.

BEARBEITEN: Ich habe das Wesentliche aktualisiert, um auch mit Exporten zu arbeiten. es ist naiv und nicht optimiert, aber funktioniert.

Irgendeine Bewegung zu diesem Thema?

Diese Frage der Erweiterung führt uns zurück zu den Anfängen von TypeScript und warum ein tsconfig.json benötigt wurde und warum eine module -Option zur compilerOptions -Einstellung hinzugefügt wurde.

Da diese Angelegenheit von extension der Erweiterung nur für ES2015+ wichtig ist, da sie recht gut aufgelöst werden kann, lassen Sie sie vom Compiler hinzufügen, wenn der Zielcode ES2015+ ist.

  1. .js für .ts
  2. .jsx für .tsx

Hallo, ich komme so spät, möchte aber helfen. Ich habe Schwierigkeiten zu verstehen, worum es hier geht. Aus dem OP-Beispiel ist es:

import { ModalBackground } from './ModalBackground';

Ist das Problem, dass wir nicht wissen, was './ModalBackground' ist? Es könnte ein Ordner oder etwas anderes sein?

Wenn wir tsc für das gesamte Projekt ausführen und wissen, dass ModalBackground.ts existiert, dann wissen wir, dass es sicher ist, die Erweiterung hinzuzufügen, oder?

Dieses Problem ist auch etwas, an dem die RxJS-Community sehr interessiert ist. Wie sieht der Zeitplan für eine Lösung dafür aus? Ist es überhaupt priorisiert? Gibt es Transformationen von Drittanbietern, die helfen würden?

Ich bin mir nicht sicher, ob dies ein Problem ist, wenn das Ausgabeziel ES2015 ist, oder? Dies könnte möglicherweise in den Bereich einer ES2015-Browserfähigkeit fallen. Noch mehr, @justinfagnani , können wir nicht darauf drängen, dass dies ein Plattformziel ist, um das wir uns Sorgen machen müssen? (Vielleicht müssen Sie in einen separaten Thread verzweigen).

Noch mehr, @justinfagnani , können wir nicht darauf drängen, dass dies ein Plattformziel ist, um das wir uns Sorgen machen müssen? (Vielleicht müssen Sie in einen separaten Thread verzweigen).

Ja, natürlich möchten viele Leute, dass die Plattform irgendeine Form von Bare-Specifiern unterstützt, aber die aktuelle Tatsache ist, dass dies nicht der Fall ist, und es gibt nicht einmal einen Vorschlag, sie hinzuzufügen. Wir müssen diesen ganzen, wahrscheinlich mehrjährigen Prozess durchlaufen.

Selbst wenn wir schließlich Bare-Specifier-Unterstützung bekommen, ist es unglaublich unwahrscheinlich, dass dies in Form einer Node-Modul-Resolution in unveränderter Form erfolgt. Es wird also eine Diskrepanz zwischen dem Auflösungsalgorithmus geben, der von tsc verwendet wird, um Dateien zu finden, und dem Auflösungsalgorithmus, der von Browsern verwendet wird (und möglicherweise sogar der nativen Modulunterstützung des Knotens, afaik).

Es wäre großartig, wenn tsc verifizieren könnte, welchen Pfad es verwendet hat, um ein anderes Modul zu finden, damit nachgelagerte Tools und Umgebungen Spezifizierer nicht mit einer widersprüchlichen Meinung interpretieren.

@justinfagnani Sie werden bereits mit einer widersprüchlichen Meinung interpretiert. TS erzeugt eine JS-Datei, auf die der erzeugte JS-Code nicht verweist. ES6 kommt einer offiziell korrekten Methode zur Ausführung von JavaScript am nächsten. Wenn also der von TypesScript erzeugte ES6-Code falsch ist, handelt es sich schlicht und einfach um einen Fehler. Sie müssen nicht auf Vorschläge und dergleichen warten, sondern beheben Sie einfach den Fehler von TypeScript. Aber heute haben die Leute das Gefühl, dass sie nicht intellektuell handeln, wenn sie etwas nicht bemängeln und es zehn Ebenen von Vorschlägen unterziehen, bevor sie handeln. Gib mir eine Pause.

@aluanhaddad Es stimmt, dass viele Projekte nicht davon profitieren, aber es gibt einige Projekte, die keine npm-Abhängigkeiten verwenden (oder die in der Lage sind, die npm-Abhängigkeiten auf irgendeine Weise zu handhaben), sodass diese Projekte davon profitieren würden.

Es ist auch sehr nützlich für TypeScript- Bibliotheken , die für ES6 kompiliert werden. Im Moment können diese Bibliotheken nicht nativ im Browser verwendet werden, aber wenn TypeScript eine .js -Erweiterung ausgeben würde, würden sie funktionieren.

@justinfagnani Es ist noch nicht standardisiert oder implementiert, aber es gibt einen Vorschlag, npm-Pakete im Browser zum Laufen zu bringen.

Die Paketnamenzuordnung kann automatisch vom TypeScript-Compiler oder von einem anderen Tool generiert werden.

Also schaue ich mir das noch einmal an, gab es eine nette Problemumgehung dafür, abgesehen von meinem Knotenskript?

Ich habe diese Lösung verwendet:
https://github.com/Microsoft/TypeScript/issues/16577#issuecomment -343610106

Aber ich glaube, wenn das Modul nicht die Dateierweiterung hat, aber mit dem richtigen MIME-Typ geliefert wird, sollte das behoben werden.

Irgendeine Bewegung dazu?

@Kingwl Werden Sie einige andere Dateierweiterungen unterstützen? wie .mjs .es .esm .

vielleicht nicht, das ist ein weiteres Feature

Wie ist das überhaupt möglich? Der Typoskript-Compiler _weiß_, dass die Zielausgabe eine JS-Datei ist. Ich habe diese Threads 15 Minuten lang durchsucht und verstehe immer noch nicht, warum die Erweiterung weggelassen wird.

Aufgrund der Anzahl der Verweise auf dieses Problem gehe ich davon aus, dass es sich in die richtige Richtung bewegt. Ich werde bald einen weiteren Versuch wagen.

Wie ist das überhaupt möglich? Der Typoskript-Compiler _weiß_, dass die Zielausgabe eine JS-Datei ist. Ich habe diese Threads 15 Minuten lang durchsucht und verstehe immer noch nicht, warum die Erweiterung weggelassen wird.

Es gibt gängige Anwendungsfälle, die von Menschen verwendet werden, bei denen das Fehlen von Erweiterungen eine flexiblere Infrastruktur ermöglicht. Node require hook und webpack loader sind zwei solche Fälle.

Wie ist das überhaupt möglich? Der Typoskript-Compiler _weiß_, dass die Zielausgabe eine JS-Datei ist. Ich habe diese Threads 15 Minuten lang durchsucht und verstehe immer noch nicht, warum die Erweiterung weggelassen wird.

Es gibt gängige Anwendungsfälle, die von Menschen verwendet werden, bei denen das Fehlen von Erweiterungen eine flexiblere Infrastruktur ermöglicht. Node require hook und webpack loader sind zwei solche Fälle.

Nichts davon interessiert die Browsermodule.

Würde es das Typoskript-Team einfach umbringen, ein Opt-in-Flag hinzuzufügen, um eine .js-Erweiterung auszugeben? Wir wissen _do_, was wir hier tun, sonst gäbe es nicht ein Dutzend Threads (sowohl offene als auch geschlossene), die immer noch Antworten und wirre Fragen sammeln. Wir verstehen, dass es kein Mangel bei TS ist, aber wenn TS hier ist, um unsere JS-Probleme zu lösen, dann fügen Sie dieses Problem bitte der Liste hinzu.

HAFTUNGSAUSSCHLUSS:

Ja, ich verstehe, dass dies dazu führen kann, dass eine Menge Leute hier Probleme posten, die "Sie haben das Webpack geblockt" haben, aber wirklich harte Titties für diese Leute. Es sollte Opt-in sein.

Übrigens, beim Durchstöbern der TypeScript-Quelle sehe ich importModuleSpecifierEnding -- kann dies (ab)verwendet werden, um den Emitter dazu zu bringen, .js -Endungen zu verwenden?

Vielleicht diesen Vorschlag mit dem tsconfig-Schema zerdrücken? https://github.com/domenic/package-name-maps

An dieser Stelle würde ich mich freuen, wenn TypeScript Importe nur anhand der in tsconfig angegebenen paths automatisch umschreiben könnte. Auch ohne Browserunterstützung würde das wahrscheinlich die meisten Schmerzpunkte für mich lösen.

Irgendwelche Updates? Irgendwelche Versuche, dieses Problem zu lösen? Wir haben alle gängigen Browser, die es-Module standardmäßig unterstützen, der Standard für diese erfordert , dass die Erweiterung vorhanden ist. Ich verstehe, dass wir es manuell hinzufügen können und tsc wird das verstehen, aber das sollte nicht obligatorisch sein, warum kann es nicht einfach funktionieren?
Tut mir leid, dass ich jammern muss, aber dieses Problem ist jetzt sehr alt und es wurde noch nichts getan ...

Wie ist das überhaupt möglich? Der Typoskript-Compiler _weiß_, dass die Zielausgabe eine JS-Datei ist. Ich habe diese Threads 15 Minuten lang durchsucht und verstehe immer noch nicht, warum die Erweiterung weggelassen wird.

Es gibt gängige Anwendungsfälle, die von Menschen verwendet werden, bei denen das Fehlen von Erweiterungen eine flexiblere Infrastruktur ermöglicht. Node require hook und webpack loader sind zwei solche Fälle.

Dann könnte der Typescript-Compiler möglicherweise eine Option zum Hinzufügen der Erweiterungen akzeptieren oder nicht. Vielleicht könnte es sogar eine Reihe von Regex akzeptieren, um die Erweiterung hinzuzufügen (oder nicht), wie die Option include (https://www.typescriptlang.org/docs/handbook/tsconfig-json.html).

Ja, es wurde schon mindestens einmal vorgeschlagen, warum sollte man das nicht berücksichtigen? TS hat bereits einige experimentelle Funktionen, die sich in Zukunft ändern könnten, sobald sie im Browser implementiert sind, aber TS hat bereits Flags für diese instabilen Spezifikationen. Warum nicht sogar ein experimentelles Flag addImportsExtensions haben, wo es nur das module += '.js' tun würde, das war's! Keine abgefahrene Logik, keine zusätzlichen Funktionen. Es könnte ein anderes Ziel sein, wenn Sie es vorziehen, es als separates Ziel zu behalten. Mehr noch, wenn Sie eines der oben genannten akzeptieren, werde ich persönlich den tsc-Code durchforsten und eine PR dafür erstellen, ich möchte nur nicht meine Zeit verlieren, wenn es sowieso nicht akzeptiert wird.

Sie könnten einfach eine benutzerdefinierte Transformation verwenden, um Importe im ausgegebenen Code neu zu schreiben (durch Hinzufügen von „.js“ oder Verwenden des aufgelösten Pfads von Modulimporten).

So schreiben Sie eine TypeScript-Transformation
ttypescript: Wrapper für tsc , der Transformationen während der Kompilierung anwendet

Vielleicht gibt es bereits eine vorhandene Transformation, die das tut, was Sie brauchen.

Ich weiß, dass das möglich ist, ich habe ziemlich viel mit der Compiler-API herumgespielt (wenn auch nicht so viel, wie ich möchte). Die Sache ist die, es fügt dem Projekt ein zusätzliches Tool hinzu und zusätzliche Tools haben zusätzliche Betreuer, die möglicherweise schnell genug auf Probleme reagieren, wenn überhaupt (oft nicht durch ihre Schuld, wir alle haben Leben und Arbeit). Kleine Projekte werden oft aufgegeben, und alles selbst zu tun, verschiebt die Verantwortung nur auf uns, sodass wir, anstatt uns um den Geschäftscode zu kümmern, Zeit mit der Werkzeugausstattung verbringen.
Unter Berücksichtigung des oben Gesagten werden viele Projekte dies nicht einmal als Lösung in Betracht ziehen und stattdessen zusätzliche Build-Schritte wie Rollup usw. hinzufügen, was zusätzlichen Konfigurationsaufwand hinzufügt und uns wieder zu zusätzlichen Wartungskosten führt.
Zusammenfassend: Ich verbringe meine Zeit lieber mit einer PR zum offiziellen TS, von der sowohl ich als auch die Community profitieren würden, als sie mit einer kundenspezifischen Lösung zu verbringen, die ich irgendwann fallen lassen könnte (aus Zeitmangel oder vielen anderen Gründen). ) oder die von niemandem sonst auf der Welt verwendet werden könnte.

@ajafff ​​Es könnte eine Lösung sein, aber ich denke, dass das Hauptproblem das folgende ist: Der Typescript-Transpiler generiert falschen Quellcode in den Browsern. Es ist gut, Transformationen zu haben, aber ich sehe das als Problemumgehung. Ich frage mich, ob ich mich um Transpilationsdetails kümmern muss und meine eigene Transformation implementieren muss oder etwas ist, das vom Compiler verwaltet werden sollte.

Transformationen sind ein wirklich mächtiges Werkzeug, wir könnten einen ganz neuen Transpiler als Transformation schreiben, aber ich denke, das ist nicht der richtige Weg.

Ja, es wurde schon mindestens einmal vorgeschlagen, warum sollte man das nicht berücksichtigen? TS hat bereits einige experimentelle Funktionen

TypeScript hat genau ein experimentelles Flag, das vor 3 Jahren hinzugefügt wurde, und zwar für einen ECMAScript-Vorschlag, der nicht mehr mit dem aktuellen Vorschlag kompatibel ist.

der Typescript-Transpiler generiert falschen Quellcode in den Browsern

Ich verstehe Ihre Erwartungen, aber da der Compiler die von Ihnen geschriebenen Pfade nicht neu schreibt, bin ich überrascht, dass Sie die Importe Ihres eigenen Codes nicht als "falsch" betrachten. 😉

Tut mir leid, @DanielRosenwasser , hast du schon mal von einem Ding namens npm gehört? Die Leute geben ihre Pakete dort ab, damit wir alle sie nutzen können. Ich verstehe, dass Sie vielleicht sehr viel von mir halten, aber leider bin ich kein Autor der großen Mehrheit davon, also kann ich sie nicht bearbeiten, indem ich die Erweiterungen hinzufüge.
Wenn meine Projekte nur meinen Code verwenden würden, wäre ich dankbarer für das, was Typoskript bringt, da es wirklich meine rechte Hand beim Codieren ist (abgesehen von WebStorm). Ich verwende jedoch Pakete von Drittanbietern, wie ich denke, die meisten von uns, und diese enthalten nicht unbedingt die Erweiterungen. Einige Projekte, wie rxjs, warten buchstäblich in der Hoffnung, dass Typescript die Möglichkeit bietet, Erweiterungen hinzuzufügen, andernfalls müssten sie den gesamten Build-Prozess ändern, also verbringen wir wieder mehr Zeit mit Tools statt mit Produkten.
Könnten Sie jetzt bitte nur 3 Fragen beantworten?

  1. Ist das Typoskript-Team bereit, diese Funktion bereitzustellen?
  2. Wenn ja, würden Sie eine PR akzeptieren?
  3. Wenn nein, wann planen Sie die Veröffentlichung?

Wenn die Antwort auf die 1. Frage 'nein' ist, schließen Sie bitte diese Ausgabe, indem Sie offiziell erklären, dass Sie NICHT bereit sind, dieses Feature auszuliefern, und lassen Sie andere nicht warten, wenn es nicht kommt.

Ja, es wurde schon mindestens einmal vorgeschlagen, warum sollte man das nicht berücksichtigen? TS hat bereits einige experimentelle Funktionen

TypeScript hat genau ein experimentelles Flag, das vor 3 Jahren hinzugefügt wurde, und zwar für einen ECMAScript-Vorschlag, der nicht mehr mit dem aktuellen Vorschlag kompatibel ist.

der Typescript-Transpiler generiert falschen Quellcode in den Browsern

Ich verstehe Ihre Erwartungen, aber da der Compiler die von Ihnen geschriebenen Pfade nicht neu schreibt, bin ich überrascht, dass Sie die Importe Ihres eigenen Codes nicht als "falsch" betrachten. 😉

Es ist ein guter Punkt, @DanielRosenwasser , ich habe gerade meinen eigenen Code für richtig gehalten, weil er beim Lesen der Typescript-Spezifikation (https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#11.3) richtig zu sein scheint.

Ich bin mir ziemlich sicher, dass Sie die ECMAScript-Spezifikationen gelesen haben. In der Spezifikation ist nicht festgelegt, ob ein Modul mit einer Erweiterung enden soll oder nicht. In den Spezifikationen wird der Modulimport mithilfe des HostResolveImportedModule-Algorithmus aufgelöst, aber die Definition ist mehrdeutig. Das Problem ist nicht die ECMAScript-Spezifikation. Das Problem besteht darin, dass Browser Module so auflösen, als ob die in den Spezifikationen definierte [ModuleRequest] ein Pfad zu den Ressourcen wäre.

Gehen Sie in diesem Sinne einfach auf die Homepage der Sprache: https://www.typescriptlang.org/ .

In der Fußzeile der Seite können Sie die folgenden Zeilen lesen:

Beginnt und endet mit JavaScript

TypeScript geht von derselben Syntax und Semantik aus, die Millionen von JavaScript-Entwicklern heute bekannt sind. Verwenden Sie vorhandenen JavaScript-Code, integrieren Sie beliebte JavaScript-Bibliotheken und rufen Sie TypeScript-Code aus JavaScript auf.

TypeScript wird in sauberen, einfachen JavaScript-Code kompiliert, der auf jedem Browser , in Node.js oder in jeder JavaScript-Engine ausgeführt werden kann, die ECMAScript 3 (oder neuer) unterstützt.


Sie versprechen einen Code, der auf jedem Browser läuft, aber es scheint nicht wahr zu sein, deshalb besteht dieses Problem seit mehr als einem Jahr.

Als @Draccoz- Punkte möchten wir nur wissen, was Sie mit diesem Problem machen. Aber es ist ein bisschen frustrierend, auf Ihrer Homepage das eine und in dieser Ausgabe das Gegenteil zu lesen.

Nein, wir sind nicht bereit, irgendetwas damit zu versenden, bis zumindest Klarheit über Dinge wie ES-Interop in Node und eine vernünftige Strategie für den Versand von transitiven Abhängigkeiten besteht, die Sie von npm überhaupt verwenden würden. Wenn Sie TypeScript nicht verwenden würden, hätten Sie das gleiche Problem bei der Verwaltung und Auflösung von Abhängigkeiten, daher macht es keinen Sinn, dass wir uns etwas einfallen lassen, das das JS-Ökosystem insgesamt unabhängig entwickeln könnte. Aber selbst wenn diese Probleme gelöst wären, kann ich nicht garantieren, dass wir hier Änderungen vornehmen würden.

Sie versprechen einen Code, der auf jedem Browser läuft, aber es scheint nicht wahr zu sein, deshalb besteht dieses Problem seit mehr als einem Jahr.

Ich denke, diese Interpretation ist zu wörtlich. var fs = require('fs') funktioniert nicht, wenn Sie es im Browser ausführen, HTMLDivElement ist nicht in Node definiert und String.prototype.startsWith funktioniert nicht in älteren Browsern. Um dies zu lösen, haben Leute Tools und Bibliotheken/Polyfills außerhalb von TypeScript erstellt, da sie für das breitere JavaScript-Ökosystem gelten.

Kannst du dieses Thema also bitte schließen? Dies ist ein Blocker für andere Projekte, die darauf warten , dass TS es tut, oder erklären, dass Sie es nicht tun. Wenn Sie nicht einfach eine einfache Markierung hinzufügen können, schließen Sie dieses Problem und machen Sie andere auf Ihre Entscheidungen aufmerksam.

@DanielRosenwasser Danke für deine schnelle Antwort, das weiß ich sehr zu schätzen. Ich denke, es ist eine kluge Wahl.

Ich denke, diese Interpretation ist zu wörtlich. var fs = require('fs') funktioniert nicht, wenn Sie es im Browser ausführen, HTMLDivElement ist nicht in Node definiert und String.prototype.startsWith funktioniert nicht in älteren Browsern. Um dies zu lösen, haben Leute Tools und Bibliotheken/Polyfills außerhalb von TypeScript erstellt, da sie für das breitere JavaScript-Ökosystem gelten.

Natürlich ist es das, aber was könnte jemand anderes denken, der nichts von Typoskript versteht? Dass meine Interpretation zu wörtlich ist, ist ebenso wahr wie die Tatsache, dass dieser Text jeden „verwirren“ kann, der nichts von Typoskript versteht 😉.

Vielleicht könnten Sie Ihre Dokumente (https://www.typescriptlang.org/docs/handbook/modules.html) aktualisieren, um das tatsächliche Verhalten widerzuspiegeln.

@DanielRosenwasser Nochmals vielen Dank für deine Antwort. Auf so etwas warte ich seit einem Jahr.

Der Grund, warum ich diese Funktion wollte, war, dass ich sehen konnte, welche Art von Web-App ich ohne Build-Tools erstellen konnte. Bis dahin kann ich das Skript verwenden, das ich zuvor geschrieben habe.

Für Leute wie mich, die heute nach einer Lösung suchen, um ES-Module und TypeScript im Browser verwenden zu können, habe ich https://github.com/guybedford/es-module-shims gefunden. Es fungiert als eine Art Polyfill für Paketnamenzuordnungen, während wir auf die Finalisierung der Spezifikation und die Browserimplementierung warten. Es löst das Problem von @QuantumInformation , beim Erstellen einer einfachen Web-App in TypeScript (abgesehen vom TS-Compiler) keine Build-Tools (auch mein Problem) verwenden zu wollen.

import 'knockout'

export class MyViewModel {
    greeting: KnockoutObservable<string>
    target: KnockoutObservable<string>
    constructor() {
        this.greeting = ko.observable('hello')
        this.target = ko.observable('world')
    }
}
<!DOCTYPE html>


md5-f28d4b503a1603c40bfeb342f341bfbe


<main>
    <span data-bind='text: `${greeting()} ${target()}`'></span>
    <script type='module-shim'>
        import 'knockout'
        import { MyViewModel } from 'index'
        ko.applyBindings(new MyViewModel())
    </script>
</main>

Theoretisch können Sie, sobald Paketnamenzuordnungen von Browsern unterstützt werden, einfach type='module-shim' type='module' suchen/ersetzen und das Paketzuordnungsskript in das ändern, was letztendlich für die Einbindung der Paketzuordnung in die spez.

Es ist wahrscheinlich auch erwähnenswert, dass die .js -Erweiterung nicht von Browsern oder irgendetwas vorgeschrieben ist - Sie können Ihren Webserver jederzeit so konfigurieren, dass er mehr unpkg -ähnlich ist und .js -Dateien ausliefert erweiterungslose Anforderungs-URLs. Es ist alles auf der Webserver-Seite konfigurierbar.

@weswigham , das kann jedoch sehr problematisch sein, da tsc (und die Auflösung des klassischen Knotenmoduls) wissen, dass sich ./foo und ./foo.js auf dieselbe Datei beziehen, aber Browser sie unterschiedlich behandeln, selbst wenn die Webserver-Weiterleitungen. Sie müssten sicher sein, dass Sie bei jedem Import auf genau die gleiche Weise auf eine Datei verweisen.

Übrigens verhindert dieses Problem nicht, dass von TypeScript generierte Module heute in Browsern verwendet werden. Importieren Sie einfach immer Dateien mit der Erweiterung .js . tsc macht das Richtige und löst Typen aus der Datei .ts , und Sie erhalten Browserkompatibilität.

@weswigham Denken Sie daran, dass es Situationen gibt, in denen Sie Dateien bereitstellen, ohne Zugriff auf den Webserver zu haben. GitHub Pages, IPFS, S3 usw. Mit dem Aufkommen von Single-Page-App-Frameworks wird es immer üblicher, „serverless“ zu betreiben (wobei serverless hier bedeutet, dass kein Server, den Sie steuern/konfigurieren, Ihre Assets bedient), also Sie kann sich nicht darauf verlassen, dass serverseitige Filter apple.js , wenn eine Anfrage für apple gestellt wird.

Sie müssten sicher sein, dass Sie bei jedem Import auf genau die gleiche Weise auf eine Datei verweisen.

Kann immer den einen oder anderen 404 machen, je nach Ihrer Authoring-Präferenz. Wenn Sie in Ihrem Projekt Symlinks verwenden, würden diese ein ähnliches Problem verursachen, mit dem Sie ebenfalls entscheiden müssten, wie Sie damit umgehen möchten.

Importieren Sie einfach immer Dateien mit der Erweiterung .js

Ja, das geht auch gut.

@QuantumInformation Wird Ihr Snippet hier zur freien Verwendung verwendet? Kann ich es in einem Projekt verwenden? 😃

@distante ja du kannst es verwenden

Zu Ihrer Information, wenn Sie Jest verwenden, um Erweiterungen zu .js in der Quelle zu testen und zu ändern, bricht es zusammen
aber Sie können Folgendes zu Ihrer Jest-Konfiguration hinzufügen, um das zu beheben

  "jest": {
    ...
    "moduleNameMapper": {
      "(.*)\\.js": "$1"
    }
  }

Hallo @MrAntix ,

Ich denke, Jest ist die Bibliothek, die sich an TypeScript anpassen sollte, nicht umgekehrt.

Ich habe eine andere Site, für die ich kein Build-Tool verwenden möchte. Ist das das Beste, wo wir sind:

https://github.com/microsoft/TypeScript/issues/16577#issuecomment -452312753

Als Problemumgehung können Sie es einfach so machen (obwohl es eine ts-Datei ist, nicht js) 😢

Screenshot 2019-06-05 at 22 47 49

Falls es jemand ausprobieren möchte:
https://github.com/QuantumInformation/web-gen-bot

Allerdings kann ich das Source-Debugging mit der aktuellen tsconfig nicht zum Laufen bringen, werde mich wieder melden.

Am Ende ging ich zurück zu Webpack, node_modules war der Killer, als ich versuchte, von Build-Tools im Browser wegzukommen.

Es ist nicht nur Scherz – wenn Sie TypeScript vor der Veröffentlichung mit tsc kompilieren, wird jedes JS-Modul, das das resultierende Paket importiert, aufgrund der Unterschiede in der Modulauflösung beschädigt.

Die Diskussion hier scheint sich ein wenig in zwei verwandte, aber letztendlich getrennte Themen aufgespalten zu haben:

  • Typescript sollte Dateien generieren, die nativ in einen Browser geladen werden können
  • Typoskript sollte die Tatsache lösen, dass Knotenmodulpfade nicht immer gültige URLs sind.

Ich denke, wir müssen uns auf das erste Problem konzentrieren, da das zweite eindeutig etwas ist, das Typoskript allein nicht lösen kann.

Das erste Problem ist jedoch absolut etwas, das Typescript lösen kann und priorisiert werden sollte, da es ein großes Hindernis für die meisten Leute darstellt, die Typescript verwenden möchten, um Webapps zu erstellen, die auf moderne Browser ausgerichtet sind.

Meiner Meinung nach läuft das Problem auf folgendes hinaus:

Wenn das Ausführen tsc eine Datei mit einer .js -Erweiterung und dann eine andere Datei generiert, die die erste .js -Datei importiert, gibt es keine Zweideutigkeit darüber, welche Erweiterung verwendet werden soll, und es sollte eine geben Option zum Einfügen der Erweiterung.

Für alle import-Anweisungen, die auf andere Dateien als die von Typescript generierten Dateien verweisen, denke ich, dass es in Ordnung ist, diese unverändert zu lassen (wie es Typescript heute tut).

Bei der ersten Option denke ich, dass ein Befehlszeilen-Argument am besten wäre und standardmäßig deaktiviert wäre. Ich sage das, weil ich, wenn ich Webpack verwende, nicht möchte, dass .js zu den Importen hinzugefügt wird, da Webpack sich um die Modulbündelung kümmert.

Wie auch immer, node_modules war der Killer, der mich daran gehindert hat, den Hack für native Modul-Browser-Apps zu verwenden.

Ich sage das, weil ich, wenn ich Webpack verwende, nicht möchte, dass .js zu den Importen hinzugefügt wird, da Webpack sich um die Modulbündelung kümmert.

Webpack verarbeitet die .js -Erweiterung jedoch einwandfrei, sodass es keinen Unterschied gibt.

Tatsächlich ist es manchmal notwendig, .js mit Webpack zu verwenden (in Situationen, in denen mehrere Dateien mit demselben Namen, aber unterschiedlichen Erweiterungen vorhanden sind).

Könnten Sie also näher erläutern, warum Sie keine .js -Importe mit Webpack wünschen?

Als ich I don't want sagte, meinte ich, dass ich es für meine Anwendungsfälle nicht brauche.

Ich sehe keinen zwingenden Grund, warum es dann nicht das Standardverhalten sein sollte (immer widerstrebend, ein weiteres Konfigurationsflag hinzuzufügen ...)

Das Setzen von imports auf .js führt dazu, dass ts-node für die Datei nicht mehr richtig funktioniert. Dies liegt daran, dass ts-node jeweils nur eine Datei kompiliert und wenn der ausgegebene Dateiinhalt mit require('./foo.js') endet, dann versucht nodejs, wenn diese Datei verarbeitet wird, ./foo.js zu laden, was nicht existiert irgendwo auf der Festplatte und daher wird es fehlschlagen. Wenn der Code andererseits ( ./foo ) erfordert, wird der Handler von ts-node aufgerufen, an welchem ​​Punkt er ./foo.ts in JS kompilieren und das zurückgeben kann.

Wenn TypeScript in allen Fällen .js -Erweiterungen ausgibt, wird ts-node auf das gleiche Problem stoßen. Wenn es jedoch eine Option zum Umschalten gibt, ob eine Erweiterung automatisch hinzugefügt wird oder nicht, kann ts-node diese Compiler-Option auf „off“ setzen, wodurch das aktuelle System weiterhin funktionieren kann.

Da Node.js --experimental-modules obligatorische Dateierweiterungen erfordert, ist die API dafür unkompliziert, ohne dass eine Abhängigkeitsanalyse erforderlich ist - eine Option wie --jsext kann jede .ts -Erweiterung in eine .js umschreiben .ts endet, wie import 'npmpkg.ts' . Dieser Fall ist extrem selten, aber um ihn in der Auflösung umfassend zu behandeln, könnte die Regel lauten, eine Ausnahme für _bare specifiers_ zu machen, etwa - wenn der bare specifier (keine URL oder kein relativer Pfad) ein gültiger npm-Paketname ist ( passend zu /^(@[-_\.a-zA-Z\d]+\/)?[-_\.a-zA-Z\d]+$/ , von https://github.com/npm/validate-npm-package-name), ignorieren Sie dann die Erweiterungen .ts beim Umschreiben.

Ich habe einen TypeScript-Compiler-Transformer erstellt, der eine .js -Dateierweiterung an jeden relativen Importpfad anhängt. Das bedeutet, wenn Ihre Datei .ts import { Foo } from './foo' enthält, wird sie import { Foo } from './foo.js' ausgeben. Es ist auf NPM verfügbar, und Anweisungen zur Verwendung finden Sie in der Readme-Datei des Projekts.

https://github.com/Zoltu/typescript-transformer-append-js-extension

Wenn so etwas in den TypeScript-Compiler (als Compiler-Option) integriert werden sollte, sollte es wahrscheinlich klüger sein, zu entscheiden, wann die Erweiterung .js angehängt werden soll und wann nicht. Im Moment sucht es nach jedem Pfad, der mit ./ oder ../ beginnt und der nirgendwo anders im Pfad ein . hat. Dies bedeutet, dass es in einer Reihe von Randszenarien nicht das Richtige tun wird, obwohl ich frage, ob jemand _tatsächlich_ auf diese Randfälle stoßen wird oder nicht.

@MicahZoltu großartig, Userland-Lösungen dafür zu sehen. Ich denke jedoch, dass es ziemlich wichtig ist, dass das mentale Modell immer Dateierweiterungen enthält , sodass die TypeScript-Erweiterungsoption beim Kompilieren zu .ts-Erweiterungen in .js-Erweiterungen werden kann_. Das vermeidet die Randfälle der Auflösung und lässt nur den Fall von npm-Paketnamen übrig, die zufällig auf „.ts“ enden, was so gehandhabt werden kann, wie ich in meinem vorherigen Kommentar besprochen habe.

@guybedford Das Einfügen der Erweiterung .js in eine .ts -Datei bewirkt, dass die Datei nicht in ts-node ausgeführt werden kann. Das Lösen des Problems in ts-node ist aufgrund der Art und Weise, wie NodeJS die Dateiauflösung durchführt, alles andere als nicht trivial. Das bedeutet, dass, wenn Sie eine Bibliothek mit fest codierten .js -Erweiterungen veröffentlichen, die Bibliothek für niemanden funktioniert, der ts-node verwendet. Siehe Diskussion dazu unter https://github.com/TypeStrong/ts-node/issues/783.

@MicahZoltu Ich meine, die Erweiterung .ts eher in eine Datei .ts aufzunehmen.

@guybedford Das Einfügen der Erweiterung .js in eine .ts-Datei bewirkt, dass die Datei nicht in ts-node ausgeführt werden kann.

Dies ist ein weiterer Grund, warum die automatische Ausführung von TypeScript in Knoten und Browsern eine schlechte Idee ist.

@MicahZoltu Ich meine eher die Erweiterung .ts in einer .ts-Datei.

Ich denke, das Problem dabei ist, dass es die Äquivalenz zwischen einer .ts -Datei und einem .js / .d.ts -Paar aufhebt. Wenn Sie also eine Datei importieren, die mit dem aktuellen Projekt kompiliert wurde, verwenden Sie .ts , und wenn Sie die Datei in ein anderes Projekt verschieben, müssen Sie die Importe ändern, um .js zu verwenden .

Das bedeutet auch, dass der Ausgang ohne Transformator in Standardumgebungen nicht funktioniert. Da es keine Möglichkeit gibt, einen Transformer aus einer .tsconfig -Datei zu installieren, bedeutet dies, dass Sie immer einen benutzerdefinierten Compiler verwenden müssen. Das ist eine ziemlich große Barriere für den kleinen Vorteil, .ts anstelle von .js zu verwenden.

Dies bedeutet, dass Sie beim Importieren einer Datei, die mit dem aktuellen Projekt kompiliert wurde, .ts verwenden, und wenn Sie die Datei in ein anderes Projekt verschieben, müssen Sie die Importe ändern, um .js zu verwenden.

Externe/interne Importgrenzen sind wohldefinierte Dinge. Wenn sich eine Abhängigkeit von einer internen .ts -Datei des aktuellen gleichen Builds zu einer externen .js -Datei eines anderen Paketimports ändert, der über einen eigenen separaten Build verfügt oder vielleicht sogar kein TypeScript ist , dann müssen Sie die Erweiterung ändern, da es sich um ein völlig anderes Konzept handelt.

Das bedeutet auch, dass der Ausgang ohne Transformator in Standardumgebungen nicht funktioniert.

Ein Transformer kann uns zwar helfen, dies zu untersuchen, aber ein --ts-to-js oder ein ähnliches Compiler-Flag / eine ähnliche Option wird dringend benötigt, um dieses Problem zu lösen.

@guybedford Sie haben mich davon überzeugt, dass das Einfügen von .ts das Richtige für das Plugin war. Als ich jedoch versuchte, es zu implementieren, erfuhr ich, dass TypeScript dies eigentlich nicht zulässt!

// foo.ts
export function foo() { console.log('foo') }
// bar.ts
import { foo } from './foo.ts' // Error: An import path cannot end with a '.ts' extension. Consider importing './foo' instead
foo()

Hallo, was ist damit?


Eingang:

// src/lib.js.ts
export const result = 42;
// src/index.js.ts
import { result } from "./lib.js";

console.log(result);

Ausgang:

// build/lib.js
export const result = 42;
// build/index.js
import { result } from "./lib.js";

console.log(result);

Ausgabe Nr. 30076

Eine einzige .ts -Erweiterung für eine TypeScript-Datei erscheint mir am angemessensten. Oft weiß man bis zur Kompilierzeit nicht, was das Ziel ist. Beispielsweise habe ich in vielen meiner Bibliotheksprojekte mehrere tsconfig.json -Dateien, die auf unterschiedliche Umgebungen abzielen, z. B. auf moderne Browser, die .js -Dateien ausgeben und Importpfade .js sollten , oder auf einen modernen Knoten abzielen, der .mjs Dateien ausgeben und Importpfade .mjs sollte.

@MicahZoltu , dass das Importieren von Dateien, die auf .ts enden, ein Fehler ist, ist möglicherweise tatsächlich zu unserem Vorteil. Weil dies bedeutet, dass das Umschreiben der Erweiterung .ts in .js beim Kompilieren hinzugefügt werden kann, wenn Erweiterungen von .ts verwendet werden, ohne dass ein Flag erforderlich ist :)

Vielleicht wäre ein PR, um nachlaufende .ts -Erweiterungen zu unterstützen und in .js -Erweiterungen umzuschreiben (möglicherweise unter einem Flag, um diese Funktion zu aktivieren, aber ein Flag, das rechtzeitig entfernt werden kann), eine großartige Möglichkeit auf diesem Weg zu beginnen.

//cc @DanielRosenwasser

Diese Ausgabe ist schon sehr lang, also könnte jemand dies bereits gesagt haben, also besteht die Gefahr, dass das bereits Gesagte wiederholt wird:

TypeScript sollte es Entwicklern ermöglichen, Erweiterungen in import s anzugeben, da es JavaScript validiert. Und hier geht es nicht nur um die JS/TS-Erweiterung! In ESM ist jede Erweiterung gültig, solange der MIME-Typ korrekt ist.

import actuallyCode from './lookLikeAnImage.png';

… sollte gültig sein, solange der Server gültiges JavaScript in dieser Datei bereitstellt und den richtigen MIME-Typ einstellt. Dies geht noch weiter, da dasselbe für TS gelten könnte! Eine TS-Datei könnte nur ein JS-Quellcode sein, der mit dem JS-MIME-Typ bereitgestellt wird, und daher ein gültiger Pfad für den Import eines ESM-Moduls.

IMO TypeScript sollte nur Importe ohne Erweiterung berücksichtigen (wie es Sie heute haben möchte) und diejenigen mit allein lassen, ohne Fehler, Warnung usw. Andernfalls lehnt es gültigen JavaScript-Code ab, was ziemlich unglücklich für etwas ist, das behauptet, eine Obermenge von JS zu sein.

Tut mir leid, wenn dies nicht der richtige Ort ist, um dies anzusprechen, ich habe ein paar andere Probleme gesehen: # 18971, # 16640, # 16640, aber Probleme zu diesem Thema scheinen links und rechts geschlossen zu werden, also gehe ich davon aus, dass dies das "Hauptproblem" ist da es offen bleiben durfte.

Spielen mit NodeJS v12.7.0

salathiel@salathiel-genese-pc:~/${PATH_TO_PROJECT}$ node --experimental-modules dist/spec/src/ioc
(node:15907) ExperimentalWarning: The ESM module loader is experimental.
internal/modules/esm/default_resolve.js:59
  let url = moduleWrapResolve(specifier, parentURL);
            ^

Error: Cannot find module '${PROJECT_ROOT}/dist/spec/src/ioc' imported from ${PROJECT_ROOT}/
    at Loader.resolve [as _resolve] (internal/modules/esm/default_resolve.js:59:13)
    at Loader.resolve (internal/modules/esm/loader.js:73:33)
    at Loader.getModuleJob (internal/modules/esm/loader.js:149:40)
    at Loader.import (internal/modules/esm/loader.js:133:28)
    at internal/modules/cjs/loader.js:830:27
    at processTicksAndRejections (internal/process/task_queues.js:85:5) {
  code: 'ERR_MODULE_NOT_FOUND'
}
salathiel@salathiel-genese-pc:~/${PATH_TO_PROJECT}$ node --experimental-modules dist/spec/src/ioc.js
(node:16155) ExperimentalWarning: The ESM module loader is experimental.
internal/modules/esm/default_resolve.js:59
  let url = moduleWrapResolve(specifier, parentURL);
            ^

Error: Cannot find module '${PROJECT_ROOT}/dist/spec/src/observe' imported from ${PROJECT_ROOT}/dist/spec/src/ioc.js
    at Loader.resolve [as _resolve] (internal/modules/esm/default_resolve.js:59:13)
    at Loader.resolve (internal/modules/esm/loader.js:73:33)
    at Loader.getModuleJob (internal/modules/esm/loader.js:149:40)
    at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:43:40)
    at link (internal/modules/esm/module_job.js:42:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Ich weiß jetzt nicht, warum das nervig ist...

Im Moment schreibt TypeScript keine Pfade um. Es ist definitiv ärgerlich, aber Sie können die Erweiterung .js derzeit selbst hinzufügen.

@DanielRosenwasser https://github.com/microsoft/TypeScript/issues/16577#issuecomment -309169829

Was ist mit der Implementierung hinter einer Option? Wie --rewrite-paths ( rewritePaths: true ) ?

@viT-1 Hier ist vorerst ein Workaround: https://github.com/microsoft/TypeScript/issues/16577#issuecomment -507504210

@MicahZoltu Ich löse gerade meinen Anwendungsfall durch SystemJS-Bündelung (Option tsconfig outFile)

Ich habe nicht jeden Kommentar gelesen, den die Leute darüber geschrieben haben, aber ich weiß nicht, warum ich millionenfach .js schreiben muss. Ich möchte, dass der Computer das für mich erledigt.

@richardkazuomiller Das tun wir alle, aber @DanielRosenwasser hat in https://github.com/microsoft/TypeScript/issues/16577#issuecomment -448747209 erklärt, dass sie dazu vorerst nicht bereit sind (ich bin überrascht, dass dieses Problem irreführenderweise immer noch offen ist für eine so lange Zeit nach der obigen Aussage). Wenn Sie möchten, dass der Computer dies für Sie erledigt, sollten Sie einen Bundler oder ein Tool eines Drittanbieters verwenden, um das Umschreiben von Importpfaden zu handhaben.

Wer möchte, dass ich dieses Thema schließe?

Bitte schließen Sie nicht, ich warte immer noch darauf, wie das TypeScript-Team darauf reagieren wird, wie es ESM-Importe angehen wird, die die Verwendung beliebiger Erweiterungen zulassen und sich stattdessen auf den MIME-Typ verlassen. Im Moment ist dies in JavaScript möglich, aber nicht in TypeScript. (Details finden Sie in meinem vorherigen Kommentar.)

@TomasHubelbauer Aus diesem Grund habe ich ein Flag in der Konfigurationsdatei vorgeschlagen, das darauf hinweisen könnte, dass allen Importen ohne Erweiterung die Erweiterung .js (oder eine andere konfigurierte) hinzugefügt werden sollte. Dies wäre ein Opt-in, sodass der Standardwert falsch sein könnte, sodass vorhandene Projekte oder Projekte mit anderen Anforderungen so funktionieren, wie sie sind.

Wie schon gesagt:

Ich bin mir nicht sicher, welche Version von TS es hinzugefügt hat, aber Importe wie ' ./file.js' funktionieren jetzt (auch wenn die Datei tatsächlich file.ts ist).
TypeScript löst die Datei gut auf und gibt den vollständigen .js -Import an das Ziel aus.

Dies ist sinnvoll, da jedes gültige JavaScript gültiges TypeScript ist. Da können Sie:

import foo from './bar.js'

... in JS sollten Sie es auch in TS tun können. Wenn Sie das tun, lösen Sie das Problem der Verwendung nativer ES6-Module, da Sie Ihre Erweiterungen korrekt haben.


Vergessen wir auch nicht, dass der Browser, wenn er einen Import für ./foo/bar sieht, tatsächlich eine Anfrage dafür stellt. Dass nichts serviert wurde, lag am Server. Sie könnten es so konfigurieren, dass Anfragen für /foo/bar mit /foo/bar.js erfüllt werden. Ich sage nicht, dass dies eine gute Lösung oder sogar eine gute Idee ist, aber es würde technisch funktionieren.

Flag in der Konfigurationsdatei, könnte dies darauf hinweisen, dass allen Importen ohne Erweiterung die Erweiterung .js (oder eine andere konfigurierte) hinzugefügt werden sollte

Dies würde die überwiegende Mehrheit der Fälle lösen. Wäre das TypeScript-Team bereit, eine PR für diese Konfigurationsoption in Erwägung zu ziehen?

NodeJS verhält sich jetzt _standardmäßig_ genauso wie Browser, wenn es um die relative Pfadmodulauflösung geht. Es wird standardmäßig keine .js -Erweiterung mehr abgeleitet. Dies bedeutet, dass das aktuelle Verhalten von TSC dazu führt, dass JS ausgegeben wird, das in allen Laufzeitkontexten ungültig ist. Es scheint, dass dieses Problem jetzt angegangen werden sollte, da sowohl das Browser- als auch das NodeJS-Verhalten für ESM klar sind.

https://nodejs.org/api/esm.html#esm_customizing_esm_specifier_resolution_algorithm

Der neue Resolver für esm benötigt einen neuen Auflösungsmodus - moduleResolution: node ist wirklich nur der CJS-Resolver für das, was ich jetzt "alte Versionen von Knoten" nennen kann. Wenn Sie beabsichtigen, auf den neuen esm-Resolver abzuzielen, benötigen wir einen neuen Auflösungsmodus, um besser zu passen. Zumal node den alten Resolver in allen bestehenden Konfigurationen noch voll unterstützt. (Beachten Sie: Es wäre schwierig, einen solchen neuen Resolver zu _unserem Standard_ zu machen)

Obwohl! Während es _Uneinigkeit_ darüber gibt und _einige Leute sich dafür entscheiden werden, Meinungen als Tatsachen anzugeben_, gibt es immer noch ein --es-module-specifier-resolution=node -Flag, das das erwartete Erweiterungsverhalten zurückgibt und dennoch zum Standard werden kann - wie die Dokumentation sagt, obwohl es nicht markiert ist , es-Module in node sind _noch experimenteller Natur_.

Auch als Erinnerung für die ursprüngliche Anfrage: Wir schreiben keine Importe um. Je. Überhaupt. Bezeichner ein === Bezeichner aus. Spezifizierer beschreiben die strukturelle Absicht, und es ist nicht unser Ziel, implizit eine beabsichtigte Struktur auf eine andere abzubilden. Sie könnten es sich auch so vorstellen: Wenn Sie const varFoo = "./Foo"; import(varFoo) schreiben, würden wir die Erweiterung dort irgendwie hinzufügen, falls erforderlich? Nein – das ist lächerlich – um alle Formen dynamischer Eingaben zu verarbeiten, müssten wir den dynamischen Import zur Laufzeit umschließen, und plötzlich sind wir zu einem eigenen Modullader geworden, der über dem eingebauten Plattformlader liegt. Stattdessen würden wir einen Resolver-Modus bereitstellen, der entsprechende Fehler ausgibt, wenn Sie die Erweiterung weglassen (für die Sie zweifellos bereits Lint-Regeln finden können).

Wenn Sie diesen Thread finden und _wirklich wollen_, dass Ihre Eingabequellen keine Erweiterungen haben, und Sie _wirklich_ brauchen_, dass Ihre Ausgabe immer noch damit funktioniert, wenn Sie auf (Knoten-)Module abzielen, sollten Sie Feedback unter https://github.com/ geben.

plötzlich sind wir unser eigener Modullader geworden

Muss tsc nicht in jedem Fall ein funktionierender Modullader sein? Sie können einen Import nicht typisieren, wenn Sie das Modul, aus dem er stammt, nicht finden können. Ich möchte nur sehen, dass sich all die verschiedenen Modullader auf weitgehend kompatible Weise verhalten oder zumindest auf eine vorhersehbar unterschiedliche Weise, die einigermaßen schmerzlos zu berücksichtigen ist.

NodeJS verhält sich jetzt standardmäßig genauso wie Browser, wenn es um die relative Pfadmodulauflösung geht. Es wird standardmäßig keine .js-Erweiterung mehr abgeleitet. Dies bedeutet, dass das aktuelle Verhalten von TSC dazu führt, dass JS ausgegeben wird, das in allen Laufzeitkontexten ungültig ist.

Ist dies nicht ein weiterer Grund, einfach die Dateierweiterungen .js in Spezifizierern zu verwenden, wie sie TypeScript bereits unterstützt? Das löst alles, außer dass es großartig wäre, wenn tsc bei erweiterungslosen Importen einen Fehler machen würde.

Muss tsc nicht in jedem Fall ein funktionierender Modullader sein? Sie können einen Import nicht typisieren, wenn Sie das Modul, aus dem er stammt, nicht finden können. Ich möchte nur sehen, dass sich all die verschiedenen Modullader auf weitgehend kompatible Weise verhalten oder zumindest auf eine vorhersehbar unterschiedliche Weise, die einigermaßen schmerzlos zu berücksichtigen ist.

Wir zielen nicht darauf ab, eine Runtime-Loader-Implementierung bereitzustellen, sondern nur eine Analyse der Kompilierzeit, die widerspiegelt, welchen Runtime-Loader Sie anstreben. Wir können unmöglich alle Importe ohne eine Laufzeitkomponente neu zuordnen, die wir nicht haben oder haben wollen.

Muss tsc nicht in jedem Fall ein funktionierender Modullader sein?

Nicht zur Laufzeit. tsc muss verstehen, wie die Laufzeit der Wahl Spezifizierer auflöst und dies zur Build-Zeit implementiert, aber die Laufzeit wird ausschließlich der Umgebung überlassen.

Man könnte es sich auch so vorstellen: Wenn man const varFoo = "./Foo"; import(varFoo) würden wir die Erweiterung dort irgendwie hinzufügen, falls nötig?

@weswigham Dies ist ein starkes Argument in Bezug auf dynamische Importe, aber ich glaube nicht, dass Sie das mit statischen Importen tun können? Ich kann das Argument verstehen, dass die Strategie für beide gleich sein sollte, aber ich denke, es ist erwähnenswert, dass statische Importe eine ganz andere Rolle spielen als dynamische Importe, und ich denke nicht, dass es absolut _unvernünftig_ ist, eine andere Strategie für statische Importe zu haben Importumschreiben und dynamisches Importumschreiben.

Ist dies nicht ein weiterer Grund, einfach die .js-Dateierweiterungen in Spezifizierern zu verwenden, wie sie TypeScript bereits unterstützt? Das löst alles, außer dass es großartig wäre, wenn tsc bei erweiterungslosen Importen fehlerhaft wäre.

@justinfagnani Damit gibt es zwei Probleme:

  1. Eine Laufzeitumgebung, die TS nativ ausführt (z. B. TS-Node), funktioniert nicht, wenn Sie .js -Erweiterungen für Ihre Importe angeben.
  2. Sie belügen den Compiler (IMO), wenn Sie .js-Erweiterungen in Ihre Importe aufnehmen.

In Bezug auf (2), wenn ich zwei TS-Dateien a.ts und b.ts habe und a.ts import ... from './b.js' macht, sage ich dem Compiler, dass ich eine Geschwisterdatei habe mit dem Namen b.js . Diese Aussage ist nicht wahr. Um die Sache noch schlimmer zu machen, wenn Sie sowohl .b.ts als auch b.js haben (die möglicherweise nicht die Ableitungen voneinander sind). Jetzt wird unklar, auf welche Sie sich beziehen, _obwohl Sie explizit eine Erweiterung eingefügt haben_.

Ich bin der Meinung, dass der Benutzer dem Compiler mitteilen sollte, was er eigentlich (als Benutzer) möchte, und zwar entweder "jede Datei mit dem Namen X und einer beliebigen Erweiterung importieren" (im Fall von import ... from './foo' ) oder "speziell diese Datei importieren" (im Fall von import ... from './foo.ext' ). Wenn der Compiler erkennt, dass Sie eine TS-Datei importieren, und der Compiler damit fortfährt, eine .js -Datei auszugeben, sollte der Compiler meiner Meinung nach den Import aktualisieren, um die entsprechende Datei korrekt zu importieren. Dies kann bedeuten, dass in der Importanweisung ein .ts in ein .js geändert wird.

@justinfagnani Damit gibt es zwei Probleme:

  1. Eine Laufzeitumgebung, die TS nativ ausführt (z. B. TS-Node), funktioniert nicht, wenn Sie für Ihre Importe .js-Erweiterungen angeben.

Dies ist ein Fehler in TS-Node. Es stimmt nicht mit dem Verhalten von tsc .

  1. Sie belügen den Compiler (IMO), wenn Sie .js-Erweiterungen in Ihre Importe aufnehmen.

Es ist eigentlich das Gegenteil – Sie sagen die Wahrheit darüber, was tatsächlich importiert wird. Sie importieren _keine_ .ts -Datei, sondern eine .js -Datei. Es sollte auch keinen sichtbaren Unterschied zwischen einem .d.ts / .js Paar und einer .ts Datei geben. Sie sind austauschbar. Der einzig richtige Weg, dies zu erreichen, besteht darin, die .js -Datei zu importieren - was die .ts -Datei nach der Kompilierung sein wird.

@justinfagnani

Es sollte auch keinen sichtbaren Unterschied zwischen einem .d.ts/.js-Paar und einer .ts-Datei geben

Dies ist nicht immer wahr. Sie können Ihren Server so konfigurieren, dass er alle JS, TS und DTS mit einem JS-MIME-Typ bereitstellt und sie dann alle separat in JavaScript importiert, und die Laufzeit führt sie alle pflichtgemäß als JS aus. ESM kümmert sich überhaupt nicht um Erweiterungen.

Aus diesem Grund denke ich, dass TS-Benutzer tatsächlich gezwungen werden sollten, eine .ts -Erweiterung einzuschließen, und ohne Erweiterung wäre ein Fehler, es sei denn, sie importieren tatsächlich eine Datei ohne Erweiterung oder diesen Namen. Und TS würde die Importe in der Ausgabe in .js umschreiben. Und wenn eine JS-Datei vorhanden wäre (keine von TS generierte), wäre dies ebenfalls ein Fehler.

Dies ist ein Fehler in TS-Node. Es stimmt nicht mit dem Verhalten von tsc überein.

Es ist eine Einschränkung des NodeJS-Loaders, kein Fehler in TS-Node: https://github.com/TypeStrong/ts-node/issues/783#issuecomment -507437929

Dies ist nicht immer wahr. Sie können Ihren Server so konfigurieren, dass er alle JS, TS und DTS mit einem JS-MIME-Typ bereitstellt und sie dann alle separat in JavaScript importiert, und die Laufzeit führt sie alle pflichtgemäß als JS aus. ESM kümmert sich überhaupt nicht um Erweiterungen.

Das ist mir sehr wohl bewusst, aber der Browser führt TypeScript auch nicht aus. Es ist fast allgemein wahr, dass die Datei, die die Umgebung tatsächlich lädt, eine JavaScript-Datei ist.

Mein Punkt ist jedoch, dass, wenn Sie bereits ein .js / .d.ts -Paar haben, sagen wir aus einem Drittanbieterpaket, und die .js -Datei importieren, tsc wird Sehen Sie sich die Datei .d.ts an und laden Sie die Typen. dh ein .js / .d.ts -Paar _verhält_ sich wie eine .ts -Datei, und so sollte es sein, da Sie auf diese Weise transparent von JavaScript nach TypeScript portieren können, ohne Änderungen vorzunehmen die Importe der portierten Dateien.

Dies ist ein Fehler in TS-Node. Es stimmt nicht mit dem Verhalten von tsc überein.

Es ist eine Einschränkung des NodeJS-Loaders, kein Fehler in TS-Node: TypeStrong/ts-node#783 (Kommentar)

Es ist immer noch ein Fehler, dass TS-Node vom tsc -Verhalten abweicht. Das führt zu .ts -Dateien, die sowohl in tsc als auch in TS-Node nicht funktionieren, und ich würde tsc stark als den Standardsetzer betrachten, dem TS-Node folgen sollte .

Mein Punkt ist jedoch, dass, wenn Sie bereits ein .js/.d.ts-Paar haben, beispielsweise aus einem Drittanbieterpaket, und die .js-Datei importieren, tsc die .d.ts-Datei sieht und die Typen lädt. dh ein .js/.d.ts-Paar verhält sich wie eine .ts-Datei, und so sollte es auch sein, da Sie auf diese Weise transparent von JavaScript zu TypeScript portieren können, ohne die Importe der portierten Dateien zu ändern.

Wenn Sie ein externes _Paket_ laden, benötigen Sie irgendeinen Runtime-Paketlader (z. B. benannte Import-Maps im Browser), der die Zuordnung des benannten Moduls zur Einstiegspunktdatei durchführt. Ich denke jedoch, dass Ihr Standpunkt im Allgemeinen gilt, wenn Sie ein relatives .js/.d.ts-Paar haben. Ich bin mir nicht sicher, ob Sie in diesem Fall import ... from './foo.d.ts' oder import ... from './foo.js' tun sollten.

Die Datei .d.ts ist im Wesentlichen ein Header, der eine Struktur beschreibt, die keine Informationen darüber enthält, welcher Erweiterung sie zugeordnet ist (wobei davon ausgegangen wird, dass Sie im Allgemeinen nicht mehrere Dateien mit demselben Namen, aber unterschiedlichen Erweiterungen an derselben Stelle haben sollten, und wir Fehler beim Build, wenn Sie dies tun) - selbst heute könnte die zugehörige Runtime-"Quelle" .js oder .jsx sein (mit jsx: preserve ). Sie könnten im Großen und Ganzen eine .d.ts -Referenz nicht durch .js in einem Import zum Zeitpunkt der Ausgabe ersetzen und davon ausgehen, dass es funktioniert ...

Es ist wichtig, dass tsc nicht zu eigensinnig im weiteren Sinne ist
Aufbau- und Auflösungsannahmen.

Angesichts der Tatsache, dass es sich um ein Multitool auf einer komplexen Grenze handelt, wäre dies zu erwarten
Diese Konfiguration könnte es ermöglichen, sich so zu verhalten, wie es die Benutzer wünschen.

Es wurde sehr bewusst darauf geachtet, Auflösungsänderungen nicht offenzulegen
Teil des TSC-Kompilierungsprozesses - dies zwingt an sich zu Meinungsbildung
Benutzer und verursacht Reibung in ihren Arbeitsabläufen.

Am Mittwoch, 27. November 2019 um 16:48 Uhr Wesley Wigham [email protected]
schrieb:

Die .d.ts-Datei ist im Wesentlichen ein Header, der die Struktur beschreibt, die enthält
keine Informationen darüber, von welcher Erweiterung es abbildet (die Annahme ist, dass
im Allgemeinen sollten Sie nicht mehrere Dateien mit demselben Namen haben, aber
verschiedene Erweiterungen an derselben Stelle) - auch heute noch die dazugehörigen
Laufzeit-„Quelle“ könnte .js oder .jsx sein (unter Verwendung von jsx:konserve). Sie könnten
Ersetzen Sie im Allgemeinen nicht die .d.ts-Referenz durch .js in einem Import zum Zeitpunkt der Ausgabe
und gehe davon aus, dass es funktioniert...


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/microsoft/TypeScript/issues/16577?email_source=notifications&email_token=AAESFSQS2DQ23RR5KN3RTZ3QV3TLXA5CNFSM4DPRQTY2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFK2TPA#issuecomment-21026 ,
oder abbestellen
https://github.com/notifications/unsubscribe-auth/AAESFSUAP2YO23ZFHCOWVQLQV3TLXANCNFSM4DPRQTYQ
.

Ich bin mir nicht sicher, wie ich mit diesem Szenario umgehen soll, hatte aber Zweifel in Bezug auf dasselbe.

Ich habe eine Importkarte wie diese in meiner HTML-Datei:

<script type="importmap-shim">
      {
        "imports": {
          "@root/":"../../../",
         }
      }
</script>

Und ich habe meine ts -Datei, in die ich eine Datei wie diese importiere:

import '@root/components/page-main/page-main.js';

Jetzt funktioniert dieses Setup gut im Browser. Aber wie kann ich in VSCode navigieren/verwenden? Ich meine, ich möchte Strg+Klick auf den Import und zur Datei navigieren, Autovervollständigung erhalten, def eingeben usw.

Wenn man bedenkt, dass tsc keine Importerweiterungen von .ts in .js umschreibt, gibt es ein anderes empfohlenes Tool/Paket, mit dem ich dasselbe zur Build-Zeit tun kann? Danke.

(Ich verwende https://github.com/guybedford/es-module-shims für ES-Module und Importkarten)

Aber wie kann ich in VSCode navigieren/verwenden?

Suchen Sie nach der Compiler-Option paths .

Wenn man bedenkt, dass tsc keine Importerweiterungen von .ts in .js umschreibt, gibt es ein anderes empfohlenes Tool/Paket, mit dem ich dasselbe zur Build-Zeit tun kann? Danke.

Verwenden Sie einfach .js und es wird gut funktionieren, selbst wenn Sie sich beim Erstellen auf eine .ts -Datei beziehen.

@tvvignesh https://github.com/Zoltu/typescript-transformer-append-js-extension/ zum Umschreiben von erweiterungslosen Importen in .js zur Kompilierzeit. Ich persönlich bin kein Fan von "einfach .js in Ihre TS-Dateien einfügen", da Ihr Code in diesem Fall nicht in ts-node ausgeführt wird. Wenn Sie Ihren Code nicht in ts-node ausführen müssen, funktioniert die Verwendung von .js.

Aber wie kann ich in VSCode navigieren/verwenden?

Suchen Sie nach der Compiler-Option paths .

Wenn man bedenkt, dass tsc keine Importerweiterungen von .ts in .js umschreibt, gibt es ein anderes empfohlenes Tool/Paket, mit dem ich dasselbe zur Build-Zeit tun kann? Danke.

Verwenden Sie einfach .js und es wird gut funktionieren, selbst wenn Sie sich beim Erstellen auf eine .ts -Datei beziehen.

Danke für deine schnelle Antwort. Ich hatte die Pfadoption bereits in tsconfig.json eingestellt, konnte aber immer noch nicht mit Strg + Klick navigieren.

Dies ist meine Pfadoption in tsconfig.json

"paths": {
            "*": ["www/node_modules/*"],
            "@modules/*": ["www/node_modules/*"],
            "@root/*": ["www/*"]
        }

Verwenden Sie einfach .js und es wird gut funktionieren, selbst wenn Sie sich beim Erstellen auf eine .ts -Datei beziehen.

Das ist ziemlich unpraktisch, wenn es Tausende von Importen gibt.

Das Problem mit "nur .js verwenden" ist, dass Ihr Programm nicht funktioniert, wenn TypeScript .mjs Dateien ausgibt. Das bedeutet, dass Sie in eine Situation geraten, in der Sie TypeScript schreiben, das _entweder_ im Browser funktioniert _oder_ in NodeJS funktioniert. Sie können TypeScript nicht mehr schreiben, das in beiden funktioniert.

Ich glaube, das Argument hier lautet: "Das ist nicht die Schuld von TypeScript, das ist, dass der Browser und NodeJS auseinandergehen".

Node 13.2 unterstützt .js-Erweiterungen problemlos.

@justinfagnani Für ES-Module? Ich dachte, NodeJS würde ES-Module nur laden, wenn sie eine .mjs -Erweiterung haben, sonst würden die Dateien als CommonJS behandelt?

Ich finde diesen ganzen Thread etwas fehlgeleitet. Das explizite Schreiben der Dateierweiterung würde dieses gesamte Problem lösen. Wenn Sie eine JavaScript-Datei importieren, schreiben Sie die Erweiterung .js. Wenn Sie eine TypeScript-Datei importieren, schreiben Sie die Erweiterung .ts. Dies ist im Standard erlaubt und der TypeScript-Compiler versteht das alles gleich gut. Das einzige Problem ist, dass der Compiler angibt, dass .ts-Erweiterungen Fehler sind. Dies betrifft keine reine Transpilation, sondern ist nur ein Tippfehler. TypeScript sollte dies beheben, da offensichtlich eine .ts-Dateierweiterung gültig ist, da wir in TypeScript schreiben. Um dieses Problem zu umgehen, hat Deno.js eine VS-Code-Erweiterung: https://marketplace.visualstudio.com/items?itemName=justjavac.vscode-deno

Mit dem Aufkommen von WebAssembly werden Webanwendungen damit beginnen, immer mehr Dateitypen zu importieren. Es wird immer wichtiger, explizit anzugeben, ob Sie eine .wasm-, .js-, .ts-, .rs-, .c- usw. Datei importieren

Hat jemand tatsächlich das Skript verwendet, das ich geschrieben habe?

https://github.com/microsoft/TypeScript/issues/16577#issuecomment -310426634

eine Rückmeldung wenn ja?

@QuantumInformation Ich habe Ihr Skript nicht verwendet, aber das von mir geschriebene TypeScript-Transformer-Plugin macht im Grunde dasselbe. 😊 https://github.com/Zoltu/typescript-transformer-append-js-extension/

Zunächst einmal werde ich nicht noch einmal versuchen, Typoskript davon zu überzeugen, es zu implementieren, ich verstehe, das wirst du nicht tun.
Ich lese jedoch die Kommentare und frage mich: All diese Leute sagen, dass das Hinzufügen .js zu Pfaden alles lösen wird - verwenden Sie wirklich keine Pakete von Drittanbietern? Wie füge ich Erweiterungen zu meinen Importen hinzu, um zu beheben, was in node_modules ist?

@MicahZoltu oh schön

Was meinen Sie? Sie würden explizit die Dateierweiterung der Datei schreiben, die Sie aus node_modules importieren, wenn Sie einen Pfad verwenden. Aber wäre das nicht sowieso ein bloßer Import?

Wenn Sie einen relativen Pfad angeben, ist er nicht leer. Ich spreche jedoch von internen Importen des Pakets, das ich importiere, schauen Sie sich zum Beispiel rxjs an.

@Draccoz Ich glaube, der Punkt ist, dass, wenn jemand TypeScript wie import { ... } from './foo' schreibt und das dann als NPM-Paket veröffentlicht, ein Benutzer diese Bibliothek nicht direkt in einem Browser verwenden kann, selbst wenn sie auf ES-Module abzielt. Ich glaube, Microsoft argumentiert hier, dass das Paket falsch ist, wenn es solchen Code mit der Erwartung verteilt, dass es in einem Browser funktioniert.

Sie würden die Erweiterung der Datei schreiben, die in node_modules vorhanden ist. import * as stuff from 'rxjs/path/to/file.js'; , wenn es sich um eine JavaScript-Datei handelt, und import * as stuff from 'rxjs/path/to/file.ts'; , wenn sie eine TypeScript-Datei verteilt haben. Das funktioniert jetzt, wenn ich mich nicht irre

@lastmjs Ja, aber was ist, wenn rxjs/path/to/file.ts import foo from './bar' enthält? Sie können das nicht ändern, da Sie die Datei nicht ändern können, da es sich um eine Bibliothek eines Drittanbieters handelt.

Deshalb sollten wir darauf drängen, überall explizite Erweiterungen zu verwenden, aber ja, ich verstehe Ihren Punkt. Mein Tool (https://github.com/lastmjs/zwitterion) führt dieses Umschreiben als Notlösung für Dateien durch, die keine Erweiterungen haben.

Ja, genau das war mein Punkt - das Hinzufügen von Erweiterungen repariert keine Bibliotheken von Drittanbietern, die wir nicht ändern können, also ist das keine Lösung.
Ich verstehe auch Microsoft Point, daher forciere ich es nicht mehr (abgesehen von der Tatsache, dass das Offenhalten dieses Problems unnötige Hoffnung gibt, was Paketbetreuer daran hindert, nur den Build anzupassen, anstatt darauf zu warten, dass TS dies löst), es würde Es wäre jedoch großartig, nur Typoskript als Build-Tool und keine anderen Abhängigkeiten zu haben.

Ja, aber Hoffnung ist für viele Menschen immer noch gut

image

Trotzdem wurde durch diese Kommentare ein paar Mal gesagt, dass es NICHT implementiert wird, also warum es offen lassen?

wenn jemand TypeScript wie import { ... } from './foo' schreibt und das dann als NPM-Paket veröffentlicht

Veröffentlichen viele Leute unkompilierte TS in NPM-Paketen? Ich habe mir das für meinen eigenen internen Gebrauch angesehen. Ich erstelle Bibliotheken mit gemeinsamem Code, der von Projekten gemeinsam genutzt wird, und dachte, NPM sei eine vernünftige Möglichkeit, sie zu paketieren, und unser Team ist ausschließlich zu TS gewechselt, sodass ich es gerne vermeiden würde, die Deps kompilieren zu müssen. Aber es sieht so aus, als ob der häufigste Anwendungsfall darin besteht, das Paket mit separaten Eingaben in JS zu erstellen und dann modules oder main auf die JS und types auf die Eingaben zu verweisen.

Gibt es eine Konvention für die Veröffentlichung von unkompilierten TS in NPM? Wenn ja, ist das irgendwo dokumentiert? Ich verstehe, dass dies vom ursprünglichen Problem abweicht, aber ich denke, es ist für die Antwort relevant, da wir wissen müssen, ob "TypeScript von Drittanbietern" (Pakete) ein unterstützter Anwendungsfall / ein unterstütztes Ziel ist.

@thw0rted Entschuldigung für die Unklarheit, ich meinte:

... wenn jemand TypeScript wie import { ... } from './foo' schreibt und das dann mit TSC heute in JS transpiliert und dieses JS als NPM-Paket veröffentlicht ...

Wenn es NICHT implementiert wird, überlasse ich es MS, das Problem jetzt zu schließen.

Ah, jetzt verstehe ich es. Ja, wenn ich transpiliere (mit target: ES2018 ), lässt das ausgegebene JS die Erweiterung der import-Anweisung weg, aber es funktioniert für mich, weil der Verbraucher alles durch webpack/babel schickt und die fehlende Erweiterung ausfüllen muss Für mich. Ich bin jetzt auf dem Laufenden. Es war mir nicht einmal in den Sinn gekommen, dass mein "Paket" nicht nativ im Browser funktionieren würde, ohne zuerst das Webpack zu durchlaufen.

Ja, das ist eine harte Nuss.

@thw0rted Ich verwende kein Webpack/Babel, daher ist das Auflösen von .js aus der Box ein Problem für mich.
Eine Lösung/Problemumgehung besteht darin, den Webserver für standardmäßige Auflösungsquellen zu konfigurieren.

Tut mir leid, wenn ich das wiederhole, was andere gesagt haben, aber das ist etwas, mit dem ich jeden Tag zu tun habe, also würde ich gerne einen weiteren meiner unaufgeforderten zwei Cent einwerfen.

Ich weiß, dass TypeScript nicht auf eine bestimmte Umgebung (Node.js, Webpack usw.) ausgerichtet sein muss, aber Tatsache ist, dass es viele Umgebungen gibt, in denen die Erweiterung immer erforderlich ist, sofern nicht anders speziell konfiguriert Ich glaube nicht, dass sie ignoriert werden sollten. Importe befinden sich nicht mehr hinter einem Flag in Node und der Importpfad muss mit dem URL-Pfadnamen im Web übereinstimmen. Obwohl es keine technische Notwendigkeit gibt, .js am Ende einer URL zu haben, ist dies der De-facto-Standard.

Wenn die netten Leute bei Microsoft wirklich keine Dateiendung als Standard haben wollen, werde ich nicht darüber streiten. Sie sind wahrscheinlich klüger als ich, aber ich wäre sicherlich glücklicher, wenn Sie, anstatt abzuleiten, ob Erweiterungen auf der Grundlage anderer Importe in derselben Datei erforderlich sind, projektweit festgelegt werden könnten, damit es für die ersten automatischen Vervollständigungen von Intellisense funktioniert Import einer Datei hinzugefügt!

Kennt in der Zwischenzeit jemand VSCode-Plugins, die dies beheben? Das Hinzufügen von Import/Erweiterungen zu eslint ist das Beste, was ich tun konnte, um damit umzugehen.

Derzeit schreibe ich import Zeilen ohne .js-Erweiterung und verwende dann sed , um die .js-Erweiterung in Ausgabedateien hinzuzufügen.
https://github.com/yoursunny/NDNts/blob/9f50fcec245b33c7649fa815bbb3dd404eee160e/mk/build.sh#L12 -L14
Ich muss SourceMaps während des Produktions-Builds löschen, da sie nach der Änderung der Ausgabedateien nicht mehr übereinstimmen würden.

Ich kann keine .js-Erweiterung in .ts-Quelldateien schreiben, weil sie ts-jest unterbricht.
Während es möglich ist, Jest auf kompilierten .js-Dateien auszuführen, bricht es Coveralls .

@yoursunny Ja, sed ist eine Variante (ich habe es auch verwendet, bevorzuge aber das Ersetzen in der Datei wegen der Konfiguration, die durch die Importmap-Dateizuordnung konfiguriert werden kann), um Zeichenfolgen in generierten js-Dateien zu ersetzen, aber es riecht nicht gut =) Kann sein Das Hinzufügen von Erweiterungen ist eine nützliche Funktion/Option für ttypescript mit dem Transformations-Plugin (z. B. typescript-transform-paths von @MicahZoltu).

@richardkazuomiller dieser Teil ist nicht wahr:

Wenn die netten Leute bei Microsoft wirklich wollen, dass keine Dateiendung die Voreinstellung ist

Nur TypeScript:

  1. Ermöglicht die Modulauflösung im Node-Require-Stil (sie sollten dies erweitern, um die Auflösung im Node-Import-Stil zu ermöglichen, für die Dateierweiterungen erforderlich sind).
  2. In derselben Kompilierungseinheit werden .js-Dateien in ein .js/.d.ts-Paar aufgelöst, noch bevor sie vom Compiler generiert werden.
  3. Ändert die Importspezifizierer _überhaupt nicht, niemals_.

Die Lösung für all dies besteht also darin, einfach die .js-Dateien mit der Erweiterung .js zu importieren. TypeScript löst die richtige .ts-Datei auf und ändert den Importbezeichner nicht, sodass die Dinge nur in Browsern und Node >= 13.2 funktionieren.

@yousunny hast du einen Bug gegen ts-jest gemeldet? Sie weichen hier vom De-facto-TypeScript-Standard ab. Scheint auch ein Fehler in Overalls zu sein, wenn es keine Quellkarten in den .js-Dateien verwenden kann.

hast du einen Bug gegen ts-jest ? Sie weichen hier vom De-facto-TypeScript-Standard ab.

Nein, weil ich nicht ganz verstehe, wie die Auflösung von ts-jest funktioniert.

Scheint auch ein Fehler in Overalls zu sein, wenn es keine Quellkarten in den .js-Dateien verwenden kann.

Coveralls erhält einen lcov-Bericht von meinem Build-Prozess und zeigt dann die Codeabdeckung mithilfe von Dateien an, die an GitHub übergeben werden.
Ich übertrage keine .js-Ausgabedateien auf GitHub. Wenn ich Komponententests für .js-Dateien durchführe, verweist der lcov-Bericht auf die .js-Dateien, die nicht auf GitHub vorhanden sind.
Daher kann Overalls die Quelldateien nicht finden. Es zeigt den Abdeckungsprozentsatz an, kann aber nicht anzeigen, welche Linien nicht abgedeckt sind.

Die neue Ära ist da!

Das neu veröffentlichte Node.js v13 und alle gängigen Browser unterstützen standardmäßig native ES-Module, und es wäre großartig, wenn TypeScript diese Umgebungen auf einfache Weise unterstützen würde.

Die einfachste Lösung für die grundlegendsten Anwendungsfälle (eine Website, die über einen einfachen statischen Dateiserver bereitgestellt wird) wäre das Hinzufügen einer neuen Compiler-Option wie "appendJsExtension": true oder ähnlich.

@mjbvz Das Problem im Repo von VS Code, das Sie geschlossen haben, ist etwas anders: Es geht darum, die automatische Vervollständigung zu verwenden, um Importanweisungen automatisch hinzuzufügen. Wenn VS Code dies tut, wird die import-Anweisung ohne eine .js -Erweiterung hinzugefügt, und es ist leicht, dies bis zu einem Laufzeitfehler zu übersehen.

Wenn TypeScript jedoch eine Option wie "appendJsExtension": true oder ähnliches hinzufügt, spielt dies keine große Rolle, und wir könnten TS-Code ohne .js in der Quelle schreiben.

Vielleicht sollte das VS Code-Plugin eine Option zum Aktivieren/Deaktivieren des automatischen Hinzufügens von .js -Erweiterungen in automatisch vervollständigten Importanweisungen haben?

@mjbvz Das VS Code / Intellisense-Problem ist verwandt, sollte aber nicht als Dupe geschlossen werden. Wenn dieses Problem schließlich als WONTFIX geschlossen wird, würde dies die Bedeutung des VS-Code-Problems tatsächlich erhöhen.

Ich sehe einen übersehenen Punkt und verstehe nicht, wie Lösungen, bei denen die JS-Erweiterung ein Sonderfall ist, dies lösen würden: Für ESM hat keine Erweiterung einen besonderen Status, selbst Dateien ohne Erweiterung sind völlig in Ordnung, solange der Server sie dem Browser mit bereitstellt den entsprechenden Text-/Javascript-MIME-Typ. Das bedeutet, dass Code wie:

import something from './javascript-code.png';
import something2 from './javascript-code2.js';
import something3 from './javascript-code3.ts';

Dies alles gilt, solange die Dateien (unabhängig von ihren Erweiterungen) JavaScript-Code enthalten und mit dem JavaScript-MIME-Typ an den Browser geliefert werden.

Da TypeScript eine typsichere Obermenge von JavaScript sein sollte, sehe ich keine Möglichkeit, Importe wie die oben genannten zuzulassen, da der Code gültiges JavaScript ist und wenn TypeScript es nicht akzeptiert, ist es keine sichere Obermenge mehr von JavaScript, ist das nicht richtig?

Also Lösungen, bei denen die JS-Erweiterung entweder impliziert oder die einzige zulässige ist, die meiner Meinung nach nicht geschnitten werden kann? Darüber hinaus können selbst die TS- und DTS-Erweiterungen IMO keinen Sonderfall darstellen, denn obwohl dies normalerweise nicht der Fall ist, könnten sie JavaScript-Code enthalten, nicht TypeScript-Code und Server zum Browser als solchem, soweit es ESM betrifft, überhaupt kein Problem , sofern sie mit dem richtigen MIME-Typ bedient werden.

Übersehe ich etwas an dieser Front? Ist es möglich, dass TypeScript keine Unterstützung für beliebige (einschließlich fehlende) Erweiterungen in Codeimporten implementiert, und ist es möglich, dass TypeScript weiterhin TS-Erweiterungen in Modulimporten annimmt, da file.ts und file (keine Erweiterung) würde es dann zu einem Konflikt kommen?

Web- und Service-Mitarbeiter erhalten auch Unterstützung für den Import/Export von ES-Modulen .

Ich unterstütze und befürworte voll und ganz die Idee von @trusktr , ihre Idee als Compiler-Option zu implementieren. Es ist nicht so, dass ich Bundler wie Webpack und Rollup loswerden möchte. Aber ich glaube, dass eine Funktion wie diese viel Ärger und Zeitaufwand für die Einrichtung von Bundlern erspart, wenn Sie nur ein einfaches Typoskript-Projekt kompilieren möchten, ohne durch Reifen zu springen oder umständliche Problemumgehungen zu verwenden.

Bitte betrachten Sie dies als Option für den Typescript-Compiler. <3

Kennt jemand eine Möglichkeit, wie Sie die kompilierten einzelnen js-Dateien in einem Browser ohne Webpack oder --outFile mit einem beliebigen Modulsystem ausführen können?

Mein Problem ist folgendes: Das ziemlich große TypeScript-Projekt, mit dem ich arbeite, dauert ungefähr 35 Sekunden, um mit Webpack in eine gebündelte js-Datei mit ts-loader zu kompilieren.
Die einzige Möglichkeit, dies zu optimieren, war die Verwendung transpileOnly , wodurch die Kompilierzeit auf 20 Sekunden verkürzt wurde, aber das ist immer noch langsam und ich verliere die Typprüfung.
Webpack loswerden Ich könnte mit outFile auf etwa 14 Sekunden kommen, aber das ist mir immer noch zu langsam. Die Verwendung incremental hat keinen Unterschied gemacht.

Die einzige Möglichkeit, einige Sekunden Kompilierzeit zu erreichen, bestand darin, 1 js-Datei pro 1 ts-Datei auszugeben und das incremental -Flag zu verwenden. In diesem Fall stelle ich mir vor, dass ts nur die Dateien erkennt und kompiliert, die sich wirklich geändert haben. Das Problem ist, dass ich dies in keinem der von mir ausprobierten Modulziele in einem Browser ausführen konnte: system, amd, es6.
Ich verwende paths Mapping in tsconfig.json und in den kompilierten js-Dateien beziehen sich die Fehler, die ich erhalte, hauptsächlich darauf, dass ich diese Aliase nicht auflösen kann.

Gibt es eine Möglichkeit, dies zu erreichen?

@andrewvarga Ich führe derzeit alle meine kompilierten TypeScript-Dateien direkt im Browser aus, ohne sie zu bündeln oder in eine einzige Datei zu kompilieren. Der einfachste Weg, dies zu tun, ist:

  1. Stellen Sie sicher, dass alle Importe in TypeScript-Dateien die Erweiterung .js haben.
  2. Führen Sie bei Bedarf einen Entwicklungsserver aus, der Importe von npm-Paketnamen für Abhängigkeiten auflöst. es-dev-server ist das einfachste, das ich kenne.
  3. Führen Sie tsc --watch aus (stellen Sie sicher, dass das Modul in Ihrer tsconfig esnext ist)

Das ist es. Wenn Sie nur die .js -Erweiterung für Importe in Ihr TypeScript schreiben, benötigen Sie keine weiteren Tools, um die Dateien für Browser zu reparieren.

@justinfagnani Kumpel, Sie haben die wichtigste Information vergessen - Typen müssen im jsdoc-Format vorliegen, jede Typoskript-Abstraktion über natives JavaScript führt dazu, dass der Parser fehlschlägt.

@Draccoz tsc gibt JavaScript aus, nicht TypeScript.

@andrewvarga Der einfachste Weg, den ich kenne, um ohne Bündelung zu transpilieren, ist mein Projekt Zwitterion . Es ist als Ersatz für einen statischen Dateiserver konzipiert, sodass Sie Ihre Entwicklungsmethode nicht ändern müssen. Sie können mit expliziten Dateierweiterungen (.js für JavaScript und .ts für TypeScript) sogar in Skriptelementen importieren und exportieren. Es ist sehr leistungsfähig, führt Caching und automatisches Neuladen durch, wenn sich Dateien ändern. Für die statische Analyse (Tippfehler) müssen Sie sich jedoch auf Ihren Editor verlassen

@andrewvarga Ich verwende https://github.com/Zoltu/typescript-transformer-append-js-extension/ und ziele auf native ES-Module ab, die in allen modernen Browsern geladen werden (außer Safari, dem neuen IE).

Wenn Ihre Laufzeit-NPM-Abhängigkeiten ziemlich begrenzt sind, können Sie sie mit es-modules-shim ohne Bündelung laden. Sie können eine von mir erstellte Reaktionsvorlage sehen, die zeigt, wie all dies zusammenarbeitet: https://github.com/Zoltu/react-es2015-template

@MicahZoltu Safari unterstützt ES-Module, das weiß ich aufgrund von Caniuse und persönlicher Erfahrung: https://caniuse.com/#search =modules

@justinfagnani awww Entschuldigung, ich habe den Teil "compiled TypeScript" verpasst, dachte, Sie sprachen über das jsdoc-Typoskript.

Danke an alle für die diversen Tipps!

Was ich gefunden habe, ist, dass durch die Verwendung des hard-source-webpack-plugin npm-Moduls für Webpack und transpileOnly: true in den ts-loader-Optionen die Build-Zeit auf etwa 4-5 Sekunden verkürzt wurde.
Dies wird natürlich Tippfehler ignorieren, daher ist es nur nützlich für schnelle Iterationen beim Erstellen, beim Ausprobieren im Browser und beim Verlassen auf die IDE für potenzielle Fehler, aber ich denke, es ist während der Entwicklung sehr nützlich.

Um die beiden TS-Fehler zu erhalten und schnell zu kompilieren, denke ich immer noch, dass die einzige Möglichkeit darin besteht, Module im Browser auszuführen, aber die fehlende Unterstützung für Import-Maps und js-Erweiterungen machte dies schwierig.
@justinfagnani @MicahZoltu danke, ich werde diese Optionen ausprobieren. Im Allgemeinen vermeide ich es lieber, ein weiteres npm-Modul zu verwenden, aber es scheint unvermeidlich zu sein.

Ich habe versucht, es auch mit systemjs zum Laufen zu bringen, aber ich bin beim Importieren von Karten hängen geblieben.

@andrewvarga Sie können SystemJs anhand meines leichten Beispiels mit importmap ausprobieren.
Sie können auch mein schweres Beispiel ausprobieren - systemjs & esm alternative, aber esm importmaps werden von native nicht unterstützt, und wir sollten Module manuell auflösen (gulp-replace), oder Sie können es-module-shims versuchen.

Wenn ich also tsc als meinen einzigen Compiler verwende, ziele ich auf esnext oder es2015 als Modultyp ab. Gibt es eine Möglichkeit, die Ausgabe direkt in meinem Browser zu verwenden?

https://github.com/alshdavid-sandbox/typescript-only-compiler

Wenn ich den Rest dieses Threads richtig verstehe, sollte Typescript Ihren Code gerne kompilieren, wenn Sie diese Zeile ändern, um from "./module.js" zu sagen. Dann hat das kompilierte index.js eine gültige ES6-Importanweisung und es sollte alles funktionieren.

Es sei denn, Sie importieren eine Bibliothek, die entweder nicht weiß, wie man ES importiert, oder die sich nicht darum kümmert: P.

Ich habe ein Plugin für Gulp erstellt, das .js zum Importieren von Dateipfaden hinzufügt. (auch eine Bonus-ts-Pfadauflösung).

Ich habe Gulp verwendet, weil ich keinen anderen Task-Runner kenne, mit dem ich im Wesentlichen einen einfachen Nachbearbeitungsschritt an den tsc-Compiler anhängen könnte (sowohl im Überwachungs- als auch im normalen Modus). Webpack und Rollup bündeln beide ausschließlich, und ich möchte es-Module ausgeben.

Es funktioniert, aber es ist langsam zu beobachten, wie es scheint, das Ganze wieder aufzubauen.

https://github.com/alshdavid-sandbox/typescript-only-compiler/tree/gulp

Dies wird immer wichtiger, da sich das Knotenteam gegen erweiterungslose Importe entschieden hat
https://github.com/nodejs/modules/issues/444

Add import maps hat sich auch gegen erweiterungslose Importe entschieden
https://github.com/WICG/import-maps/issues/194

Wenn wir das mit Typoskript kompilierte es-Modul im Browser oder Knoten verwenden möchten, müssen wir Erweiterungen mit Typoskript hinzufügen? (für interne Module) und manuell für externe Module? @weswigham

Nochmals @chyzwar , wenn Sie einfach die Erweiterungen .js in Ihre TypeScript-Quelle schreiben, hat die kompilierte Ausgabe die richtigen Erweiterungen und die Module funktionieren in Browsern und Node. Sie benötigen keine zusätzlichen Transformationstools oder tsc , um irgendetwas für Sie zu tun.

Für den Entwickler ist es einfacher, Folgendes zu tun: Wenn es sich um eine TypeScript-Quelldatei handelt, schreiben Sie eine .ts-Erweiterung. Wenn es sich um eine JavaScript-Quelldatei handelt, schreiben Sie eine .js-Erweiterung. Das wird auch im Browser korrekt kompiliert und ausgeführt (.ts benötigt einen Anwendungs-/Javascript-MIME-Typ). Die Erweiterung sollte mit dem Quelldateityp übereinstimmen. tsc- und ES-Module können damit umgehen (zumindest ES-Module im Browser, Node.js folgt hoffentlich genauso)

@justinfagnani tsc ist ziemlich zufrieden damit, und es ist fair, hier zu sagen "nicht unser Problem", aber es scheint hier keinen Konsens darüber zu geben, was richtig ist,

Zwischen tsc, vscode, webpack und ts-node kann keiner wirklich gut gegen einen Standard ankommen, der gerade nativ verfügbar wird (jetzt verfügbarer Browser und Knoten).

Beispiel 1

Ich möchte ein modernes Javascript-Paket schreiben, es in Typoskript verfassen und die Typen für die Verteilung als Ecmascript-Modul entfernen (wobei Import- und Exportanweisungen beibehalten werden).

Beispiel 2

Ich erstelle eine statische Website mit Modulen in vscode, standardmäßig wird sie automatisch ohne Erweiterung für jeden ersten Import importiert und Sie müssen dies manuell anpassen.

In diesen Fällen kann tsc damit umgehen und sogar Deskriptordateien beiseite exportieren, die dann das Konsumieren der es-Modulverteilung aus Typoskript mit vollständigen Typisierungen unterstützen (großartig).

Aber wenn ich Testcode gegen die Quelle ausführen möchte, könnte ich ts-node verwenden, aber hier ist ts-node nicht glücklich.

In ähnlicher Weise haben sich tsc, vscode und webpack entwickelt, um Folgendes zu tun:

  1. vscode wird automatisch ohne Erweiterung importiert
  2. tsc schreibt Importe gerne in eine js-Datei um, was die ts-Datei bedeutet
  3. webpack macht hier verschiedene Magie, um nach Standarderweiterungen zu suchen

Sind alles Dinge, die jetzt hinterfragt werden sollten, dass vier Implementierungen (Chrome, Firefox, Safari, Node) alle erwarten, dass der Importpfad auf etwas zeigen sollte, das direkt in eine Datei aufgelöst werden kann.

Das Hinzufügen .js zu einem Import sollte eine vorübergehende Problemumgehung sein, keine endgültige Lösung. Wenn überhaupt, fühlt es sich wie ein Hack an. Eine Möglichkeit, den Compiler zu täuschen. Und der Versuch, einen Compiler zu überlisten, ist meiner Meinung nach eine schreckliche Ideologie. Ich kann mir nur vorstellen, wie verwirrend das für Typescript-Neulinge sein muss. Eine Sprache, die Javascript-Entwicklern helfen soll, _besseren_ Code zu schreiben.

Wie bereits von mehreren Personen erwähnt, gibt TypeScript diese aus, wenn Sie .js zum Import hinzufügen, und alles funktioniert (zumindest in Ihrem Code). Die Begründung, dass tsc Erweiterungen hinzufügen sollte, weil sie im Browser nicht funktionieren, ist wie die Aufforderung an TypeScript, vom Entwickler verursachte Laufzeitfehler zu beheben - ok, aber warum kann der Entwickler sie nicht selbst beheben?
Versteh mich nicht falsch, ich würde es lieben, wenn tsc meine einzige Entwicklerabhängigkeit wäre, aber einige Dinge werden einfach nicht passieren und bleiben ein Traum.

Ich würde es lieben, wenn tsc meine einzige Entwicklerabhängigkeit wäre, aber einige Dinge werden einfach nicht passieren und bleiben ein Traum.

Ich muss Dutzende von nahezu identischen Kommentaren gesehen haben, die sich über mehrere Jahre zu #3469 erstrecken, einschließlich einiger vom Typescript-Team. "Es ist ein Typprüfer, er soll eine Sache gut machen, erwarte nicht, dass er deine gesamte Toolchain ersetzt ..." Es dauerte 3 Jahre, aber sie fügten immer noch den Build-Modus hinzu, weil gute Argumente dafür vorgebracht wurden die richtige Richtung zu gehen.

Webpack und Rollup bündeln beide ausschließlich, und ich möchte es-Module ausgeben.

@alshdavid Rollup funktioniert möglicherweise für Sie, wenn Sie das Ausgabeformat auf esm und preserveModules auf true setzen: https://rollupjs.org/guide/en/#preservemodules

vielleicht waren "erweiterungslose" Importe eine Erbsünde, nicht kompatibel mit der Funktionsweise von Browsern

Jetzt ist es an der Zeit, unseren Quellcode zu korrigieren und die .js -Erweiterungen einzufügen: Wenn Sie heute .js -Erweiterungen zu Ihrem Quellcode hinzufügen, funktioniert alles: Der Browser ist zufrieden, Typoskript ist agnostisch und Den Bündlern ist das egal

also war Extensionless vielleicht ein Fehler in unserem Quellcode, den unsere alten Werkzeuge kompensierten

Das Schreiben der .js -Erweiterung in Imports in Typoskript-Quellcode ist völliger Unsinn. Es funktioniert, es behält die Erweiterung in der Ausgabe bei, aber es wird wahrscheinlich mit Fehlern "Datei konnte nicht aufgelöst werden" in ESLint-Regeln (oder TypeScript) in VSCode oder dem von Ihnen verwendeten Editor fehlschlagen. Ganz zu schweigen davon, wenn Sie gegen diesen Typescript-Quellcode testen. Dann sollte das Testtool auch von diesem Bullshit-Verhalten wissen. Ich bin mir fast sicher, dass es Fehler auslöst, dass Dateien nicht aufgelöst werden können.

Einfaches Beispiel

src/index.ts
src/foo.ts
test/index.ts

src/foo.ts

export default (a: number) => a + 100;

src/index.ts

// okay, editor (without ESLint) doesn't report error here
import foo from './foo.js';

export default () => {
  console.log(foo(123));
}

test/index.ts

// errm... ts or js ext?! .ts should be the one that make sense
// and that's how the testing too will expect it to be, otherwise will throw
// but then it will detect some weird `.js` ext in the source files...
// which again won't be able to resolve... complete bullshit. 
import main from '../src/index.ts';
import foo from '../src/foo.ts';

test('some boolshit', () => {
  main();
});

test('about foo', () => {
  foo(20);
});

Entschuldigung für die "Bullshit" -Nutzung, aber das ist die Wahrheit.

Ich denke nicht, dass es so schwer ist, eine grundlegende Option zu implementieren, die, wenn der Compiler die Erweiterung ( .ts ) in den Importen sieht, sie in .js umwandelt (oder optional sogar die Angabe der Ausgabeerweiterung erlaubt). sein). Wenn keine Erweiterung vorhanden ist, behalten Sie die Erweiterungen nicht bei (halbaktuelles Verhalten?).

Das Schreiben der Erweiterung .js in Imports in Typoskript-Quellcode ist völliger Unsinn. Es funktioniert, es behält die Erweiterung in der Ausgabe bei, aber es wird wahrscheinlich mit Fehlern "Datei konnte nicht aufgelöst werden" in ESLint-Regeln (oder TypeScript) in VSCode oder dem von Ihnen verwendeten Editor fehlschlagen.

Das ist einfach nicht wahr. ESLint, TypeScript, VS Code und alle anderen TypeScript-bezogenen Tools, die ich verwendet habe, funktionieren mit dieser Methode _einfach_. Es ist kein Hack und hat eine sehr vernünftige Begründung: dass die Datei, die Sie importieren, tatsächlich _die Datei .js ist, und dass sich Ihre Erweiterungen nicht ändern sollten, nur weil eine importierte Datei Teil der lokalen Datei ist Projekt oder vorkompiliert als Teil eines Pakets eines Drittanbieters.

Auch hier schreibe ich meinen gesamten TypeScript-Code auf diese Weise und es löst alle Probleme, die in diesem Thread angesprochen werden. Die Ausgabe funktioniert hervorragend in Browsern und Node. Es ist kein Bullshit, es funktioniert einfach, _heute_.

Nein, ist es nicht. Zumindest im häufigsten Fall, in dem das Ausgabeverzeichnis dist oder build oder lib usw. ist. Ihre kompilierten Dateien befinden sich nicht im selben Verzeichnis, sie existieren einfach nie dort (in src/ ) - weder beim Testen, noch beim Codieren im Editor.

./foo.js in den obigen src/index.ts zu haben/zu sehen und zu importieren macht für mich KEINEN Sinn - es sei denn natürlich, wenn Sie wirklich die js/json-Datei importieren wollen, was völlig in Ordnung ist. Aber ./foo.js zu schreiben, wenn Sie wirklich eine andere Typoskript-Quelldatei ( ./foo.ts ) meinen, ist ... brutal. Es ist irreführend und verwirrend und definitiv falsch.

Ich bin mir fast sicher, wenn ich das obige test/index.ts mit Jest ausführe, wird es mit dem Fehler fehlschlagen, dass es ./foo.js nicht finden/auflösen kann, weil es nur ./foo.ts gibt.

Wenn wir alles beiseite lassen, warum ist es erlaubt, .js Erweiterung zu haben, aber nicht .ts eine (ts meldet Fehler im Editor)? Es ist eine grundlegende, einfache und dumme Inkonsistenz. Wie viele andere "nur weil" Probleme in TypeScript.

Ich habe tatsächlich die Logik verloren, warum dieses Problem so benannt wird, wenn es tatsächlich möglich ist, mit der Erweiterung .js zu enden. Ich denke, das Problem ist das komplette Gegenteil - dass es nicht mit .ts enden kann (ab 3.7+)

warum ist die .ts Erweiterung bei Importen total verboten?!

Und lassen Sie uns klären. Ich rede von Entwicklungszeit und Erfahrung. Ich verstehe, warum wir die .js -Erweiterung in der kompilierten Ausgabe beibehalten können und warum wir .js ext zu Importen in einer .ts -Datei hinzufügen können, ohne Fehler zu melden, und ich Ich bin damit einverstanden.

TypeScript ist eine Obermenge von JavaScript, aber es ist kein JavaScript. JavaScript ist ein Kompilierungsziel für TypeScript.

In Anbetracht dessen würde ich trotz des Wissens, dass TS zu JS kompiliert wird, erwarten, dass sich TypeScript-Code vollständig in sich geschlossen verhält.

Das Schreiben eines .js beim Versuch, eine .ts -Datei zu importieren, setzt die Kenntnis des Zielkompilierungstyps voraus und setzt voraus, dass das Kompilierungsziel immer JavaScript ist.

Was ist, wenn wir TypeScript in eine Webassembly-Binärdatei kompilieren oder TypeScript-Code mit einer alternativen Laufzeitumgebung wie Deno oder ts-node ausführen?

Importanweisungen, die mit .js enden, machen in solchen Kontexten keinen Sinn.

Ich würde eher gezwungen sein, .ts in meine Importpfade einzugeben oder keine angegebene Erweiterung zu haben, um eine TypeScript-Quelldatei anzunehmen.

Es ist traurig, dass Typoskript eine eigene Erweiterung erfunden hat, anstatt nur ein Syntax-Zucker wie Flow zu sein.

@phaux Ich würde niemals mit einem Projekt arbeiten wollen, das Quell- und Dist-Dateien unter derselben Erweiterung mischt, selbst wenn sie sich in verschiedenen Ordnern befinden. Es ist, als würde man alle Dateien index.js nennen, nur weil sie sich in verschiedenen Ordnern befinden ...

Dieses Problem (das größer ist als TypeScript) scheint IntelliSense von Visual Studio Code daran zu hindern, in Webbrowsern und Node zu funktionieren – was vollständige (relative) Dateipfade in Importbezeichnern erfordert. Ohne dies funktionieren die generierten import -Anweisungen, die es erstellt, nur mit Transpilern und Bundlern wie WebPack und TypeScript selbst.

Die Antwort des VSCode-Teams war, dass Erweiterungen durch den Code hinzugefügt werden sollten, der Vorschläge für den automatischen Import bereitstellt. Ich vermute, das ist der TypeScript Language Server (nicht tsc , um den es hier in der Diskussion ging).

Kann jemand, der sich wirklich auskennt, bestätigen (oder korrigieren), dass VSCode Vorschläge für den automatischen Import vom TypeScript Language Server erhält?

Die Situation ist ein wenig kompliziert und nuanciert, und während die „.js“-Erweiterungen zunächst den eleganten Intuitionen und Idealen vieler Menschen zuwiderlaufen, könnte es unklug und verwirrend sein, wenn Typoskript stark von ratifizierten Browserstandards und ausgelieferten Implementierungen abweicht

vielleicht betrachten wir das aktuelle Paradigma wie folgt:
Typoskript-Importe beschreiben, was zur Laufzeit importiert wird – das heißt, Ihre Importe werden in Ihrem „dist“-Verzeichnis ausgeführt, nicht in „src“ – wie fetch -Aufrufe und der Rest – wenn wir diese Idee tolerieren können, wird der Rest einfach und konsequent

Es scheint sicherlich eine schlechte Idee zu sein, Typoskript blind „.js“ an erweiterungslose Importe anhängen zu lassen, wie es node für commonjs tut (es ist erwähnenswert, dass die Node-ESM-Unterstützung „.js“ genauso erfordert wie Typoskript heute) – blind „.js“ anhängen würde neue Probleme aufwerfen, wie das Importieren wirklich erweiterungsloser Javascript-Dateien oder sogar anderer Dateitypen wie css oder json – es würde Erweiterungen sinnvoll machen und eine spezielle Parsing-Logik erfordern, wodurch ein deutlicher Unterschied zwischen Browser- und Typoskript-Semantik entsteht – und wir werden es offensichtlich nicht tun um fetch -Aufrufe auf die gleiche Weise umzuschreiben, also sollte import vielleicht ähnlich bleiben?

Ich frage mich jedoch, ob es für Typoskript relativ harmlos ist, ".ts" -Erweiterungen in ".js" umzuwandeln?

Das würde natürlich den Import einer Javascript -Datei mit der Erweiterung „.ts“ unmöglich machen – aber vielleicht ist das ein bisschen verrückte Magie, die wir tolerieren könnten? auf der anderen Seite ist es ein funky, magischer, idiosynkratischer Unterschied zwischen Browser- und Typoskript-Semantik, den Entwickler lernen und verstehen müssten (was sicherlich seltsame Gotchyas erzeugt) – also ist mein Instinkt, die Dinge dort zu belassen, wo sie heute stehen

Auf der anderen Seite, wenn wir die Dinge unverändert lassen, wird die Magie einfach in Typoskript verlagert, das die ".js"-Importe mit den entsprechenden ".ts"-Quelldateien in Beziehung setzen muss - dies scheint mir ein vernünftigerer Ort zu sein beherbergen die Magie und sind intern in Typoskript, anstatt die Browsersemantik mit Füßen zu treten

🥃 jagen

@rconnamacher , @TomasHubelbauer

Dieses Problem (das größer ist als TypeScript) scheint IntelliSense von Visual Studio Code daran zu hindern, in Webbrowsern und Node zu funktionieren – was vollständige (relative) Dateipfade in Importbezeichnern erfordert. Ohne dies funktionieren die generierten Importanweisungen nur mit Transpilern und Bundlern wie WebPack und TypeScript selbst.

Ich denke, es gibt hier nur einige Verwirrung – es ist heute sehr gut möglich, eine Typescript-Bibliothek oder App zu erstellen, die hervorragend mit vscode und intellisense funktioniert, die in Browsern und Nodes funktioniert und in esm oder commonjs funktioniert – eine wirklich universelle Lösung ist heute möglich

Ich habe an einer Handvoll offener Bibliotheken gearbeitet, die dies aufweisen – renraku , cynic , redcrypto , authoritarian

Schicken Sie mir eine E-Mail und ich erkläre Ihnen gerne mehr

:winken: jagen

Ein weiterer Punkt ist, dass es zu Verwirrung darüber führt, auf welche Datei Sie zugreifen. Es ist bereits unklar, was tsc nach der Modulauflösung betrachtet, wenn Sie eine .js - und eine .ts -Datei nebeneinander haben.

/folder
  a.ts
  a.js
  index.ts

Wenn in index.ts , wenn moduleResolution: 'node' verwendet wird

// points to a.ts
import * as a from './a` 

// points to a.ts
import * as a from './a.js` 

// compiler emits error
import * as a from './a.ts` 

Es ist bereits unklar, was tsc nach der Modulauflösung betrachtet, wenn Sie eine .js- und eine .ts-Datei nebeneinander haben.

OK, sicher, irgendwie, aber wenn a.js etwas anderes als die transpilierte Version von a.ts ist, dann ist etwas katastrophal schief gelaufen und es ist nicht die Schuld von TypeScript.

@thw0rted Wenn Sie in eine einzelne JS-Bundle-Datei kompilieren, generiert TypeScript keine JS-Gegenstücke für die eingegebenen TypeScript-Dateien, sondern nur die einzelne Bundle-Datei. In diesem Fall ist es völlig legal, eine JS-Datei für und eine TS-Datei mit demselben Namen zu haben, die in keiner Weise übereinstimmen.

Es ist nicht "illegal", aber das bedeutet nicht, dass es eine gute Idee ist. Haben Sie ein konkretes Beispiel dafür, wo Sie das eigentlich wollen würden?

Es wäre einfach schön, TypeScript ohne Bundler, Loader und in einer Weise zu verwenden, die JavaScript ausgibt, das von modernen Browsern direkt verwendet werden kann.

Als Beispiel:
https://github.com/alshdavid/tsc-website

Aber ich spüre den Schmerz des Problems. Das TypeScript-Team möchte keine Modulauflösung implementieren. Aus dem gleichen Grund kann der TypeScript-Compiler paths zur Kompilierzeit nicht in ihre tatsächlichen relativen Pfade konvertieren.

Das Konvertieren eines Imports von .ts in .js oder das Hinzufügen von .js zu einem Import ohne Erweiterung bedeutet, dass das TypeScript-Team eine Modulauflösung implementieren würde, was außerhalb des Umfangs liegt.

Eine Lösung dafür besteht darin, dass das TypeScript-Team eine Möglichkeit bietet, Erweiterungen einzuführen, damit wir diese Dinge implementieren können.

Eine Lösung dafür besteht darin, dass das TypeScript-Team eine Möglichkeit bietet, Erweiterungen einzuführen, damit wir diese Dinge implementieren können.

Sie tun es, es wird nur nicht über tsc (nur durch programmgesteuerten Aufruf des Compilers). Glücklicherweise hat jemand einen Wrapper um den Core-Compiler gebaut, der _exakt_ wie tsc funktioniert, außer dass er Erweiterungen über die Konfiguration unterstützt. Mit diesem TSC-Wrapper können Sie eine Erweiterung wie https://github.com/Zoltu/typescript-transformer-append-js-extension/ verwenden, um die Erweiterung .js automatisch hinzuzufügen.

@alshdavid Ihr Beispiel in GitHub funktioniert in Browsern ohne Bundler, wenn Sie nur die Erweiterung .js bei Importen einschließen. Ich habe eine PR eingereicht, um das Problem zu beheben.

@alshdavid Vielleicht interessiert Sie mein Beispielprojekt (esm for modern & IE11 with SystemJS ).
Aber ich bin gezwungen, esm-Module manuell aufzulösen =(

Ich habe im Prinzip kein Problem damit, .js in alle meine import s einzufügen, aber leider offenbart es eine schlechte Interaktion mit einigen Tools. Beispielsweise drosselt ts-node: https://github.com/TypeStrong/ts-node/issues/783. Es scheint keine klare Einigung darüber zu geben, wessen Verantwortung dies ist - TypeScript, um die Erweiterung .js (unter bestimmten Umständen) auszugeben, oder jedes Tool, das TypeScript-Quellen verwendet, um die Übersetzung durchzuführen. Und solange jeder den Schwarzen Peter weitergibt, leiden die Benutzer unter schlecht dokumentierten Plugins oder umständlichen Servicemitarbeitern, um die Interop-Inkompatibilitäten zu umgehen.

Gibt es dazu irgendwelche Updates? Ich kann ehrlich gesagt nicht glauben, dass es nicht möglich zu sein scheint, TypeScript heute ohne einen externen Modullader oder Bundler wie Webpack normal zu verwenden. Das kommt mir sehr komisch und auch frustrierend vor. Wenn ich ein externes Modul verwenden muss, damit TypeScript vollständig funktioniert, sollte das gestartet werden.

Ich versuche, dies in meiner Electron-App zu verwenden, weshalb ich keinen Grund sehe, einen Web-Bundler zu verwenden, und ich möchte auch keinen externen Modullader installieren, wenn er nicht benötigt wird. Aber das macht mich wahnsinnig. Nicht einmal in der Lage zu sein, ein grundlegendes TypeScript + Electron-Setup zum Laufen zu bringen, obwohl beide überall als die beste Lösung da draußen gelobt werden. Das ist verrückt, um ehrlich zu sein. Ich weiß nicht, ob ich nur etwas übersehe, aber keine adäquate Lösung finden zu können, ist mehr als frustrierend.

Und wenn ich es wirklich nicht bin, verstehe ich nicht, warum dieses Problem in 3 Jahren nicht behoben wurde ...

Ich habe kürzlich das Typoskript-Tutorial abgeschlossen und als ich dann versuchte, einige ts-Dateien zu erstellen, kam ich um dieses Problem herum. Ich bin völlig neu in dieser js-ts-Welt, also verzeihen Sie mir, wenn etwas falsch oder irreführend / falsch informiert ist.

Was ich tat, war während des Importierens

Ich habe einfach die Erweiterung .js in die ts -Datei eingefügt, und als ich dann das Intellisense überprüfte, funktionierte es auch, als ich es mit tsc transpilierte, es fügte der generierten Ausgabedatei auch die Erweiterung .js hinzu.

Folgendes habe ich getan.
tsc -p tsconfig.json

{
"compilerOptions": {
//"modul": "amd",
"modul": "es6",
"Ziel": "es6",
"noImplicitAny": falsch,
"removeComments": wahr,
"preserveConstEnums": falsch,
//"outFile": "js",
"outDir":"js",
"sourceMap": falsch
},
"enthalten": [
"testscript.ts"
]
}

Obwohl es bei mir funktioniert hat.

Mein Zweifel ist, dass es keine svgwrapper.js zum Importieren gibt
warum/wie hat es funktioniert? (Ich gehe davon aus, dass es keine Erweiterung berücksichtigt)

Ich hänge den Screenshot als Referenz an.

ts-js-ext-issue

@yogeshjog genau so ist und soll tsc funktionieren. Sie importieren das Modul mit dem Dateinamen, der generiert wird. Ob das importierte Modul ursprünglich als .ts -Datei oder als .d.ts / .js -Paar geschrieben ist, sollte vom importierenden Modul nicht erkennbar sein.

@yogeshjog genau so ist und soll tsc funktionieren. Sie importieren das Modul mit dem Dateinamen, der generiert wird. Ob das importierte Modul ursprünglich als .ts -Datei oder als .d.ts / .js -Paar geschrieben ist, sollte vom importierenden Modul nicht erkennbar sein.

Danke! @justinfagnani zur Klarstellung 👍

Sie importieren das Modul mit dem Dateinamen, der generiert wird.

TypeScript erlaubt aber auch das Weglassen der Erweiterung, was laut ECMAScript nicht erlaubt ist. Es lässt sogar die Erweiterung weg, wenn die Auto-Import-Funktion in VSCode verwendet wird, was am nervigsten ist. Sie schreiben etwas JS und TS sagt, dass es in Ordnung ist, und dann stürzt es zur Laufzeit ab.

Aber TypeScript erlaubt es auch, die Erweiterung wegzulassen

Bei Verwendung der Knotenauflösung. tsconfig ist zumindest so eingerichtet, dass es andere Auflösungsmodi zulässt, die davor warnen würden, aber ich verstehe, dass das Team die Unterstützung nativer Module belassen hat, bevor weitere Modi hinzugefügt werden.

was laut ECMAScript nicht erlaubt ist.

ECMAScript sagt nichts über Importbezeichner aus. Das bleibt den Hostumgebungen wie HTML und Node überlassen. TypeScript unterstützt die Knotenauflösung beim Laden von Modulen und interpretiert die Auflösung anhand der Compiler-_Ausgabe_, nicht der Compiler-_Eingabe_. Auf diese Weise funktionieren die Spezifizierer nach der Kompilierung und sie funktionieren unabhängig davon, ob Sie versuchen, ein kompiliertes Modul zu importieren oder nicht.

Da TypeScript die Knotenauflösung verwendet, die eine Pfadsuche durchführt, um './foo' info './foo.js' umzuwandeln, ist './foo' gültig. Aber die Knotenauflösung wird './foo.ts' nicht in './foo.js' , also ist './foo.ts' ungültig.

Aber das ist innerhalb der Knotenauflösung. Wenn Sie versuchen, eine andere Umgebung wie HTML oder die native Modulunterstützung von Node zu verwenden, sind sich TypeScript und der Host nicht einig darüber, was gültig ist.

Hoffentlich ist die Unterstützung nativer Module jetzt ausreichend, damit TypeScript eine weitere Auflösungseinstellung hinzufügen kann.

@leontepe Du brauchst keinen Bundler/Loader. Sie können entweder https://github.com/Zoltu/typescript-transformer-append-js-extension/ (meine bevorzugte Lösung) verwenden oder Sie können .js an alle Ihre Importanweisungen anhängen (Vorsicht: dies wird lassen Sie Ihren Code in ts-node fehlschlagen).

@leontepe Du brauchst keinen Bundler/Loader. Sie können entweder https://github.com/Zoltu/typescript-transformer-append-js-extension/ (meine bevorzugte Lösung) verwenden oder Sie können .js an alle Ihre Importanweisungen anhängen (Vorsicht: dies wird lassen Sie Ihren Code in ts-node fehlschlagen).

@MicahZoltu Nun, danke, aber immer noch etwas frustrierend, dass es nicht einfach "out of the box" funktioniert. Wie @phaux sagte, schlägt VSCode seinen Benutzern vor, Importanweisungen ohne die Erweiterung zu machen, und das funktioniert zur Laufzeit einfach nicht. Ich bezweifle ernsthaft die Kompetenz des TypeScript-Teams hier oder ich habe die ganze Zeit etwas falsch gemacht und bin einfach nur dumm. Aber wer weiß...

Bearbeiten: Erwägen Sie ernsthaft, TypeScript für JavaScript + Babel an dieser Stelle einfach fallen zu lassen.

Ich habe keine Electron-Anwendung geschrieben, aber gibt es eine Möglichkeit, eine Auflösung im Node-Stil durchzuführen, bei der es einen Algorithmus gibt, um zu versuchen, Importe aufzulösen, der mehrere Dinge in einer festen Reihenfolge versucht? Scheint so, als ob es in Ordnung sein sollte, da alle Quellen aus lokalen Ressourcen geladen werden ...

Vielleicht ist es an der Zeit, TS um eine neue Modulauflösung zu erweitern? Node.js haben jetzt native ESM-Unterstützung, aber ohne explizite Erweiterungen in relativen Pfaden wird die Verwendung des --experimental-specifier-resolution=node -Flags erzwungen, was irgendwie ärgerlich ist. Es gibt auch Deno und Browser. Idealerweise sollte es so etwas geben:
tsconfig.json:

{
    "compilerOptions": {
        "moduleResolution": "explicit",
        "strict": true
    }
}

dann Typoskript:

import foo from './foo.ts'; // no ts(2691) here

kompiliert zu Javascript:

import foo from './foo.js';

„streng“: wahr bedeutet viel Arbeit!
2020, immer noch nicht behoben, lächerlich.

Ich melde mich nur, um zu sagen, dass dieses Problem auch unser Team blockiert 😢

Wir würden wirklich gerne eine einzige Quelle haben, die zu nativen Modulen aufbaut und auch in Knoten und mit Webpack konsumierbar ist. Webpack scheint ein Problem zu haben, wenn Sie .js manuell in Ihre Importe in Ihrem TS-Code einfügen. Sie können Webpack jedoch irgendwie zum Laufen bringen, wenn Sie die Dateierweiterung .ts in Ihre Importe einfügen, aber natürlich beschwert sich Typoskript. Das Fehlen einer Dateierweiterung führt dazu, dass keine nativen Module vorhanden sind. Also scheint keine Kombination den Browser und die Bundler zufrieden zu stellen. Wenn wir .ts in unsere Importe schreiben könnten und daraus .js in der Ausgabe werden könnten, wäre das Problem meiner Meinung nach gelöst (und Sie würden auch deno compat erhalten). Etwas wie @ evg656e schlägt vor, dass es funktionieren sollte.

@EisenbergEffect Gibt es dafür einen Fehler, der gegen WebPack eingereicht wurde? Klingt wirklich nach einem WebPack-Problem, das vom normalen tsc abweicht.

@justinfagnani Ich bin mir nicht sicher, ob das Problem in Webpak, ts-loader oder anderswo liegt. Ich habe viel Zeit damit verbracht, mein optimales Build-Setup einzurichten, und bin auf keine Lösung gestoßen, die alle Kästchen aktiviert hat. Es gibt wahrscheinlich Möglichkeiten , dies mit benutzerdefinierten Transformatoren oder Post-Build-Schritten zu tun, aber ich zögere, nicht standardmäßige Setups zu übernehmen, da dies negative Auswirkungen auf nachgeschaltete Entwickler haben kann.

@EisenbergEffect Wenn Sie mit dem TypeScript-Loader von WebPack keine TypeScript-Dateien über eine .js -Erweiterung importieren können, wie dies tsc der Fall ist, handelt es sich um einen Fehler. Wie Sie sagten, verhindert das Verhalten, dass derselbe Quell-Build mit WebPack und tsc erstellt wird.

Vielleicht ist es an der Zeit, TS um eine neue Modulauflösung zu erweitern? Node.js haben jetzt native ESM-Unterstützung, aber ohne explizite Erweiterungen in relativen Pfaden wird die Verwendung des --experimental-specifier-resolution=node -Flags erzwungen, was irgendwie ärgerlich ist. Es gibt auch Deno und Browser. Idealerweise sollte es so etwas geben:
tsconfig.json:

{
    "compilerOptions": {
        "moduleResolution": "explicit",
        "strict": true
    }
}

dann Typoskript:

import foo from './foo.ts'; // no ts(2691) here

kompiliert zu Javascript:

import foo from './foo.js';

Leute (zum Beispiel ich) würden es lieben, wenn ein Stück Code gleichzeitig zwischen Node.js, Deno und dem Web funktioniert. Ich denke, das wäre ein großer Meilenstein für die TypeScript/JavaScript-Programmierung.

Wenn Sie vscode verwenden und eine Zwischenlösung benötigen, scheint das Hinzufügen zu settings.json die Probleme zu beheben:

"typescript.preferences.importModuleSpecifierEnding": "js"

Es wird .js an Ihre Importpfade anhängen (wodurch die *.ts -Dateien in src ohne Fehler aufgelöst werden, aber die .js beim Transpilieren beibehalten werden). Dies ist nützlich, wenn Sie tsc ohne Bundler verwenden.

Während wir auf eine tsc-Lösung warten, gibt es eine Low-Tech-Lösung dafür

  1. Kopieren Sie alle Quelldateien in einen temporären Ordner
  2. Entfernen Sie die Erweiterung für Importe und Exporte vor dem Build

Ich wollte diesen Einzeiler teilen, falls andere ihn verwenden können. Es kopiert den Ordner src/ nach tmp/ und ändert die Dateien dort.

npx shx cp -r ./src/ ./tmp/ && npx rexreplace "(^§s*?(?:import|export).*?from§s+?(['\"]).*?)§.ts§2" €1€2 './tmp/**/*.{ts,js,tsx,jsx}'

Als Teil eines Build-Skripts in package.json (nach einem yarn add --dev shx rexreplace ) könnte es so aussehen

"scripts":{
  "build": "yarn build-esm && yarn build-tsc",
  "buil-esm": "...Whatever you normally do...",
  "build-tsc": "shx mkdir -p tmp && shx cp -r ./src/* ./tmp && rexreplace \"(^§s*?(?:import|export).*?from§s+?(['\\\"]).*?)§.ts§2\" €1€2 './tmp/**/*.{ts,js,tsx,jsx}' && tsc src/index.ts && shx rm -r ./tmp"
}

Ich halte derzeit .js von den Importpfaden in TypeScript-Quellen fern, um Jest bei Laune zu halten.
Dann habe ich einen Nachbearbeitungsschritt, um .js hinzuzufügen.
Quellzuordnungen werden bei dieser Methode nicht unterstützt.

tsc -b tsconfig-solution.json -w --listEmittedFiles \
  | node mk/build-post.js

Das Nachbearbeitungsskript build-post.js führt Folgendes aus.

Hängen Sie .js an import und export der relativen Pfade an

Zum Beispiel,

export { X } from "./first";
import { Y } from "./second";

wird

export { X } from "./first.js";
import { Y } from "./second.js";

Beachten Sie, dass ich nirgendwo index.ts verwende, sondern stattdessen mod.ts gemäß der Deno-Konvention verwende. Daher muss ich den Fall des Anhängens von /index.js nicht berücksichtigen.

Ändern Sie import in require für CommonJS-Pakete

Mein Code wird auf den Knoten ^12.17 und ^14.1 im Modulmodus ausgeführt. Ich veröffentliche nur ES-Module.
Viele Abhängigkeiten haben jedoch immer noch CommonJS in ihrem Feld "main" .
Daher sollte ich diese in CommonJS ändern, mit Ausnahme der integrierten NodeJS-Module.

Zum Beispiel,

import { Server as WsServer } from "ws";

wird

import { createRequire } from "module";
const require = createRequire(import.meta.url);
const { __importDefault } = require("tslib");

const { Server: WsServer } = require("ws");

Aber dann ist webpack mit diesen require s unzufrieden, also muss ich verwenden:

/// #if false
import { createRequire } from "module";
const require = createRequire(import.meta.url);
const { __importDefault } = require("tslib");
/// #endif

/// #if false
const { Server: WsServer } = require("ws");
/*
/// #else
import { Server as WsServer } from "ws";
/// #endif
/// #if false
*/
/// #endif

In Webpack muss jedes Paket, das mein Projekt importiert, ifdef-loader verwenden, und dann würde Webpack die ursprüngliche Zeile import sehen.

Wir sind auch davon betroffen und ich kann nicht verstehen, wie dies 3 Jahre nach der Meldung nicht behoben wird.
Wir verwenden WebStorm, daher funktioniert die VSCode-spezifische Einstellung nicht.
Die Verwendung eines separaten Skripts zum Korrigieren der Ausgabe ist lächerlich.
Dies sollte funktionieren, ohne dass Tools von Drittanbietern verwendet werden müssen.

+1

Dies ist meine Problemumgehung mit einer asp.net Core 3.1-Website (funktioniert wahrscheinlich auf niedrigeren Versionen)
In der startup.cs:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            var rewriteOptions = new RewriteOptions();
            rewriteOptions.AddRewrite(@"^js/(.+)", "js/$1.js", skipRemainingRules: true);

            app.UseRewriter(rewriteOptions);

            app.UseStaticFiles();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }

Die Rewriting-Middleware fügt die Erweiterung ".js" zu jeder Anfrage hinzu, die auf den Ordner /js abzielt.
Warnung: Die Reihenfolge der Middleware ist hier wichtig, die UseStaticFiles müssen nach dem UseRewriter platziert werden, sonst funktioniert es nicht.

Wie alle hier würde ich eine Out-of-the-Box-Lösung bevorzugen, aber bis dahin...

Vielleicht ist es an der Zeit, TS um eine neue Modulauflösung zu erweitern? Node.js haben jetzt native ESM-Unterstützung, aber ohne explizite Erweiterungen in relativen Pfaden wird die Verwendung des --experimental-specifier-resolution=node -Flags erzwungen, was irgendwie ärgerlich ist. Es gibt auch Deno und Browser. Idealerweise sollte es so etwas geben:
tsconfig.json:

{
    "compilerOptions": {
        "moduleResolution": "explicit",
        "strict": true
    }
}

dann Typoskript:

import foo from './foo.ts'; // no ts(2691) here

kompiliert zu Javascript:

import foo from './foo.js';

Ich habe die node/file-extension-in-import -Regel in eslint-plugin-node zur Linting-Konfiguration mit der Idee eingerichtet, die Erweiterung manuell hinzuzufügen, um Anweisungen zu importieren (da es so besser ist) und die "moduleResolution": "node" in TypeScript config und alles, was ich sehen kann, ist ts(2691) .

Hoffentlich lohnt es sich, das, was @ evg656e gesagt hat, umzusetzen.

Ich kann nicht glauben, dass dies immer noch ein Problem ist.

wenn Sie verwenden
"baseUrl": ".", "paths": { "/*": ["./*"] },

Sie können einen absoluten Modulimport wie folgt durchführen:
`importiere ws aus "/hey/connection";

aber beim Hinzufügen der Erweiterung ".js" findet der Compiler plötzlich nicht mehr die Deklaration connection.ts und sagt:

Could not find a declaration file for module '/hey/connection'. '/home/tobi/Documents/JITcom/Code/Libs/Test_Browser/hey/connection.js' implicitly has an 'any' type.

Mit einem relativen Pfad funktioniert alles einwandfrei.

Bitte beheben Sie dies

Ich möchte auch eine Lösung dafür.

Danke.

Es ist lächerlich, dass dies immer noch ein Problem ist! :00

Ich habe mich endlich entschieden, auf TypeScript umzusteigen, und dies war eines der ersten Probleme, auf die ich gestoßen bin. Es unterbricht die Modulauflösung in der nativen Implementierung von Node, und ich konnte es nur umgehen, indem ich entweder das esm-Paket verwendet habe, das beim Akzeptieren von Namen ohne Erweiterungen flexibler zu sein scheint, oder (seltsamerweise) .js-Erweiterungen in den Importpfaden verwendet habe in meinen .ts-Dateien, auch wenn der Import auf eine .ts- oder .tsx-Datei verweist. Ich bin mir nicht sicher, warum der TypeScript-Compiler das akzeptiert, aber zumindest enthält die Build-Ausgabe dann die Erweiterung .js. Schrecklich hackige Lösung.

Ich verwende heutzutage auf der Clientseite nicht einmal Typoskript, hat meine Codequalität nicht zu sehr beeinträchtigt und die Dinge viel einfacher gemacht. Wahrscheinlich wird JavaScript optionale Typen von einem Punkt haben und dieses Problem spielt keine Rolle mehr.

Ich lasse die Erweiterung bei Importzeilen weg, um Jest und Webpack glücklich zu machen.
Beim Kompilieren rufe ich tsc --listEmittedFiles und leite die Ausgabe an ein Nachbearbeitungsskript weiter. Dieses Skript fügt die Erweiterungen .js hinzu, um Node (im Modulmodus) glücklich zu machen.
https://github.com/yoursunny/NDNts/blob/fa6b2eb68a9f32a6a2e24e5475275f803236b8f8/mk/build-post.js

@kj

(komischerweise) die Verwendung von .js-Erweiterungen in den Importpfaden in meinen .ts-Dateien, selbst wenn der Import auf eine .ts- oder .tsx-Datei verweist. Ich bin mir nicht sicher, warum der TypeScript-Compiler das akzeptiert, aber zumindest enthält die Build-Ausgabe dann die Erweiterung .js. Schrecklich hackige Lösung.

Es ist nicht seltsam und definitiv nicht hacky und funktioniert perfekt mit der Browser- und Node-nativen Modulauflösung.

Die Ressource, die Sie importieren, _ist_ die .js-Datei. Der Typ kann sich entweder in einer .ts-Datei oder in einer .d.ts-Datei befinden. Eine .d.ts-Datei muss nicht einmal dem .js-Modul gleichgeordnet sein, und es muss keine 1-zu-1-Beziehung zwischen .d.ts-Dateien und .js-Dateien bestehen.

Das Importieren des .js-Moduls ist die zuverlässigste und stabilste Option, die tsc hätte wählen können. Andernfalls würde es Fälle geben, in denen Sie die Typen importieren und tsc nicht den richtigen Weg kennt, um sie in einen tatsächlichen Modulpfad umzuschreiben.

@justinfagnani Ah, ich denke, das macht Sinn. Ich wollte nicht andeuten, dass irgendetwas, was TypeScript hier tat, hacky war (ich bin nicht in der Position, eine solche Behauptung aufzustellen), nur dass ich das Gefühl hatte, dass das, was ich tat, möglicherweise nicht typisch war. Da habe ich aber wohl falsch gedacht. Es ist nicht TypeScript, das das Modul importiert, sondern was auch immer die Build-Ausgabe auswertet (oder verstehe ich das falsch)? In diesem Fall kann ich verstehen, warum es so funktionieren würde.

Die Ressource, die Sie importieren, _ist_ die .js-Datei

Sie beziehen sich hier auf das eingebaute Modul, oder? Keine .js-Datei im Quellverzeichnis, sondern die gebaute Version des .ts-Moduls?

Könnte es nicht sein, dass, wenn Sie explizit die Erweiterung .ts oder .tsx in einem Modulpfad angeben, die Ausgabe .js ersetzt?

Ich denke, es könnte ein Missverständnis darüber geben, was los ist @kj. Wenn Sie eine .ts-Erweiterung angeben, ohne Ihren Code kompiliert zu haben, verweist sie auf die ts-Datei. Wenn Sie jedoch mit tsc kompilieren, wird der Inhalt der ts-Datei in eine js-Datei konvertiert, die in der Umgebung, in der Sie sich befinden (Knoten oder Browser), ausführbar ist.

Ich verstehe das @mkay581 , aber sagen wir, ich habe diese Zeile in einer Datei foo.ts:

import { Component } from './Component.js';

Die 'Component.js', auf die ich mich beziehe, ist tatsächlich 'Component.tsx' im Dateisystem (es gibt keine .js-Datei, es sei denn, TypeScript versteht, dass sich dies auf die eventuell transpilierte Version der Datei bezieht?). TypeScript akzeptiert dies problemlos und die gleiche Importzeile ist dann in der Ausgabe vorhanden (mit der Erweiterung .js, die dann mit Node oder dem Browser funktioniert).

Der traditionelle TypeScript-Weg (AFAIK) wäre, diese Importzeile ohne die Erweiterung anzugeben, wie folgt:

import { Component } from './Component';

Das lässt sich offensichtlich auch gut kompilieren, außer dass die Importzeile in der transpilierten .js-Datei nicht die .js-Erweiterung auf „./Component“ enthält, die von bestimmten Umgebungen benötigt wird (und möglicherweise klingt es wie die Spezifikation, obwohl ich es getan habe) nicht lesen, um sicher zu sein).

Wenn ich dagegen die Zeile mit dem eigentlichen Dateinamen der Quelldatei angebe:

import { Component } from './Component.tsx';

Dann erkennt TypeScript den Pfad nicht und schlägt vor, dass ich die Importzeile ohne die Dateierweiterung versuchen sollte (wenn ich mich erinnere, bin ich gerade nicht an meinem Computer).

Das erste Beispiel fühlt sich für mich also etwas seltsam an, da ich TypeScript schreibe, von dem ich erwarten würde, dass es mit der Erweiterung .ts oder .tsx importieren kann, aber es akzeptiert nur den Pfad ohne Erweiterung (was anscheinend .tsx ist). im Widerspruch zu anderen Implementierungen des ES-Modulsystems) oder mit der Erweiterung .js, die sich nur auf die Ausgabedatei beziehen konnte, da ich keine solche Quelldatei habe.

@justinfagnani

Die Ressource, die Sie importieren, _ist_ die .js-Datei.

Ich weiß nicht, wie tsc funktioniert, aber das klingt für mich nicht richtig. Wenn Sie Ihren Code schreiben, gibt es noch keine .js-Datei. Es ist die Aufgabe des Compilers, es zu erstellen.

TS fungiert als Abstraktionsschicht über JS, und die .js-Dateien sind die Ausgabe des Kompilierungsschritts. Sich darauf zu verlassen, dass sie mit dieser spezifischen Erweiterung da sind, scheint die Abstraktion zu brechen, IMO.

Anders ausgedrückt: Wenn Sie C oder C++ verwenden, verwenden Sie nicht #include die .o -Dateien in Ihrem Code, sondern fügen die .h oder höchstens .c ein .cpp .

Ich bin bereit, eine vernünftige Erklärung für dieses Verhalten in Typescript zu akzeptieren, aber wenn mir nichts fehlt, scheint es das nicht zu sein.

@kj

Es ist nicht seltsam und definitiv nicht hacky

Schwer zu widersprechen. Für mich ist es die Definition von seltsam und hacky. 😛 Sie referenzieren hier eine hypothetische Datei. Eine Datei, deren Existenz nicht garantiert ist. (zB beim Bündeln von Code, mit AssemblyScript oder deno) Sie nehmen das Ausgabeformat an. Aber beim Schreiben von agnostischem Code (z. B. Module von Drittanbietern) ist es eine _gefährliche_ Sache anzunehmen.

@borfast @frzi Ja, im Grunde habe ich mich dabei gefühlt, und ich bin froh zu sehen, dass ich nicht der einzige bin, der sich damit nicht wohl fühlt. Ich versuche nur, nicht zu viele Annahmen zu treffen, da ich so neu bei TypeScript bin!

@frzi

Was Sie hier tun, ist eine hypothetische Datei zu referenzieren. Eine Datei, deren Existenz nicht garantiert ist

Nicht hypothetisch, tsc weiß, dass es es generieren wird. Es ist garantiert vorhanden, wenn man tsc verwendet.

Eine andere Sichtweise ist, dass Sie beim Importieren der .ts-Datei eine Datei importieren, die nach der Kompilierung nicht mehr vorhanden ist.

beim Bündelcode

Bundler laufen nach tsc

@kj hat .tsx-Dateien erwähnt, und sie bringen meinen Punkt noch mehr nach Hause. .tsx existiert nur, um dem Compiler dieses Moduls _lokal_ zu signalisieren, dass das Modul JSX enthält. Importeure des Moduls müssen nicht wissen, dass JSX in der Datei enthalten war, und sie können es nach der Kompilierung nicht feststellen. Dateien können nahtlos zwischen .tsx-, .ts- und .js/.d.ts-Paaren portiert werden.

Angenommen, Sie importieren eine .ts-Datei:

import {Component} from './component.ts';

Und Sie möchten dann JSX für die Komponente verwenden, also benennen Sie sie in „component.tsx“ um. Sollten alle Importe fehlschlagen? Angenommen, Sie migrieren von .ts zu .js/.d.ts, sollten die Importe erneut fehlschlagen?

@borfast

TS fungiert als Abstraktionsschicht über JS, und die .js-Dateien sind die Ausgabe des Kompilierungsschritts. Sich darauf zu verlassen, dass sie mit dieser spezifischen Erweiterung da sind, scheint die Abstraktion zu brechen, IMO.

Die Abstraktion ist nicht so vollständig, wie Sie hier andeuten. Sie können .js-Dateien von innerhalb oder außerhalb Ihres TS-Projekts importieren. Sie können Typen zu einer .js-Datei mit einer .d.ts-Datei hinzufügen, die sich an einer beliebigen Stelle in Ihrem Projekt befindet. Die .js-Dateien sind nach der Kompilierung real. Alles andere hilft nur dem Compiler.

@justinfagnani Ich verliere mich ein wenig mit dem, was Sie sagen, aber warum kann TypeScript nicht einfach davon ausgehen, dass es eine .js-Datei für dieses Modul und generiert, wenn Sie ihm einen Importpfad mit .ts oder .tsx geben sollte daher die letztere Erweiterung in der Ausgabe ersetzt werden?

@justinfagnani

Nicht hypothetisch, tsc _weiß_, dass es es erzeugen wird. Es ist garantiert vorhanden, wenn man tsc verwendet.

Aber hier ist eine Symmetrie impliziert, die Sie nicht zugeben.

Diese von Ihnen erwähnte „Garantie“ gilt in beide Richtungen. Wenn, wie Sie sagen, „tsc _weiß_, dass es [js-Dateien] generiert“, dann ist es eine ebenso gültige Frage zu stellen: „Nun, warum handelt tsc dann NICHT auf diese Garantie und wendet die .js-Erweiterungen an, die es _kennt_ fehlt im kompilierten js?“

Die Interpretation der Tatsache, dass „tsc js-Dateien garantiert“, geht in beide Richtungen.

Also stimme ich zu, @justinfagnani , deine Interpretation _ist_ gültig, von einem bestimmten Standpunkt aus. Aber die entgegengesetzte Interpretation ist, dass „tsc daher _nach seinem Wissen handeln_ und diesen Prozess für den Entwickler durchführen sollte“. Und was mich an dieser ganzen Debatte von Anfang an stört, ist, wie _negativ_ diese Interpretation aufgenommen wird, fast bis zur Lächerlichkeit. Es ist unvernünftig.

Letztlich geht es in dieser Debatte um _eine ästhetische Entscheidung, nicht um eine logische_. Und meine Hoffnung ist, dass ein unterstützender und entgegenkommender Tonfall – wie es einer ästhetischen _Meinung_ (nicht einer logischen Deduktion) eigen ist – von ihren Kritikern zu diesem Thema vorgebracht wird.

Kurz gesagt, geben Sie bitte zu, dass die Frage des OP eine absolut gültige Interpretation ist - vielleicht zusammen mit Ihrer eigenen. Keine Notwendigkeit für scharfe Debatten.

Danke

@justinfagnani

Eine andere Sichtweise ist, dass Sie beim Importieren der .ts-Datei eine Datei importieren, die nach der Kompilierung nicht mehr vorhanden ist.

Natürlich nicht, genauso wie eine .h -Datei nicht mit der ausführbaren Datei eines C-Programms verteilt wird. Genau das ist der Punkt: Sie weisen einen Compiler an, Quelldateien einzuschließen, keine kompilierten Dateien.

Ok, ich bekomme zu viel Spam mit dieser Konversation, um sie weiter zu ignorieren.
Die import -Anweisung ist NICHT Teil des Typoskripts, sondern Teil der JavaScript-Umgebung, die sie ausgeführt hat. Nun, das Schlüsselwort hier ist JavaScript- Umgebung, da DIES die Pfade auflöst. Zeigen Sie mir eine einzelne App, die zur Laufzeit .ts-Dateien importiert und ausführt (sicher, es mag einige geben, aber sie sind das, was ich als hacky bezeichnen würde).
TypeScript ermöglicht das Hinzufügen .js -Erweiterungen, da es natives JavaScript in seinen Quelldateien zulässt. Keiner der Browser von node.js führt .ts-Dateien aus, selbst ts-node transpiliert .ts-Dateien im laufenden Betrieb, behält das Ergebnis nur im Speicher, anstatt sie auf die Festplatte zu schreiben (überhaupt nicht hacky, richtig ?).

Nun wäre der richtige tsc-Fix:

  • wir haben .ts Datei
  • Wir referenzieren es in einer anderen Datei
  • tsc transpiliert diese .ts -Datei in .js -Datei
  • tsc schreibt dann alle direkten Verweise auf die .ts -Datei mit der .js -Datei um (es weiß genau, wie es transpiliert wurde, und kann es daher korrekt aktualisieren).

Problem: „moderner Webentwickler“ ist kein echter Webentwickler und verwendet node.js Importmethode, wobei die Erweiterung (und der gesamte Dateipfad) übersprungen wird. tsc weiß jetzt nicht mehr, was die Ausgabe sein wird, da das Importieren my-awesome-module/test alles sein kann, angefangen von einer Datei test.js in node-modules/my-awesome-module bis hin zu einer Datei $ index.js im Ordner test in node-modules/my-awesome-module , endet bei einigen lokalen Umschreibungen mit Nicht-js-Dateien wie ./local-mocks/my-awesome-module/mock.json .

Hier entsteht das Problem: Wie kann ein TSC wissen, was die funky Webpack/Rollup/super-awesome-new-and-shiny-bundler-Konfiguration für Ihr spezielles Projekt ist?

Nochmals: Ich bin dafür, dass tsc Importpfade umschreibt, aber es würde nur für einfache Projekte funktionieren, und es nur für einfache Projekte funktionieren zu lassen (was heutzutage eine Minderheit ist, da selbst einfache Präsentationsseiten mit einer überentwickelten Webpack-Konfiguration reagieren) ist es nicht wert Zeit zu verbringen, wenn dies mit einem einfachen, benutzerdefinierten Skript möglich ist.

Nochmals: Ich bin dafür, dass tsc Importpfade umschreibt, aber es würde nur für einfache Projekte funktionieren, und es nur für einfache Projekte funktionieren zu lassen (was heutzutage eine Minderheit ist, da selbst einfache Präsentationsseiten mit einer überentwickelten Webpack-Konfiguration reagieren) ist es nicht wert Zeit zu verbringen, wenn dies mit einem einfachen, benutzerdefinierten Skript möglich ist.

Wie würden Sie es in einem einfachen Projekt ohne Webpack machen, nur mit tsc, meine ich?

Ich lese die Kommentare aller und es scheint eine grundlegende Meinungsverschiedenheit über die Erwartungen an die Verwendung von Typoskripten hier zu geben.

Wenn .ts-Quelldateien auf .js-Dateien verweisen, hat das Problem bereits begonnen.

Typoskript wurde entwickelt, um .ts-Quelldateien ~auszuführen~ zu kompilieren -- nicht .js-Dateien. Wenn ein Entwickler TypeScript für sein Projekt verwenden möchte, sollte er sein _gesamtes_ Projekt in TypeScript konvertieren und keine verwaisten .js-Dateien hinterlassen und versuchen, auf sie zu verweisen. Und wenn Sie nicht die Zeit haben, den Inhalt in js-Dateien in Typescript-Syntax zu ändern, benennen Sie die js-Dateien einfach in ts-Dateien um (oder verwenden Sie die Pfadzuordnung von TS, um Importe auf .js-Dateien abzubilden). Problem gelöst. :mann_achselzuckend:

BEARBEITEN: "Ausführen" in "Kompilieren" korrigiert, was ich meinte, aber ich kann sehen, wie das möglicherweise anders interpretiert wurde.

@ mkay581 TypeScript sollte nie etwas ausführen, sondern nur JS-Dateien ausgeben.

@valeriob Einfaches Projekt hätte wahrscheinlich höchstens wenige Dateien, die nicht gebündelt werden müssen. Heutzutage haben Browser Importe eingebaut, darum müssen Sie nicht herumkommen. Dann wäre es so einfach, Navigationsereignisse im Browser abzuhören, dann jedes Ereignis der passenden Route zuzuordnen, jede Route könnte Daten mit fetch importieren und nach der Rückgabe mit nicht kompilierten Templating-Engines (lit- html, HyperHTML oder ältere wie Schnurrbart, Lenker, Mops usw.). Fertig, keine Lust auf Webpack, Framework oder irgendwelche Utility-Bibliotheken, nur noch Listener, Regexp, Fetch, Promises und eine einfache JS-Template-Engine.

Danke @Draccoz , kannst du mir dann sagen, wie man dieses einfache Szenario zum Laufen bringt? https://github.com/valeriob/Typescript_Non_SPA
Es ist eine einfache .ts-Datei, die auf eine JS-Bibliothek verweist (rxjs als Beispiel), und ich möchte sie als Modul in einer HTML-Seite verwenden.

@valeriob Das ist nicht so trivial, wie es sein sollte. Die meisten Bibliotheken von Drittanbietern, selbst wenn sie erklären, dass sie mit ES-Modulen kompatibel sind, sind sie nicht in der Welt der Browser.
RxJS war etwas, an dem ich am meisten interessiert war, als ich es in den nativen Flow brachte, aber sie warten, bis dieses Ticket gelöst ist, bevor sie sich entscheiden, es selbst zu implementieren (komisch ...).
In der von mir entworfenen Architektur habe ich zunächst sed verwendet, um alle Importe zu reparieren, habe dann aber meine Meinung geändert und einen einfachen Entwicklungsserver mit Pfadumschreibung verwendet. Mein Konzept ist es, abgesehen von rxjs, Typescript und lit-html (node_modules mit 4 Ordnern und ULTRA-schnellen CI-Tests/Builds) keine externen Abhängigkeiten in meinen Apps zu haben. Wenn TS Pfade neu schreiben würde, würde es die Notwendigkeit für meinen Server beseitigen, obwohl es sowieso ungefähr 90 Codezeilen sind. Es ist Open Source, wenn jemand einen Link haben möchte, fragt einfach oder überprüft Organisationen in meinem Profil.

Bei einfachen Seiten bezog ich mich auf diejenigen, die keine Bibliothek benötigen, wie z. B. das Drücken einer URL -> Abrufen von Daten -> Anzeigen -> Wiederholen.

Keine Bibliothek in Js verwenden zu müssen, ist reine Fantasie, da Js keine Basisbibliothek hat.

Das einfache Szenario ist das, das ich verlinkt habe, und es funktioniert nicht. Es ist auch das häufigste Szenario für Leute, die nicht in die verrückte Webpack-/Kompilierungswelt eintauchen wollen, die Dinge ohne wirklichen Nutzen kompliziert, Ihre Optionen sehr einschränkt, Entwickler dazu bringt, mehr gegen die Tools zu kämpfen, als Ihre App zu schreiben, und Ihren Entwickler verlangsamt Schleife.

Viele mentale Gymnastik wird hier betrieben, um zu leugnen, dass dieses Problem existiert und dass es ein wichtiges Anliegen für die Produktivität vieler Entwickler ist.

Zu erklären, dass es _kein Problem sein sollte_, _löst das Problem nicht_. Software sollte den mentalen Modellen der Benutzer entsprechen und den Benutzern nicht ihr eigenes Implementierungsmodell aufzwingen. (UX-Zeug)

Wenn Benutzer tsc gemäß @borfast als C-ähnlichen Compiler konzipieren, dann ist dies der privilegierte mentale Modus, der trotz der Implementierungsdetails von tsc berücksichtigt werden muss.

Die Frage des OP hat mehr als 200 Daumen nach oben, mehr als alle anderen Probleme im Repo.

Dieses Problem verdient eine Community-Abstimmung. Bitte erwägen Sie, eine Umfrage zu starten.

Wenn die meisten Benutzer möchten, dass tsc ihre Importe umschreibt, ist dies die richtige Antwort. So sieht zumindest die UX-Sichtweise aus.

Es ist sogar noch einfacher, wenn Typoskript als Sprache eine Obermenge von JavaScript ist, sollte die Ausgabe von tsc (sogar der Schalter für nicht einzelne Ausgabedateien) von JavaScript selbst verdaulich sein.

@weoreference , wenn Sie klar definieren (keinen Code schreiben, nur entwerfen), wie GENAU Pfade umgeschrieben werden sollen, unter Berücksichtigung mehrerer Umgebungen (node.js, Browser), mehrerer Bundler-Konfigurationsmöglichkeiten (Untersuchung aller aktuellen, geplanten und möglichen zukünftigen Funktionen von Webpack, Rollup und Paket und alle anderen Bundler) dann sicher, dann wäre das TypeScript-Team meiner Meinung nach voll auf Ihrer Seite.

Wenn Sie dazu nicht bereit sind oder denken, dass es zu schwierig ist, hören Sie auf, sie zu bitten, ein Feature zu erstellen, das niemand wirklich beschreiben kann, es ist wie "Ist mir egal wie, aber bringen Sie diese Kuh zum Fliegen" ...

@Draccoz , Sie möchten, dass Ihr Auto die Gänge wechselt, damit Sie es schneller als 10 km / h fahren können, aber ich bin sicher, dass Sie vom Hersteller nie gebeten wurden, zu erfahren, wie ein Getriebezug funktioniert, geschweige denn einen zu entwerfen.

Was das Thema Bundler und so weiter betrifft, warum ist das ein Blocker dafür?

Sehen Sie, ich möchte nur ES-Module verwenden, ich möchte mich nicht mit dem ganzen Babel- und Webpack-Wahnsinn herumschlagen. Warum kann dies keine optionale Compiler-Option sein, die einfach die Dateierweiterung in .js ändert? Wenn dieses Verhalten mit anderen vom Benutzer festgelegten Konfigurationsoptionen kollidiert, sollte es automatisch deaktiviert werden, oder es sollte eine Warnung/ein Fehler angezeigt und die Kompilierung gestoppt werden, wenn tsc ausgeführt wird, damit der Benutzer weiß, dass er die Konfiguration ändern muss.

Ich verstehe wirklich nicht, warum das unmöglich ist.

@Draccoz Hallo :) Nun, wie ich es sehe, fragst du zwei Dinge:

  1. Wie es umgesetzt werden kann

  2. Wie ich als Entwickler tsc signalisieren kann, dass die Importe für meine spezielle Umgebung auf eine bestimmte Weise umbenannt werden sollen

Hier sind meine Gedanken.

  1. Bitte sehen Sie sich die Antwort von @borfast an; Es ist eine Antwort "höherer Ordnung", aber prägnant :)

  2. Vielleicht kann ich ein Flag an tsc/tsconfig übergeben, z. B. „renameImports“:true, oder ein anderes Signal, das von tsc abgeholt wird. Wenn mehr Präzision benötigt wird, sollte das Flag vielleicht nicht boolesch sein, sondern eine Zeichenfolge nehmen, vielleicht so etwas wie diese:

standardImportExtension: 'js'

daher sind alle Importe ohne Dateierweiterungen standardmäßig .js

Fazit:
Diese Funktionalität scheint nur schwer zu implementieren, da Sie davon ausgehen, dass Q2 (Import-Umbenennungsschema) Q1 (dh tsc) im Voraus bekannt sein muss. Aber eigentlich nein. Ich, der menschliche Entwickler, kann dieses „Weltwissen“ leicht an tsc liefern, ohne dass es wissen muss, wie Webpack/Browser/etc funktionieren. All dies mit einer einfachen Flagge.

@borfast Transmission wurde nicht von einem Benutzer gefragt, es wurde von einem Hersteller mit einem Auto ausgestattet, der Benutzer stimmte nur zu, dass es sich um eine neue Funktion handelt, und begann mit der Verwendung - Entschuldigung, das ist kein richtiges Argument. Im Vergleich zu Ihrem Beispiel als Benutzer - Autohersteller ist es eher so: "Ich möchte, dass mein Auto ein vollwertiges Elektroauto mit einer Reichweite von 100.000 Meilen und einer Höchstgeschwindigkeit ist, die die Geschwindigkeit eines Jets erreicht. Es ist mir egal, wie ich es erreichen soll, ich will es und das ist es - Punkt.
@weoreference etwas Missverständnis in meinen Fragen. Ich habe gefragt: Wie kann man tsc verstehen lassen, worauf der Pfad zeigt? Ist es direkt eine js-Datei? Oder ist es ein Ordner mit index.ts darin? Oder ist es ein Modul mit package.json, das das Feld main enthält? Oder esnächstes Feld? Oder irgendetwas anderes, das kein Standard ist? Oder ist es ein Pfad, der von Webpack umgeschrieben wird? Oder aufrollen? Wenn ja, wo ist die Konfig? Ist es vielleicht ein anderer Bundler? Einige weniger bekannt? Und was sind die anderen Anwendungsfälle, an die ich im obigen Satz nicht gedacht habe?

Vielleicht kann ich ein Flag an tsc/tsconfig übergeben, z. B. „renameImports“:true, oder ein anderes Signal, das von tsc abgeholt wird.

@weoreference können Sie dies nicht bereits mit Pfadzuordnung tun? Die Option paths in der TSconfig-Datei gibt uns die Kontrolle, die Importpfade JS-Dateien zuzuordnen. Sorry, wenn ich falsch interpretiere.

@Draccoz Vielen Dank für Ihre Antwort, bitte lassen Sie mich das klären

Und was sind die anderen Anwendungsfälle, an die ich im obigen Satz nicht gedacht habe?

Oh ja, es wäre sehr schwierig für tsc, Kenntnisse über all diese Umgebungs-/Build-Tool-Kombinationen zu haben.

Aber tsc könnte ein einfaches Dienstprogramm haben, das Entwicklern hilft, _die meisten_ Anwendungsfälle abzudecken, und das ist der Konfigurationswert „standardImportExtension“, den ich erklärt habe.

Hier kommt natürlich das Problem der „Garantie“. An früherer Stelle in diesem Thread wurde argumentiert, dass tsc „garantieren“ sollte, dass das kompilierte js tatsächlich [in einer Umgebung] ausgeführt wird.

Nun... vielleicht war das eine zu harte Verpflichtung. Es ist in der Tat sehr schwierig für tsc zu garantieren, dass js [in irgendeiner Umgebung] ausgeführt wird, da diese Umgebung, wie Sie gerade beschrieben haben, in der aktuellen js-Landschaft sehr schwer zu definieren ist.

Aber das von @borfast vorgeschlagene einfache Flag-Dienstprogramm löst _die meisten_ der js-Importfehler, auf die neue Benutzer stoßen, die tsc ausprobieren.

Fortgeschrittene Nutzung, die, wie Sie erwähnt haben, aus all diesen Überlegungen besteht —-

Ist es direkt eine js-Datei? Oder ist es ein Ordner mit index.ts darin? Oder ist es ein Modul mit package.json, das das Hauptfeld enthält? Oder esnächstes Feld? Oder irgendetwas anderes, das kein Standard ist? Oder ist es ein Pfad, der von Webpack umgeschrieben wird? Oder aufrollen? Wenn ja, wo ist die Konfig? Ist es vielleicht ein anderer Bundler?

– Nun, diese Verwendung kann tatsächlich benutzerdefinierten Benutzerskripten, Bundlern und anderen Tools überlassen werden.

Aber nur weil die fortgeschrittene Verwendung schwer zu lösen ist, heißt das nicht, dass wir es vermeiden sollten, die einfachen Fälle zu lösen.

Und der einfachste Fall ist das Hinzufügen einer .js-Erweiterung zu Importen; die wir lösen können und lösen sollten.

@weoreference , also werde ich von Ihnen abgelehnt, weil Sie eine Frage gestellt und versucht haben, hilfreich zu sein, und dann ignorieren Sie die Frage. Es scheint, als wollten Sie nur streiten und debattieren, anstatt tatsächlich zu einer produktiven Lösung zu gelangen. Sie haben jeden Versuch, dies zu tun, abgelehnt. Letzte Nachricht für mich in diesem Thread. Entschuldigung für all das Spammen, alle zusammen.

@weoreference schau ganz am Anfang dieses Gesprächs, bei den Kommentaren von @DanielRosenwasser . Er erklärt, warum sie es nicht umsetzen würden ("im Moment"? nutzloser Hoffnungsschimmer). Nach seiner Aussage hat niemand von Typescript das Thema weiter kommentiert. Für mich sollte diese Diskussion beendet werden und Microsoft sollte offiziell Stellung beziehen. Zeitraum.
Nur als Randbemerkung - ich persönlich bin für diese Funktion, würde VIEL vereinfachen. Ich habe meinen Hoffnungsgedanken verloren, da ich auch Typoskript-Teamargumente verstehe.

@weoreferenz

Nicht hypothetisch, tsc weiß, dass es es generieren wird. Es ist garantiert vorhanden, wenn man tsc verwendet.

Aber hier ist eine Symmetrie impliziert, die Sie nicht zugeben.

Diese von Ihnen erwähnte „Garantie“ gilt in beide Richtungen. Wenn, wie Sie sagen, „tsc weiß, dass es [js-Dateien] generieren wird“, dann ist es eine ebenso gültige Frage zu stellen: „Nun, warum handelt tsc dann NICHT auf diese Garantie und wendet die .js-Erweiterungen an, von denen es weiß, dass sie es sind fehlt im kompilierten js?“

Die Symmetrie gilt eigentlich nicht. Es ist nicht so einfach, nur eine .js-Erweiterung anzuwenden - tsc müsste den Bezeichner auflösen und neu schreiben, und die Auflösung kann von Typdeklarationen abhängen. TypeScript und Babel unterstützen Einzelmodul-Kompilierungsmodi (isolatedModules für tsc). Wenn Sie in diesem Fall Typen anstelle von JavaScript importieren, müsste tsc die Typdeklarationen laden, um zu bestimmen, wo sich die entsprechende .js-Datei befinden würde, um die .js-Datei neu zu schreiben Bezeichner. Um die Dinge konsistent zu halten und Randfälle zu vermeiden, ist es am einfachsten, nur den Import der .js-Dateien zu unterstützen, die vor der Kompilierung vorhanden sind oder ein bekanntes Ergebnis des aktuellen Projekts sind.

@justinfagnani @Draccoz Danke; ok, ja ich verstehe.

Mein abschließender Kommentar: "Nur weil harte Fälle nicht gelöst werden können, heißt das nicht, dass wir die einfachen Fälle nicht lösen können."

Danke

Ich bin davon ausgegangen, dass TypeScript hier gegen die Spezifikation verstößt (und ungültiges JavaScript erzeugt), aber ich kann nirgendwo in der Spezifikation finden, die tatsächlich erfordert, dass der Importpfad genau mit den Dateinamen (mit Erweiterung) übereinstimmt. Es ist sehr schwer zu verdauen, daher bin ich mir nicht ganz sicher, aber alles, was ich finden kann, ist, dass die Spezifikation erfordert, dass der „ModuleSpecifier“ in der „FromClause“ ein „StringLiteral“ ist. Scheint eine sehr lockere Definition zu sein, aber ich nehme an, dass dies der Fall sein könnte, um Flexibilität bei der Modulauflösung in den vielen verschiedenen Umgebungen zu ermöglichen, in denen ECMAScript existiert. Kann mir jemand bestätigen, ob ich das richtig lese? Wenn dies wirklich der Fall ist, müsste ich meine Haltung gegenüber der Art und Weise, wie TypeScript damit umgeht, mildern. Obwohl ich es immer noch vorziehen würde, dass es mehr Interoperabilität zwischen TypeScript, Node und dem Web gibt. Die aktuelle Situation ist nicht optimal.

Ich bin zu diesem Thema gekommen, nachdem ich dies gelesen habe. Dieses Problem erweckte bei mir den Eindruck, dass das System von Node aufgrund der ES-Spezifikation so funktioniert (streng übereinstimmende Dateinamen), aber ich kann jetzt sehen, dass ich das falsch gelesen habe (sie bezogen sich nicht auf die ES-Spezifikation), und vielleicht weder Node, noch TypeScript machen eigentlich nichts "falsch". Dann geht es in diesem Problem wirklich um Inkompatibilitäten zwischen gleichwertigen Ansätzen zur Modulauflösung zwischen verschiedenen Umgebungen. Dennoch sind die Hauptzielumgebungen von TypeScript eindeutig Node und das Web, und obwohl Node theoretisch ihren Ansatz ändern könnte, halte ich es nicht für sehr wahrscheinlich, dass Browser dies tun werden, daher denke ich, dass dieses Problem immer noch gültig ist.

Bearbeiten: Ich denke, es könnte dieser Abschnitt der Spezifikation sein, der anzugeben scheint, dass die Modulauflösung "hostdefiniert" ist?

@kj Der relevante Spezifikationstext befindet sich in der HTML-Spezifikation: https://html.spec.whatwg.org/multipage/webappapis.html#resolve -a-module-specifier

Es besagt, dass Importspezifizierer vollständige URLs oder absolute oder relative Pfade sein müssen. Wenn der Bezeichner nicht als URL analysiert wird (normalerweise beginnend mit http:// oder https:// ) oder mit / , ./ oder ../ beginnt

Es wird keine andere Pfadsuche oder Auflösung durchgeführt. Das bedeutet, dass der Bezeichner in die vollständige URL des Moduls aufgelöst werden muss und Sie die Erweiterung einschließen müssen, wenn der Server dies erfordert. Server haben die Möglichkeit, Antworten für erweiterungslose URLs zurückzugeben.

Der Grund, warum Node sich für einen restriktiveren Auflösungsalgorithmus für Module entschieden hat, ist die bessere Kompatibilität mit dem Web, sodass es häufiger vorkommt, dass in npm veröffentlichte Module keine zusätzlichen Tools benötigen, um nativ in Browsern ausgeführt zu werden. Das Importieren nach Paketnamen ist immer noch eine sehr wichtige Funktion, daher unterstützt Node dies, zielt aber darauf ab, mit dem Import Maps-Vorschlag kompatibel zu sein (den Deno und SystemJS bereits unterstützen).

Alles in allem funktioniert die Unterstützung von tsc für den Import mit .js -Erweiterungen sowohl in Node- als auch in Webbrowsern perfekt. Es sind tatsächlich die erweiterungslosen Importe, die ohne zusätzliche Tools Probleme verursachen. Normalerweise verwenden die Tools, die die Knotenauflösung für Paketnamen unterstützen, auch die Klassenauflösung von require() und lösen relative Pfade auf und fügen auch ihre Erweiterungen hinzu. Das macht es-dev-server .

Danke @justinfagnani. Zumindest im Browser hängt es also wirklich nur davon ab, wie der Server es implementiert. Das ist gut zu wissen. Das ist immer noch ziemlich unintuitiv und verwirrend und ich glaube, dass es zum Wohle der Community mehr Konvergenz zwischen den Projekten geben muss, aber ich bin mir nicht mehr sicher, wie das aussehen könnte.

Bearbeiten: Fürs Erste reicht mir das (insbesondere angesichts der obigen Erklärungen fühle ich mich damit wohler):

https://nodejs.org/api/esm.html#esm_customizing_esm_specifier_resolution_algorithm

Ich bin mir nicht sicher, ob auf diese Option in der TypeScript-Dokumentation verwiesen wird, aber wenn dies nicht der Fall ist, sollte dies vielleicht der Fall sein, um Verwirrung zu vermeiden. Es scheint nicht so zu sein, wenn Sie entweder nach „ site :typescriptlang.org specifier-resolution“ oder „ site:staging-typescript.org specifier-resolution“ suchen. Da dies in Node noch ziemlich neu ist, ist das jedoch nicht allzu überraschend.

@justinfagnani Ich stimme zu, dass die Erweiterung .js in den meisten Fällen einfach funktioniert, außer in Fällen, in denen jemand eine ideologische Haltung _dagegen_ einnimmt (z. B. https://github.com/TypeStrong/ts-node/issues/783, die Ihnen bekannt sind).

Ich habe hier eine abhängigkeitsfreie Version des Skripts von @quantuminformation erstellt . Diese Version enthält auch eine Regex, die nur Module ersetzt, die nicht bereits mit .js enden.

gleichen Bedarf

Das Erreichen .js -Erweiterungen für die ESM-Kompatibilität durch die Verwendung von .js in den Importanweisungen funktioniert bei mir nicht. Wenn ich eine TS-Datei importiere und eine Erweiterung weglasse, wird sie problemlos kompiliert. Wenn ich dem Import eine .js -Erweiterung hinzufüge, erhalte ich viele Fehler (die nicht existieren sollten) vom TS-Compiler.

Es scheint, dass der Hauptgrund dafür, dass diese Funktion nicht entwickelt wird, in der Schwierigkeit/Unmöglichkeit der Kompatibilität mit verschiedenen Bundlern liegt, aber Node.js und Bundler haben ihre eigenen Modulschemata entwickelt, da Module in ECMAScript nicht unterstützt werden. Jetzt, da wir den ESM haben, so unzulänglich, wie manche Leute ihn finden mögen, ist er der Weg nach vorn. Je mehr Code in ESM- und Webkomponenten entwickelt wird, desto geringer wird die Verwendung von Bundlern, und dieser Schmerzpunkt zwischen TS und ESM wird mehr Reibung entwickeln. Es wäre gut, auch wenn die anfängliche Unterstützung fehlerhaft ist und nicht alle Anwendungsfälle berücksichtigt, wenn sie unterstützt werden könnte.

Bis es eine bessere Lösung gibt, ist dies ein Knotenskript ohne Abhängigkeiten, das als Erstellungsaufgabe verwendet werden kann

konfigurieren Sie in Ihrer package.json:

  ..
    "scripts": {
        "build": "node build.js",
   ...

//build.js
import { execSync} from "child_process"
import * as util from "util"
import * as fs from "fs"
import * as path from "path"

//function to recurse dirs finding files
function fromDir(startPath, filter, callback) {

    //console.log('Starting from dir '+startPath+'/');

    if (!fs.existsSync(startPath)) {
        console.log("no dir ", startPath);
        return;
    }

    var files = fs.readdirSync(startPath);
    for (var i = 0; i < files.length; i++) {
        var filename = path.join(startPath, files[i]);
        var stat = fs.lstatSync(filename);
        if (stat.isDirectory()) {
            fromDir(filename, filter, callback); //recurse
        }
        else if (filter.test(filename)) callback(filename);
    };
};

//this add .js to lines like:  import .* from "\.  <-- only imports from ./ or ../ are touched
function addDotJsToLocalImports(filename) {
    var buf = fs.readFileSync(filename);
    let replaced = buf.toString().replace(/(import .* from\s+['"])(?!.*\.js['"])(\..*?)(?=['"])/g, '$1$2.js')
    if (replaced !== buf.toString()) {
        fs.writeFileSync(filename, replaced)
        console.log("fixed imports at "+filename )
    }
}

//------------------------
//---BUILD TASK START 
//------------------------

execSync("npx tsc --build -verbose", { stdio: 'inherit' })

//add .js to generated imports so tsconfig.json module:"ES2020" works with node
//see: https://github.com/microsoft/TypeScript/issues/16577
fromDir("./dist", /\.js$/, addDotJsToLocalImports)

basierend auf https://github.com/microsoft/TypeScript/issues/16577#issuecomment -310426634

Kann sich jemand erinnern, was sie vor 3 Jahren gemacht haben, als diese Ausgabe geöffnet wurde?

Die Nicht-Bündler-Lösung besteht darin, über das Internet verteilte Projekte mit der Erweiterung .js zu schreiben.

Das funktioniert zu 100%. Das größere Problem ist der Versuch, Module zu schreiben, die auf Web und Node.js abzielen, aber das ist ein Problem für JS im Allgemeinen.

Wenn es etwas zu tun gäbe, würde es --moduleResolution=web hinzufügen, aber das ist nicht der Umfang dieses Problems hier.

Ich musste dieses Post-Build-Skript schreiben, um die Erweiterung .js hinzuzufügen.

fix-ts-imports

#!/usr/bin/env sh

# Fixes JavaScript module imports generated by TypeScript without extension.
# Converts
# import {} from './module'
# into
# import {} from './module.js'
#
# EXAMPLE
# ./fix-ts-imports

ProjectDir="$(cd "$(dirname "$0")/.." && pwd)"

fix() {(
        local pkg="$1"
        shift

        find "$pkg" -type f -iname '*.js' -not -ipath '*/node_modules/*' -print0 \
        | while read -r -d '' file; do
                sed -i '' -E 's|(import .+ from ['\''"]\.?\./.+[^.][^j][^s])(['\''"])|\1.js\2|g' "$file"
        done
)}

if test $# -eq 0; then
        set -- "$ProjectDir"
fi

for pkg; do
        fix "$pkg"
done

Ich habe ein ähnliches Skript in JavaScript:
https://github.com/yoursunny/NDNts/blob/743644226fe18d48e599181e87ad571a2708a773/mk/build-post.js

Es wird aufgerufen als:

tsc -b mk/tsconfig-solution.json -w --listEmittedFiles \
  | node mk/build-post.js

Der Hauptnachteil dieser Art von Skripten besteht darin, dass sie Quellzuordnungen beschädigen, sodass das Debuggen weniger effektiv wird.

Mit modernen Tools und .js -Erweiterungen im Quellcode funktioniert alles hervorragend in Knoten und Browsern

  • Typoskript
  • es-Module
  • aufrollen

Ich kann nur davon ausgehen, dass Leute, die hier Probleme haben, tatsächlich in einer kaputten Mischung aus Es-Modulen und Knotenauflösung stecken, da Entwickler an vertrauten Wahrzeichen ihrer alten Workflows festhalten – wahrscheinlich ist Webpack schuld …

— vermutlich ist webpack schuld...

Und so – die Katze ist aus dem Sack.

Mit modernen Tools und .js -Erweiterungen im Quellcode funktioniert alles hervorragend in Knoten und Browsern

_Die meisten_ Dinge funktionieren hervorragend, und ich stimme zu, dass alle Quelldateien in ihren Exporten die Erweiterung .js haben sollten. Meiner Erfahrung nach funktioniert das einzige, was damit nicht gut funktioniert, mit ts-node, da sie sich hartnäckig weigern, .js -Erweiterungen zu unterstützen . Ja, Sie können vor dem Ausführen von node einen Vortranspilationsschritt hinzufügen, und die .js -Importe funktionieren, aber wenn Sie .ts -Code oder Tests direkt mit node und auch im Browser ausführen möchten, Sie haben derzeit meistens kein Glück. (Zur Verdeutlichung: Ich denke, dies ist ein ts-node-Fehler, kein TypeScript-Fehler).

Danke @chase-moskal.

Ich habe das Repo und die tsconfig-Datei umgestaltet, und jetzt
import {something} from './something.js'
wirft nicht
typescript force overwrite error TS5055: Cannot write file because it would overwrite input file
mehr, und ich brauche den fix-ts-imports -Hack nicht mehr.

In über 250 Kommentaren gab es sehr wenig Klarheit. Zusammenfassen:

Hintergrund

Browser-Module

Browser lösen EcmaScript-Module nach URL auf, einschließlich relativer URLs. ( WASWG )

Node.js-Module

Node.js löst Module (sowohl EcmaScript als auch das Node.js-spezifische CommonJS) über einen weitaus komplexeren Algorithmus auf, der mehrere Fallbacks und das Analysieren von package.json-Dateien umfasst. ( Node.js ) Das kann angepasst werden, z. B. mit --experimental-specifier-resolution=explicit , was den vollständigen Pfad erfordert.

TypeScript-Module

TypeScript verfügt über mehrere verfügbare Modulauflösungsalgorithmen und eine Vielzahl von Optionen, um diese weiter anzupassen. ( TypeScript ) Die Absicht ist, dass Benutzer dieselben Modulbezeichner schreiben, die in der erzeugten Ausgabe verwendet werden, und die Auflösung von tsc mit Optionen wie baseUrl und pathMappings anpassen.

In der Praxis verwenden die meisten Benutzer das Knotenmodul „Resolution“, das auf eine Node.js-Umgebung oder einen kompatiblen Bundler abzielt. Diese Anfrage konzentriert sich auf Benutzer, die auf Browser ohne Bundler abzielen.

ts-node-Modulauflösung

Anscheinend unterstützt ts-node keine Modulkennungen mit Erweiterungen. Obwohl es unklar ist, warum, da sowohl Node.js als auch TypeScript dies tun und ts-node angeblich die Verschmelzung dieser ist.

Fakten

Fakt 1: Sie können .js-Erweiterungen verwenden

Für eine breitere Kompatibilität (insbesondere Browser) können Sie heute .js-Erweiterungen verwenden. Mit der seltsamen Ausnahme von ts-node (IMO-Bug) funktioniert im Moment alles, indem der vollständige Pfad angegeben wird (dh einschließlich Erweiterung).

Fakt 2: Es ist nicht so einfach wie „Erweiterung hinzufügen“

Diese Anforderung lässt sich besser zusammenfassen als „Modulkennung in Dateipfad umwandeln“. Beispiel: Aus ./example wird ./example/index.js und 'lodash' wird '.node_modules/lodash/index.js' .

Beachten Sie, dass es manchmal nicht einmal einen aufgelösten Dateipfad gibt, wie bei Deklarationen von Ambient-Modulen.

declare module "lodash" {
}

Möglicherweise beschränkt sich das Modulumschreiben auf TS-Module im aktuellen Projekt/Zusammenstellung.

Auf jeden Fall verletzen wir jetzt einen der Designparameter von TS, dass andere Module die Ausgabe für das aktuelle beeinflussen.

Fazit

Es ist möglich, den Pfad für Modulkennungen zu verwenden, die für das Web funktionieren. (zB ./foo/index.js statt ./foo .)

(Obwohl Sie praktisch gesehen wahrscheinlich sowieso einen Bundler für Browser benötigen werden. Nämlich, wenn npm-Pakete verwendet werden.)

@pauldraper es gibt ein wichtiges Problem mit "Fakt 2":

Diese Anforderung lässt sich besser zusammenfassen als „Modulkennung in Dateipfad umwandeln“. ZB wird ./example zu ./example/index.js und 'lodash' wird zu 'node_modules/lodash/index.js'.

Sie möchten wirklich keine Spezifizierer außerhalb Ihres Pakets zur Kompilierzeit auflösen, da dies möglicherweise nicht die Pfade sind, die verfügbar sind, wenn das Paket woanders installiert wird. Sie müssen die Knotenmodulauflösung in jeder einzelnen Paketinstallation ausführen. Sonst könnten wir import {} from './node_modules/lodash/index.js' schreiben und veröffentlichen und wären damit fertig.

@justinfagnani , ich stimme zu, aber das zeigt, dass Modulkennungen abstrakt sind und Sie die Speicherorte von Modulen außerhalb von tsc manipulieren. Und dass sich tsc mit solchen Manipulationen nicht befassen kann/muss.

Diese Anforderung lässt sich besser zusammenfassen als „Modulkennung in Dateipfad umwandeln“. ZB wird ./example zu ./example/index.js und 'lodash' wird zu '.node_modules/lodash/index.js'.
Beachten Sie, dass es manchmal nicht einmal einen aufgelösten Dateipfad gibt, wie bei Deklarationen von Ambient-Modulen.

Darum geht es in dieser Anfrage nicht. Es geht darum, eine Erweiterung hinzuzufügen, wenn Code ausgegeben wird. Wir wollen Module schreiben, die mit Typ: "Modul" kompatibel sind, ohne zusätzlichen Hacky-Build-Schritt. Externe Module wie lodash würden auch ohne .js weiter funktionieren, da es sich um CommonJs handelt.

Beispiel:

// ./src/moduleA.ts
export const test = 2;
// ./src/moduleB.ts
import {test} from './moduleA'



md5-ec0300a1c6d92a03c70699d0e52c0072



```js
// ./lib/moduleB.js
import {test} from './moduleA.js'

Zusätzlich zu obigem Typoskript wird package.json „exports“ und „type“ nicht unterstützt. In Projekten, die ich verwalte, gibt es keinen Weg zu echtem ESM.

Diese Anfrage konzentriert sich auf Benutzer, die auf Browser ohne Bundler abzielen.

Das ist falsch. Ich schreibe selten TS/JS für Browser, ich arbeite meistens an serverseitigem Code und ich brauche das auch, weil ich das ESM-Laden im Knoten verwenden möchte und nicht auf Bundler und zusätzlichen Code für das Laden von Modulen angewiesen bin.

Externe Module wie lodash würden auch ohne .js weiter funktionieren, da es sich um CommonJs handelt.

Es sei denn, sie sind es nicht.

Bei Emission.

Es könnte ./moduleA.js sein. Oder es könnte ./moduleA/index.js sein, richtig? Die Modulauflösung von Node.js lässt eine Reihe von Pfaden zu.

Es sei denn, sie sind es nicht.

Können Sie ein Beispiel geben, wenn diese nicht funktionieren würden? Node.js hat gerade Unterstützung für den Import benannter Exporte aus CommonJS erhalten.
https://nodejs.org/api/esm.html#esm_import_statements

Es könnte ./moduleA.js sein. Oder es könnte ./moduleA/index.js sein, richtig? Die Modulauflösung von Node.js lässt eine Reihe von Pfaden zu.

Nicht im ESM-Modus. index.js würde so wie jetzt nicht mehr unterstützt. Der ESM-Loader würde die Metadaten „exports“ und „type“ der Datei „package.json“ lesen.
https://nodejs.org/api/esm.html#esm_mandatory_file_extensions

Für Typescript + node.js-basierte Projekte brauchen wir eine bessere native ESM-Story. Dies kann über Tools (Typoskript) oder in node.js geschehen. Das Problem ist, dass es keinen Konsens darüber gibt, was getan werden sollte.

Bearbeiten Sie den entfernten Link zum Knoten PR, da er irreführend war.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

seanzer picture seanzer  ·  3Kommentare

weswigham picture weswigham  ·  3Kommentare

DanielRosenwasser picture DanielRosenwasser  ·  3Kommentare

siddjain picture siddjain  ·  3Kommentare

MartynasZilinskas picture MartynasZilinskas  ·  3Kommentare