Typescript: Fournir un moyen d'ajouter l'extension de fichier '.js' à la fin des spécificateurs de module

Créé le 16 juin 2017  ·  273Commentaires  ·  Source: microsoft/TypeScript

Pour utiliser les modules es6 dans le navigateur, vous avez besoin d'une extension de fichier .js. Cependant, la sortie ne l'ajoute pas.

En ts :
import { ModalBackground } from './ModalBackground';
Dans la sortie ES2015 :
import { ModalBackground } from './ModalBackground';

Idéalement, j'aimerais que cela sorte
import { ModalBackground } from './ModalBackground.js';

De cette façon, je peux utiliser la sortie dans Chrome 51

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

image

Lié à https://github.com/Microsoft/TypeScript/issues/13422

ES Modules Needs Proposal Suggestion

Commentaire le plus utile

De plus, pour généraliser un peu ce problème, je ne pense pas qu'il s'agisse en fait d'ajouter une extension .js , mais de résoudre le spécificateur de module en un chemin réel, quelle que soit l'extension.

Tous les 273 commentaires

Ce n'est pas seulement lié à # 13422, c'est le même problème. Mais les réponses ont été assez négatives, malgré le fait que je pense que c'est un problème important, alors j'espère que votre problème sera mieux reçu.

Eh bien, j'espère que c'est ajouté, nous étions vraiment impatients de discuter de mon POC en utilisant cela dans mon prochain podcast TypeScript, mais il semble que nous devrons attendre pour utiliser TypeScript sans outils de construction.

Pour le moment, TypeScript ne réécrit pas les chemins. C'est certainement ennuyeux, mais vous pouvez actuellement ajouter vous-même l'extension .js .

@justinfagnani @rictic

Merci pour le conseil, je vais écrire un script shell/node pour le faire.

@DanielRosenwasser serait-il judicieux de rassembler les problèmes du module ES6 natif sous une étiquette ?

De plus, pour généraliser un peu ce problème, je ne pense pas qu'il s'agisse en fait d'ajouter une extension .js , mais de résoudre le spécificateur de module en un chemin réel, quelle que soit l'extension.

J'ai rencontré un autre problème qui n'est pas vraiment le domaine de la dactylographie mais c'est pour mon cas d'utilisation.

Je ne sais pas comment gérer node_modules. Normalement, webpack les regroupe dans le code via le ts-loader mais évidemment, cela n'est pas compris par le navigateur :

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

Ajouter une extension js ici n'a aucun sens.

Je suppose qu'il devrait y avoir une extension de chemin par tapuscrit ou un résolveur d'url exécuté sur le serveur.

J'apprécie que ce soit un cas plutôt de niche, mais je pense que ce serait une façon pour TS de briller tôt dans ce domaine. Peut-être que cela pourrait être un plugin pour le compilateur tsc ?

Pour tous ceux qui viennent à cela et veulent une solution provisoire, j'ai écrit un script pour ajouter une extension de fichier js pour importer des déclarations :

"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');
      });
    })

  })
});

Je pourrais en faire un outil cli ..

Le commentaire de @justinfagnani fait mouche .

De plus, pour généraliser un peu ce problème, je ne pense pas qu'il s'agisse en fait d'ajouter une extension .js, mais de résoudre le spécificateur de module en un chemin réel, quelle que soit l'extension.

quand tu écris

import { KeyCodes } from 'vanilla-typescript';

ou d'ailleurs

import { KeyCodes } from 'vanilla-javascript';

vous importez à partir d'un spécificateur de module, il peut s'agir ou non d'un fichier, mais l'ajout .js à la fin dans ce cas n'entraînera probablement pas une résolution valide.

Si vous écrivez une application NodeJS, l'algorithme NodeJS Require tentera diverses résolutions, mais il n'essaiera probablement pas de le résoudre en 'vanilla-typescript.js' car il fait référence à un nom abstrait et sera, par convention et par configuration, résolu ( peut-être au cours de diverses tentatives) à quelque chose comme '../../../node_modules/vanilla_typescript/index.js' .

D'autres environnements, tels qu'AMD, ont des différences quant à la manière dont ils exécutent cette résolution, mais une chose que tous ces environnements ont en commun est une notion de spécificateur de module abstrait.

J'en parle parce que les implémentations du module ES livrées dans divers navigateurs implémentent quelque chose d'incomplet. Si nous considérons même nos dépendances les plus simples, et dès que nous abordons le sujet des dépendances transitives, il devient clair qu'il devra y avoir un moyen de configurer la chose doggone.

C'est peut-être loin, mais comme vous le découvrez, il n'est pas réaliste d'écrire à cette implémentation (poliment) de preuve de concept qui nous a été donnée.

De plus, je ne vois pas comment TypeScript pourrait éventuellement aider ici puisque le problème est spécifique à l'environnement.

@QuantumInformation votre programme pour ajouter .js aux chemins a l'air sympa, léger, élégant même, mais vous implémentez finalement votre propre groupeur de modules. C'est un travail amusant et intéressant, mais cela démontre les lacunes des implémentations actuelles disponibles dans les navigateurs. Même si vous écrivez en JavaScript pur, vous avez toujours besoin de quelque chose pour compiler et empaqueter vos dépendances importées de manière transitive.

Je ne fais que fulminer sur le fait que la mise en œuvre des modules ES qui a été publiée est extrêmement loin d'être adéquate.

Encore une fois, NodeJS, RequireJS AMD, Dojo AMD, Sea Package Manager, CommonJS, Browserify, Webpack, SystemJS, ont tous leurs propres façons de faire les choses, mais ils fournissent tous une résolution de nom abstraite. Ils doivent le fournir parce que c'est _fondamental_.

Merci d'avoir lu mon coup de gueule.

Vous ne savez pas quelle version de TS l'a ajouté, mais les importations telles que ' ./file.js' fonctionnent maintenant (même si le fichier est en fait file.ts).
TypeScript résout le fichier correctement et génère l'importation complète .js vers la cible.
lit-html utilisez-le : https://github.com/PolymerLabs/lit-html/blob/master/src/lib/repeat.ts#L15

C'est possible depuis TS 2.0. Mais des outils comme Webpack ne le supportent pas donc au final c'est inutile.

C'est inutile si l'on utilise ts-loader sur les sources (le cas d'utilisation le plus courant).
Il est toujours possible de regrouper la cible (généralement le dossier "dist"), car le fichier js réel existe là-bas et peut être trouvé par le processus de résolution.

Je me demande si je pourrais implémenter une transformation rapide dans ts-loader qui supprime les extensions .js du code cible, permettant de regrouper directement à partir des sources.

N'hésitez pas à le faire, ce serait super. J'ai posté le problème sur les principaux chargeurs webpack ts, comme ts-loader, il y a quelques mois, et j'ai été assez mal reçu...

Pour information, il n'y a aucun problème avec le plugin rollup typescript, preuve que c'est faisable.

Je ne vois pas à quoi cela sert jusqu'à ce que les implémentations du chargeur de navigateur et la spécification du chargeur WGATWG prennent en charge au moins _certaines_ configuration car la plupart des dépendances ne se chargent pas correctement.

De mon point de vue, rien de tout cela n'a d'importance tant qu'il n'est pas pratique d'utiliser le chargeur natif sur une importation qui fait référence à un spécificateur littéral de chaîne arbitraire, quelque chose qui n'est peut-être pas encore une URL, et de le faire passer par une transformation qui donne le URL réelle.

Jusque-là, nous resterons dépendants d'outils comme SystemJS et Webpack.

J'ai créé un petit transformateur qui supprime le '.js' des instructions d'importation/exportation.
J'ai utilisé des gardes de type tsutils , donc yarn add tsutils --dev . (le paquet est généralement installé de toute façon si vous avez tslint dans votre projet, donc une dépendance supplémentaire)

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

En utilisant cela, on peut regrouper des fichiers ts contenant des importations à partir de fichiers se terminant par .js (en utilisant webpack et ts-loader ), et toujours transpiler des sources vers des modules esm qui peuvent se charger dans le navigateur (en utilisant tsc ).

Il y a probablement un nombre limité de cas d'utilisation où cela est utile.

EDIT : J'ai mis à jour l'essentiel pour travailler également avec les exportations. c'est naïf et non optimisé, mais ça marche.

Un mouvement sur cette question ?

Cette question d'extension nous ramène au tout début de TypeScript et pourquoi un tsconfig.json était nécessaire et pourquoi une option module a été ajoutée au paramètre compilerOptions .

Étant donné que cette question de extension d'extension n'a d'importance que pour ES2015+, car require est capable de résoudre assez bien, laissez-la être ajoutée par le compilateur lorsque le code ciblé est ES2015+.

  1. .js pour .ts
  2. .jsx pour .tsx

Bonjour, j'arrive tard mais j'aimerais aider. J'ai du mal à comprendre quel est le problème ici. De l'exemple OP, c'est:

import { ModalBackground } from './ModalBackground';

Le problème est-il que nous ne savons pas ce qu'est './ModalBackground' ? C'est peut-être un dossier ou autre chose ?

Si nous exécutons tsc sur l'ensemble du projet et que nous savons que ModalBackground.ts existe, alors nous saurions qu'il est sûr d'ajouter l'extension, non ?

Ce problème est également quelque chose qui intéresse beaucoup la communauté RxJS. Quel est le calendrier d'une solution à ce problème ? Est-ce même prioritaire ? Existe-t-il des transformations tierces qui pourraient aider ?

Je ne sais pas vraiment si c'est un problème si la cible de sortie est ES2015, n'est-ce pas ? Cela pourrait peut-être tomber dans le domaine d'une capacité de navigateur ES2015. Plus encore, @justinfagnani ne pouvons-nous pas faire de cela un objectif de plateforme dont nous devons nous soucier ? (Peut-être besoin de bifurquer dans un fil séparé).

Plus encore, @justinfagnani ne pouvons-nous pas faire de cela un objectif de plateforme dont nous devons nous soucier ? (Peut-être besoin de bifurquer dans un fil séparé).

Oui, bien sûr, beaucoup de gens veulent que la plate-forme prenne en charge une certaine forme de spécificateurs nus, mais le fait actuel est que ce n'est pas le cas et il n'y a même pas de proposition pour les ajouter. Nous devons passer par tout ce processus, probablement pluriannuel.

Même si nous obtenons finalement une prise en charge des spécificateurs nus, il est extrêmement peu probable que ce soit sous la forme d'une résolution de module de nœud telle quelle. Il y aura donc un décalage entre l'algorithme de résolution utilisé par tsc pour trouver des fichiers et l'algorithme de résolution utilisé par les navigateurs (et peut-être même la prise en charge du module natif du nœud, autant que je sache).

Ce serait formidable si tsc pouvait réifier le chemin qu'il a utilisé pour trouver un autre module afin que les outils et les environnements en aval n'interprètent pas les spécificateurs avec une opinion contradictoire.

@justinfagnani ils sont déjà interprétés avec un avis contradictoire. TS produit un fichier JS vers lequel le code JS qu'il produit ne pointe pas. ES6 est la chose la plus proche d'une manière officiellement correcte de faire du JavaScript, donc si le code ES6 produit par TypesScript est faux, c'est un bogue pur et simple. Il n'est pas nécessaire d'attendre des propositions et autres, corrigez simplement le bogue de TypeScript. Mais aujourd'hui, les gens ont l'impression que s'ils ne trouvent pas à redire à quelque chose et ne le soumettent pas à 10 couches de proposition avant d'agir, alors ils n'agissent pas intellectuellement. Laisse-moi tranquille.

@aluanhaddad Il est vrai que de nombreux projets n'en bénéficieront pas, mais certains projets n'utilisent pas de dépendances npm (ou sont capables de gérer les dépendances npm d'une manière ou d'une autre), donc ces projets en bénéficieraient.

C'est également très utile pour les bibliothèques TypeScript, qui sont compilées en ES6. À l'heure actuelle, ces bibliothèques ne peuvent pas être utilisées de manière native dans le navigateur, mais si TypeScript produisait une extension .js , elles fonctionneraient.

@justinfagnani Ce n'est pas encore normalisé ou implémenté, mais il existe une proposition pour faire fonctionner les packages npm dans le navigateur.

Le mappage de noms de packages peut être généré automatiquement par le compilateur TypeScript ou par un autre outil.

Donc, je regarde à nouveau cela, y avait-il une solution de contournement intéressante à cela, en dehors de mon script de nœud?

J'utilise cette solution :
https://github.com/Microsoft/TypeScript/issues/16577#issuecomment -343610106

Mais je crois que si le module n'a pas l'extension de fichier mais est servi avec le bon type MIME, cela devrait résoudre.

Tout mouvement à ce sujet?

peut-être que https://github.com/Microsoft/TypeScript/pull/25073 pourrait résoudre ce problème ?

@Kingwl Prendrez -vous en charge d'autres extensions de fichiers ? comme .mjs .es .esm .

peut-être pas, c'est une autre fonctionnalité

Comment est-ce même une chose? Le compilateur Typescript _sait_ que la sortie cible est un fichier JS. Je parcours ces discussions depuis 15 minutes et je ne comprends toujours pas pourquoi il omet l'extension.

Au vu du nombre de références à cette question, je présume que cela va dans la bonne direction. Je ferai un autre essai bientôt.

Comment est-ce même une chose? Le compilateur Typescript _sait_ que la sortie cible est un fichier JS. Je parcours ces discussions depuis 15 minutes et je ne comprends toujours pas pourquoi il omet l'extension.

Il existe des cas d'utilisation courants, que les gens utilisent, où le manque d'extension permet une infrastructure plus flexible. Node require hook et webpack loader sont deux de ces cas.

Comment est-ce même une chose? Le compilateur Typescript _sait_ que la sortie cible est un fichier JS. Je parcours ces discussions depuis 15 minutes et je ne comprends toujours pas pourquoi il omet l'extension.

Il existe des cas d'utilisation courants, que les gens utilisent, où le manque d'extension permet une infrastructure plus flexible. Node require hook et webpack loader sont deux de ces cas.

Aucun dont les modules du navigateur ne se soucient.

Cela tuerait-il simplement l'équipe de dactylographie d'ajouter un indicateur d'opt-in pour émettre une extension .js ? Nous savons ce que nous faisons ici, sinon il n'y aurait pas une douzaine de discussions (ouvertes et fermées) recueillant encore des réponses et des questions confuses. Nous comprenons que ce n'est pas une lacune avec TS, mais si TS est là pour résoudre nos problèmes JS, alors ajoutez ce problème à la liste s'il vous plaît.

AVERTISSEMENT:

Oui, je comprends que cela puisse amener une tonne de personnes à publier des problèmes ici qui "vous avez b0rked webpack" mais vraiment, des seins durs pour ces gens. Il devrait être opt-in.

Au fait, en fouillant dans la source TypeScript, je vois importModuleSpecifierEnding - cela peut-il être (ab)utilisé pour amener l'émetteur à utiliser les terminaisons .js ?

Peut-être mush cette proposition avec le schéma tsconfig? https://github.com/domenic/package-name-maps

À ce stade, je serais heureux si TypeScript ne pouvait réécrire automatiquement les importations qu'en utilisant le paths spécifié dans tsconfig. Même sans la prise en charge du navigateur, cela résoudrait probablement la plupart des problèmes pour moi.

Les mises à jour? Des tentatives pour résoudre ce problème? Nous avons tous les principaux navigateurs prenant en charge les modules es par défaut, la norme pour ceux qui nécessitent l'extension. Je comprends que nous pouvons l'ajouter manuellement et tsc comprendra cela, mais cela ne devrait pas être obligatoire, pourquoi cela ne peut-il pas simplement fonctionner ?
Désolé de pleurnicher mais ce problème est très ancien maintenant et rien n'a encore été fait...

Comment est-ce même une chose? Le compilateur Typescript _sait_ que la sortie cible est un fichier JS. Je parcours ces discussions depuis 15 minutes et je ne comprends toujours pas pourquoi il omet l'extension.

Il existe des cas d'utilisation courants, que les gens utilisent, où le manque d'extension permet une infrastructure plus flexible. Node require hook et webpack loader sont deux de ces cas.

Ensuite, peut-être que le compilateur Typescript pourrait accepter une option pour ajouter ou non les extensions. Peut-être pourrait-il même accepter un ensemble de regex afin d'ajouter (ou non) l'extension, comme l'option include (https://www.typescriptlang.org/docs/handbook/tsconfig-json.html).

Oui, cela a déjà été proposé au moins une fois auparavant, pourquoi ne pas en tenir compte ? TS a déjà quelques fonctionnalités expérimentales qui pourraient changer à l'avenir une fois implémentées dans le navigateur, mais TS a déjà des drapeaux pour ces spécifications instables. Pourquoi ne pas simplement avoir même un drapeau expérimental addImportsExtensions où il ferait juste le module += '.js' , c'est tout ! Pas de logique funky, pas de fonctionnalités supplémentaires. Il pourrait s'agir d'une cible différente si vous préférez la conserver en tant que cible distincte. Plus que cela, si vous acceptez l'un des éléments ci-dessus, je vais personnellement creuser dans le code tsc et faire un PR pour cela, mais je ne veux pas perdre mon temps si cela ne sera pas accepté de toute façon.

Vous pouvez simplement utiliser une transformation personnalisée pour réécrire les importations dans le code émis (en ajoutant '.js' ou en utilisant le chemin résolu des importations de module).

Comment écrire une transformation TypeScript
ttypescript : wrapper pour tsc qui applique les transformations lors de la compilation

Peut-être existe-t-il déjà une transformation qui fait ce dont vous avez besoin.

Je sais que c'est possible, j'ai pas mal joué avec l'API du compilateur (mais pas autant que je le voudrais). Le fait est qu'il ajoute un outil supplémentaire au projet et que des outils supplémentaires ont des responsables supplémentaires qui pourraient ou non répondre aux problèmes assez rapidement, voire pas du tout (souvent pas par leur faute, nous avons tous des vies et du travail). Les petits projets sont souvent abandonnés, et tout faire nous-mêmes ne fait que nous transférer la responsabilité, donc au lieu de nous occuper du code métier, nous passons du temps sur l'outillage.
En tenant compte de ce qui précède, de nombreux projets ne considéreront même pas cela comme une solution et ajouteront à la place des étapes de construction supplémentaires comme le cumul, etc., ce qui ajoute des frais généraux de configuration supplémentaires et nous ramènera à des coûts de maintenance supplémentaires.
Pour résumer : je préfère passer mon temps sur un PR au TS officiel, où moi et la communauté en bénéficierions, que de le dépenser sur une solution personnalisée que je pourrais éventuellement abandonner (par manque de temps ou pour de nombreuses autres raisons ), ou qui ne pourrait être utilisé par personne d'autre dans le monde.

@ajafff ​​Cela pourrait être une solution, mais je pense que le principal problème est le suivant : le transpileur Typescript génère un code source erroné dans les navigateurs. C'est bien d'avoir des transformations, mais je vois cela comme une solution de contournement. Je me demande si je dois me soucier des détails de la transpilation et si j'ai besoin d'implémenter ma propre transformation ou si c'est quelque chose qui devrait être géré par le compilateur.

Les transformations sont un outil vraiment puissant, nous pourrions écrire un tout nouveau transpiler en tant que transformation, mais je pense que ce n'est pas la bonne façon.

Oui, cela a déjà été proposé au moins une fois auparavant, pourquoi ne pas en tenir compte ? TS a déjà quelques fonctionnalités expérimentales

TypeScript a exactement un drapeau expérimental qui a été ajouté il y a 3 ans, et c'était pour une proposition ECMAScript qui n'est plus compatible avec la proposition actuelle.

le transpileur Typescript génère un code source erroné dans les navigateurs

Je comprends vos attentes, mais étant donné que le compilateur ne réécrit pas les chemins que vous avez écrits, je suis surpris que vous ne considériez pas que les importations de votre propre code soient "erronées". 😉

Je suis désolé @DanielRosenwasser , avez-vous entendu parler d'une chose appelée npm ? Les gens y postent leurs colis afin que nous puissions tous les utiliser. Je comprends que vous puissiez avoir une très haute opinion de moi, mais malheureusement, je ne suis pas l'auteur de la grande majorité de ceux-ci, donc je ne peux pas les modifier en ajoutant les extensions.
Si mes projets n'utilisaient que mon code, je serais plus reconnaissant de ce que le tapuscrit apporte, car c'est vraiment ma main droite dans le codage (à part WebStorm). J'utilise cependant des packages tiers comme je pense que la plupart d'entre nous et ceux-ci ne contiennent pas nécessairement les extensions. Certains projets, comme rxjs, attendent littéralement avec l'espoir que le tapuscrit fournira le moyen d'ajouter des extensions, sinon cela les obligerait à modifier l'ensemble du processus de construction, nous sommes donc revenus à passer plus de temps sur les outils au lieu du produit.
Maintenant, s'il vous plaît, pourriez-vous répondre à 3 questions ?

  1. L'équipe dactylographiée est-elle disposée à livrer cette fonctionnalité ?
  2. Si oui, accepteriez-vous un PR ?
  3. Si non, quand comptez-vous le sortir ?

Si la réponse à la 1ère question est "non", veuillez fermer ce problème en déclarant officiellement que vous n'êtes PAS disposé à proposer cette fonctionnalité, ne faites pas attendre les autres si elle ne doit pas venir.

Oui, cela a déjà été proposé au moins une fois auparavant, pourquoi ne pas en tenir compte ? TS a déjà quelques fonctionnalités expérimentales

TypeScript a exactement un drapeau expérimental qui a été ajouté il y a 3 ans, et c'était pour une proposition ECMAScript qui n'est plus compatible avec la proposition actuelle.

le transpileur Typescript génère un code source erroné dans les navigateurs

Je comprends vos attentes, mais étant donné que le compilateur ne réécrit pas les chemins que vous avez écrits, je suis surpris que vous ne considériez pas que les importations de votre propre code soient "erronées". 😉

C'est un bon point @DanielRosenwasser , j'ai juste considéré mon propre code correctement car il semble être correct de lire la spécification Typescript (https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#11.3).

Je suis sûr que vous avez lu les spécifications ECMAScript. Dans la spécification, il n'est pas déterminé si un module doit se terminer par une extension ou non. Dans les spécifications, les modules importés sont résolus à l'aide de l'algorithme HostResolveImportedModule, mais la définition est ambiguë. Le problème n'est pas la spécification ECMAScript. Le problème est que les navigateurs résolvent les modules comme si le [ModuleRequest] tel que défini dans les spécifications était un chemin vers les ressources.

En gardant cela à l'esprit, rendez-vous simplement sur la page d'accueil du langage : https://www.typescriptlang.org/ .

Dans le pied de page vous pouvez lire les lignes suivantes :

Commence et se termine avec JavaScript

TypeScript part de la même syntaxe et sémantique que des millions de développeurs JavaScript connaissent aujourd'hui. Utilisez du code JavaScript existant, intégrez des bibliothèques JavaScript populaires et appelez du code TypeScript à partir de JavaScript.

TypeScript se compile en un code JavaScript simple et propre qui s'exécute sur n'importe quel navigateur , dans Node.js ou dans n'importe quel moteur JavaScript prenant en charge ECMAScript 3 (ou plus récent).


Vous promettez un code qui s'exécute sur tous les navigateurs, mais cela ne semble pas être vrai, c'est pourquoi ce problème persiste depuis plus d'un an.

Comme le souligne @Draccoz , nous voulons juste savoir ce que vous faites avec ce problème. Mais c'est un peu frustrant de lire une chose dans votre page d'accueil et l'inverse dans ce numéro.

Non, nous ne sommes pas disposés à expédier quoi que ce soit lié à cela tant qu'il n'y a pas au moins de clarté sur des choses comme l'interopérabilité ES dans Node et une stratégie raisonnable pour expédier les dépendances transitives que vous utiliseriez à partir de npm en premier lieu. Si vous n'utilisiez pas TypeScript, vous auriez le même problème concernant la gestion et la résolution des dépendances. Cela n'a donc aucun sens pour nous de proposer quelque chose que l'écosystème JS dans son ensemble pourrait développer indépendamment. Mais même si ces problèmes étaient résolus, je ne peux pas garantir que nous apporterions des changements ici, point final.

Vous promettez un code qui s'exécute sur tous les navigateurs, mais cela ne semble pas être vrai, c'est pourquoi ce problème persiste depuis plus d'un an.

Je pense que cette interprétation est trop littérale. var fs = require('fs') ne fonctionne pas lorsque vous l'exécutez dans le navigateur, HTMLDivElement n'est pas défini dans Node et String.prototype.startsWith ne fonctionne pas sur les anciens navigateurs. Pour résoudre ce problème, les utilisateurs ont créé des outils et des bibliothèques/polyfills en dehors de TypeScript, car ils s'appliquent à l'écosystème JavaScript plus large.

Alors pouvez-vous s'il vous plaît fermer ce sujet? Ceci bloque les autres projets qui attendent que TS le fasse ou déclare que vous ne le faites pas. Si vous ne pouvez pas simplement ajouter un simple indicateur, fermez ce problème et informez les autres de vos décisions.

@DanielRosenwasser Merci pour votre réponse rapide, j'apprécie vraiment cela. Je pense que c'est un choix judicieux.

Je pense que cette interprétation est trop littérale. var fs = require('fs') ne fonctionne pas lorsque vous l'exécutez dans le navigateur, HTMLDivElement n'est pas défini dans Node et String.prototype.startsWith ne fonctionne pas sur les anciens navigateurs. Pour résoudre ce problème, les utilisateurs ont créé des outils et des bibliothèques/polyfills en dehors de TypeScript, car ils s'appliquent à l'écosystème JavaScript plus large.

Bien sûr que oui, mais que pourrait penser d'autre quelqu'un qui ne connaît rien à Typescript ? Le fait que mon interprétation soit trop littérale est aussi vrai que le fait que ce texte puisse "dérouter" quiconque ne connaît rien à Typescript 😉.

Peut-être pourriez-vous mettre à jour votre documentation (https://www.typescriptlang.org/docs/handbook/modules.html) afin de refléter le comportement réel.

@DanielRosenwasser merci encore pour votre réponse. J'attends quelque chose de similaire depuis un an.

La raison pour laquelle je voulais cette fonctionnalité était que je pouvais voir quel type d'application Web je pouvais créer sans aucun outil de construction. Jusque-là, je peux utiliser ce script que j'ai écrit plus tôt.

Pour les personnes comme moi à la recherche d'une solution pour pouvoir utiliser les modules ES et TypeScript dans le navigateur aujourd'hui, j'ai trouvé https://github.com/guybedford/es-module-shims. Il agit comme une sorte de polyfill pour les mappages de noms de packages pendant que nous attendons la finalisation des spécifications et l'implémentation du navigateur. Il résout le problème de @QuantumInformation de ne vouloir utiliser aucun outil de construction (mon problème également) lors de la création d'une application Web simple dans TypeScript (à part le compilateur TS).

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>

En théorie, une fois que les mappages de noms de packages sont pris en charge par les navigateurs, vous pouvez simplement trouver/remplacer type='module-shim' par type='module' dans vos fichiers HTML et modifier le script packagemap en ce qui finit par être finalisé pour l'inclusion de packagemap dans le spéc.

Il est probablement également intéressant de noter que l'extension .js n'est pas mandatée par les navigateurs ou quoi que ce soit - vous pouvez toujours configurer votre serveur Web pour qu'il ressemble davantage unpkg et servir des fichiers .js à partir de URL de demande sans extension. Tout est configurable côté serveur Web.

@weswigham qui peut cependant être très problématique, car tsc (et la résolution de module de nœud classique) saura que ./foo et ./foo.js font référence au même fichier, mais les navigateurs les traiteront différemment, même si le redirections de serveur Web. Vous devez vous assurer que vous vous référez à un fichier exactement de la même manière à chaque importation.

Soit dit en passant, ce problème n'empêche pas les modules générés par TypeScript d'être utilisés dans les navigateurs aujourd'hui. Importez toujours les fichiers avec l'extension .js . tsc fait ce qu'il faut et résout les types du fichier .ts , et vous obtenez la compatibilité du navigateur.

@weswigham Gardez à l'esprit qu'il existe des situations dans lesquelles vous servez des fichiers sans avoir accès au serveur Web. Pages GitHub, IPFS, S3, etc. Avec l'avènement des frameworks d'applications à page unique, il devient de plus en plus courant d'exécuter "sans serveur" (où sans serveur signifie ici sans serveur que vous contrôlez/configurez pour servir vos actifs), de sorte que vous ne peut pas compter sur les filtres côté serveur pour servir apple.js lorsqu'une demande est faite pour apple .

Vous devez vous assurer que vous vous référez à un fichier exactement de la même manière à chaque importation.

Peut toujours faire l'un ou l'autre 404 selon vos préférences de création. Si vous utilisiez des liens symboliques dans votre projet, ils causeraient un problème similaire que vous devrez également choisir comment traiter.

Importez toujours les fichiers avec l'extension .js

Ouais, ça marche bien aussi.

@QuantumInformation Votre extrait utilisé ici est-il pour une utilisation ouverte ? Puis-je l'utiliser dans un projet ? 😃

@distante oui tu peux l'utiliser

Pour votre information, si vous utilisez Jest pour tester et modifier les extensions en .js dans la source - cela casse
mais vous pouvez ajouter ce qui suit à votre configuration jest pour résoudre ce problème

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

Bonjour @MrAntix ,

Je pense que jest est la bibliothèque qui devrait s'adapter à TypeScript, et non l'inverse.

J'ai un autre site avec lequel je ne veux pas utiliser d'outil de construction. Est-ce le meilleur que nous ayons :

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

Comme solution de contournement, vous pouvez simplement le faire comme ça (même si c'est un fichier ts, pas js) 😢

Screenshot 2019-06-05 at 22 47 49

Si quelqu'un veut l'essayer :
https://github.com/QuantumInformation/web-gen-bot

Cependant, je n'arrive pas à faire fonctionner le débogage source avec le tsconfig actuel, je ferai un rapport.

À la fin, je suis retourné à webpack, node_modules était le tueur en essayant de s'éloigner des outils de construction dans le navigateur.

Ce n'est pas seulement Jest - si vous utilisez tsc pour compiler TypeScript avant la publication, tout module JS important le package résultant se cassera en raison des différences de résolution de module.

La discussion ici semble avoir bifurqué un peu en deux questions liées mais finalement distinctes :

  • Typescript doit générer des fichiers pouvant être chargés nativement dans un navigateur
  • Typescript devrait résoudre le fait que les chemins de module de nœud ne sont pas toujours des URL valides.

Je pense que nous devons nous concentrer sur le premier problème, car le second est clairement quelque chose que le tapuscrit ne peut pas résoudre par lui-même.

Le premier problème, cependant, est absolument quelque chose que Typescript peut résoudre et devrait prioriser, car il s'agit d'un obstacle majeur pour la plupart des personnes souhaitant utiliser Typescript pour créer des applications Web destinées aux navigateurs modernes.

A mon avis, le problème se résume à ceci :

Si l'exécution tsc génère un fichier avec une extension .js puis un autre fichier qui importe le premier fichier .js , il n'y a pas d'ambiguïté sur l'extension à utiliser, et il devrait y avoir un possibilité d'inclure l'extension.

Pour toutes les instructions d'importation pointant vers des fichiers autres que les fichiers générés par Typescript, je pense qu'il est bon de les laisser inchangés (comme Typescript le fait aujourd'hui).

Selon la première option, je pense qu'un argument de ligne de commande serait le mieux, et il serait désactivé par défaut. Je dis cela parce que, si j'utilise webpack, je ne veux pas que .js soit ajouté aux importations car webpack s'occupe du regroupement des modules.

Quoi qu'il en soit, node_modules était le tueur qui m'a empêché d'utiliser le hack pour les applications de navigateur de modules natifs.

Je dis cela parce que, si j'utilise webpack, je ne veux pas que .js soit ajouté aux importations car webpack s'occupe du regroupement des modules.

Webpack gère parfaitement l'extension .js , il n'y a donc aucune différence.

En fait, il est parfois nécessaire d'utiliser .js avec Webpack (dans les situations où il y a plusieurs fichiers avec le même nom mais des extensions différentes).

Pourriez-vous expliquer pourquoi vous ne voulez pas d'importations de .js avec Webpack ?

Quand je dis I don't want , je voulais dire que je n'en ai pas besoin pour mes cas d'utilisation.

Je ne vois pas de raison impérieuse pour laquelle ce ne devrait pas être le comportement par défaut alors (toujours réticent à ajouter un autre indicateur de configuration ...)

Si vous définissez les importations sur .js , ts-node cesse de fonctionner correctement pour le fichier. En effet, ts-node ne compile qu'un seul fichier à la fois et si le contenu du fichier émis se termine par require('./foo.js') , alors lorsque nodejs traitera ce fichier, il essaiera de charger ./foo.js qui n'existe pas n'importe où sur le disque et donc il échouera. Lorsque le code nécessite ( ./foo ) d'autre part, le gestionnaire de ts-node sera appelé à quel point il peut compiler ./foo.ts en JS et le renvoyer.

Si TypeScript émet des extensions .js dans tous les cas, ts-node rencontrera le même problème. Cependant, s'il existe une option pour basculer si une extension est automatiquement ajoutée ou non, alors ts-node peut désactiver cette option du compilateur, ce qui permettra au système actuel de continuer à fonctionner.

Étant donné que Node.js --experimental-modules nécessite des extensions de fichier obligatoires, l'API pour cela est simple sans nécessiter d'analyse de dépendance - une option comme --jsext peut réécrire n'importe quelle extension .ts en .js extension .ts comme import 'npmpkg.ts' . Ce cas est extrêmement rare, mais pour le gérer de manière exhaustive dans la résolution, la règle pourrait être de faire une exception pour les _spécificateurs nus_ du type - si le spécificateur nu (pas une URL ou un chemin relatif) est un nom de package npm valide ( correspondant /^(@[-_\.a-zA-Z\d]+\/)?[-_\.a-zA-Z\d]+$/ , depuis https://github.com/npm/validate-npm-package-name), puis ignorez les extensions .ts dans la réécriture.

J'ai créé un transformateur de compilateur TypeScript qui ajoutera une extension de fichier .js sur n'importe quel chemin d'importation relatif. Cela signifie que si votre fichier .ts a import { Foo } from './foo' il émettra import { Foo } from './foo.js' . Il est disponible sur NPM et des instructions sur son utilisation sont disponibles dans le fichier readme du projet.

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

Si quelque chose comme ça devait être intégré dans le compilateur TypeScript (en tant qu'option du compilateur), il devrait probablement être plus intelligent de décider quand ajouter l'extension .js et quand ne pas le faire. À l'heure actuelle, il recherche tout chemin commençant par ./ ou ../ et qui n'a pas de . ailleurs dans le chemin. Cela signifie qu'il ne fera pas la bonne chose dans un certain nombre de scénarios de cas extrêmes, bien que je me demande si quelqu'un _réellement_ se heurtera à ces cas extrêmes ou non.

@MicahZoltu super de voir des solutions utilisateur à cela. Je pense qu'il est assez important cependant que le modèle mental devienne toujours inclure les extensions de fichier , de sorte que l'option d'extension TypeScript puisse devenir _tourner les extensions .ts en extensions .js sur compile_. Cela évite les cas extrêmes de résolution, ne laissant que le cas des noms de packages npm qui se terminent par ".ts", qui peuvent être traités comme je l'ai expliqué dans mon commentaire précédent.

@guybedford Inclure l'extension .js dans un fichier .ts empêche le fichier de s'exécuter dans ts-node. La résolution du problème dans ts-node est loin d'être triviale en raison de la façon dont NodeJS résout les fichiers. Cela signifie que si vous publiez une bibliothèque avec des extensions .js codées en dur, la bibliothèque ne fonctionnera pas pour quiconque utilise ts-node. Voir la discussion à ce sujet sur https://github.com/TypeStrong/ts-node/issues/783.

@MicahZoltu Je veux dire inclure l'extension .ts dans un fichier .ts plutôt.

@guybedford L' inclusion de l'extension .js dans un fichier .ts empêche le fichier de s'exécuter dans ts-node.

C'est encore une autre raison pour laquelle l'exécution automatique de TypeScript dans les nœuds et les navigateurs est une mauvaise idée.

@MicahZoltu Je veux dire inclure l'extension .ts dans un fichier .ts plutôt.

Je pense que le problème avec ceci est qu'il rompt l'équivalence entre un fichier .ts et une paire .js / .d.ts . Cela signifie que si vous importez un fichier compilé avec le projet actuel, vous utilisez .ts , et si vous déplacez le fichier vers un autre projet, vous devez modifier les importations pour utiliser .js .

Cela signifie également que la sortie ne fonctionne pas dans des environnements standard sans le transformateur. Étant donné qu'il n'y a aucun moyen d'installer un transformateur à partir d'un fichier .tsconfig , cela signifie que vous devez toujours utiliser un compilateur personnalisé. C'est une barrière assez importante à mettre en place pour le petit avantage d'utiliser .ts au lieu de .js .

Cela signifie que si vous importez un fichier compilé avec le projet actuel, vous utilisez .ts, et si vous déplacez le fichier vers un autre projet, vous devez modifier les importations pour utiliser .js.

Les limites d'importation externes / internes sont des choses bien définies. Si une dépendance passe d'un fichier interne .ts de la même version actuelle à un fichier externe .js d'une autre importation de package qui a sa propre version distincte ou qui n'est peut-être même pas TypeScript , alors oui, vous devez changer l'extension car c'est un concept complètement différent.

Cela signifie également que la sortie ne fonctionne pas dans des environnements standard sans le transformateur.

Bien qu'un transformateur puisse nous aider à explorer cela, un indicateur / option de compilateur --ts-to-js ou similaire est indispensable pour résoudre ce problème.

@guybedford Vous m'avez convaincu que mettre .ts était la bonne chose à faire pour le plugin. Cependant, en essayant de l'implémenter, j'ai appris que TypeScript ne le permettait pas réellement !

// 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()

Bonjour, Qu'en est-il de cela ?


contribution:

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

console.log(result);

sortir:

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

console.log(result);

numéro 30076

Une seule extension .ts sur un fichier TypeScript me semble la plus appropriée. Souvent, vous ne savez pas quelle est la cible avant la compilation. Par exemple, dans bon nombre de mes projets de bibliothèque, j'ai plusieurs fichiers tsconfig.json qui ciblent différents environnements, tels que le ciblage des navigateurs modernes qui devraient émettre des fichiers .js et mapper les chemins d'importation vers .js , ou ciblant Node moderne, qui devrait émettre des fichiers .mjs et mapper les chemins d'importation vers .mjs .

@MicahZoltu que l'importation de fichiers se terminant par .ts est une erreur est peut-être à notre avantage en fait. Parce que cela signifie que la réécriture des extensions .ts à .js lors de la compilation peut être ajoutée chaque fois que les extensions .ts sont utilisées sans avoir besoin d'un indicateur :)

Peut-être qu'un PR pour activer les extensions de fin .ts prises en charge et réécrites en extensions .js (éventuellement sous un indicateur pour activer cette fonctionnalité, mais un indicateur qui peut être supprimé à temps) serait un excellent moyen s'engager dans cette voie.

//cc @DanielRosenwasser

Ce sujet est déjà très long donc quelqu'un l'a peut-être déjà dit, donc au risque de répéter ce qui a déjà été dit :

TypeScript devrait permettre aux développeurs de spécifier des extensions dans import s car il valide JavaScript. Et il ne s'agit pas seulement de l'extension JS/TS ! Dans ESM, toute extension est valide tant que le type MIME est correct.

import actuallyCode from './lookLikeAnImage.png';

… devrait être valide tant que le serveur sert un code JavaScript valide dans ce fichier et définit le type MIME correct. Cela va plus loin car la même chose pourrait être vraie pour TS ! Un fichier TS peut être simplement un code source JS servi avec le type JS MIME et donc un chemin valide pour une importation de module ESM.

IMO TypeScript ne devrait considérer que les importations sans extension (comme il vous veut aujourd'hui) et laisser celles qui sont seules, sans erreur, avertissement, etc. Sinon, il rejette le code JavaScript valide, ce qui est assez regrettable pour quelque chose qui prétend être un sur-ensemble de JS.

Désolé si ce n'est pas le bon endroit pour soulever ce problème, j'ai vu quelques autres problèmes : #18971, #16640, #16640 mais les problèmes sur ce sujet semblent se fermer à gauche et à droite, donc je suppose que c'est le "principal" puisqu'il était autorisé à rester ouvert.

Jouer avec 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'
}

Maintenant, je ne sais pas pourquoi c'est ennuyeux...

Pour le moment, TypeScript ne réécrit pas les chemins. C'est certainement ennuyeux, mais vous pouvez actuellement ajouter vous-même l'extension .js .

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

Qu'en est-il de la mise en œuvre derrière une option ? Comme --rewrite-paths ( rewritePaths: true ) ?

@viT-1 Voici une solution de contournement pour le moment : https://github.com/microsoft/TypeScript/issues/16577#issuecomment -507504210

@MicahZoltu Je viens de résoudre mon cas d'utilisation en regroupant SystemJS (option tsconfig outFile)

Je n'ai pas lu tous les commentaires que les gens ont écrits à ce sujet, mais je ne comprends pas pourquoi je dois écrire .js un milliard de fois. Je veux que l'ordinateur le fasse pour moi.

@richardkazuomiller Nous le faisons tous, mais @DanielRosenwasser a déclaré dans https://github.com/microsoft/TypeScript/issues/16577#issuecomment -448747209 qu'ils ne sont pas disposés à le faire pour le moment (je suis surpris que ce problème soit encore ouvert de manière trompeuse si longtemps après la déclaration ci-dessus). Si vous voulez que l'ordinateur le fasse pour vous, envisagez d'utiliser un bundler ou un outil tiers pour gérer les réécritures des chemins d'importation.

Qui veut que je ferme ce sujet ?

S'il vous plaît, ne fermez pas, j'attends toujours de voir comment l'équipe TypeScript va répondre à la façon dont elle va aborder les importations ESM qui permettent d'utiliser n'importe quelle extension et de s'appuyer sur le type MIME à la place. Pour le moment, cela est possible en JavaScript mais pas en TypeScript. (S'il vous plaît voir mon commentaire précédent pour plus de détails.)

@TomasHubelbauer C'est pourquoi j'ai proposé un indicateur dans le fichier de configuration, cela pourrait indiquer que toutes les importations sans extension doivent avoir l'extension .js (ou toute autre configurée) ajoutée. Ce serait opt-in, donc la valeur par défaut pourrait être fausse, faisant fonctionner des projets existants ou des projets avec des besoins différents tels quels.

Comme dit précédemment :

Vous ne savez pas quelle version de TS l'a ajouté, mais les importations telles que ' ./file.js' fonctionnent maintenant (même si le fichier est en fait file.ts).
TypeScript résout le fichier correctement et génère l'importation complète .js vers la cible.

Cela a du sens car tout JavaScript valide est un TypeScript valide. Puisque vous pouvez faire :

import foo from './bar.js'

... en JS, vous devriez également pouvoir le faire en TS. Si vous faites cela, vous résolvez le problème de l'utilisation de modules ES6 natifs car vos extensions sont correctes.


N'oublions pas non plus que lorsque le navigateur voit une importation pour ./foo/bar , il en fait une demande. Le fait que rien n'ait été servi était dû au serveur. Vous pouvez le configurer de manière à ce que les demandes de /foo/bar soient satisfaites avec /foo/bar.js . Je ne dis pas que c'est une bonne solution, ni même une bonne idée , mais cela fonctionnerait techniquement.

flag dans le fichier de configuration, cela pourrait indiquer que toutes les importations sans extension doivent avoir l'extension .js (ou toute autre configuration configurée) ajoutée

Cela résoudrait la grande majorité des cas. L'équipe TypeScript serait-elle disposée à envisager un PR pour cette option de configuration ?

NodeJS maintenant _par défaut_ se comporte de la même manière que les navigateurs en ce qui concerne la résolution du module de chemin relatif. Il ne déduira plus une extension .js par défaut. Cela signifie que le comportement actuel de TSC entraîne l'émission de JS qui est invalide dans tous les contextes d'exécution. Il semble que ce problème devrait maintenant être résolu car le comportement du navigateur et de NodeJS pour ESM est clair.

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

Le nouveau résolveur pour esm a besoin d'un nouveau mode de résolution - moduleResolution: node n'est vraiment que le résolveur cjs pour ce que je peux maintenant appeler "les anciennes versions de node". Si vous avez l'intention de cibler le nouveau résolveur esm, nous aurons besoin d'un nouveau mode de résolution pour une correspondance plus appropriée. D'autant plus que le nœud prend toujours entièrement en charge l'ancien résolveur dans toutes les configurations existantes. (Remarque : faire un tel nouveau résolveur _notre défaut_ serait difficile)

Mais! Bien qu'il y ait un _désaccord_ à ce sujet et que _certaines personnes choisiront d'exprimer leur opinion comme un fait_, il existe toujours un indicateur --es-module-specifier-resolution=node qui renvoie le comportement d'extension attendu et peut encore devenir la valeur par défaut - comme le disent les docs, bien qu'il ne soit pas signalé , es modules dans node sont _toujours expérimentaux par nature_.

Aussi, pour rappel de la requête d'origine : nous ne réécrivons pas les importations. Jamais. Du tout. Spécificateur in === spécificateur out. Les spécificateurs décrivent l'intention structurelle, et notre objectif n'est pas de mapper implicitement d'une structure prévue à une autre. Vous pourriez aussi y penser de cette façon : si vous écriviez const varFoo = "./Foo"; import(varFoo) , ajouterions-nous d'une manière ou d'une autre l'extension, si nécessaire ? Non - c'est ridicule - pour gérer toutes les formes d'entrée dynamique, nous aurions besoin d'encapsuler l'importation dynamique au moment de l'exécution, et soudain, nous sommes devenus notre propre chargeur de module, superposé au chargeur de plate-forme intégré. Au lieu de cela, nous fournirons un mode de résolution qui corrige correctement les erreurs lorsque vous omettez l'extension (pour laquelle, bien sûr, vous pouvez sans aucun doute déjà trouver des règles de charpie).

Si vous trouvez ce fil et que vous _voulez vraiment_ que vos sources d'entrée n'aient pas d'extensions, et que vous _vraiment besoin_ que votre sortie fonctionne toujours avec cela lorsque vous ciblez des modules (nœuds), vous devez fournir des commentaires sur https://github.com/ nodejs/modules/issues/323 avec votre justification, afin que cela puisse fonctionner de cette façon dans la plate-forme cible elle-même, car c'est finalement ce à quoi nous nous reportons.

tout à coup, nous sommes devenus notre propre chargeur de modules

tsc ne doit-il pas être un chargeur de module fonctionnel quoi qu'il arrive ? Vous ne pouvez pas vérifier le type d'une importation si vous ne trouvez pas le module dont elle provient. Je veux juste voir tous les différents chargeurs de modules se comporter d'une manière largement compatible, ou du moins d'une manière prévisible et différente qui est raisonnablement facile à adapter.

NodeJS se comporte désormais par défaut de la même manière que les navigateurs en ce qui concerne la résolution du module de chemin relatif. Il ne déduira plus une extension .js par défaut. Cela signifie que le comportement actuel de TSC entraîne l'émission de JS qui est invalide dans tous les contextes d'exécution.

N'est-ce pas une autre raison d'utiliser simplement les extensions de fichier .js dans des spécificateurs comme TypeScript les prend déjà en charge ? Cela résout tout sauf que ce serait formidable si tsc faisait une erreur sur les importations sans extension.

tsc ne doit-il pas être un chargeur de module fonctionnel quoi qu'il arrive ? Vous ne pouvez pas vérifier le type d'une importation si vous ne trouvez pas le module dont elle provient. Je veux juste voir tous les différents chargeurs de modules se comporter d'une manière largement compatible, ou du moins d'une manière prévisible et différente qui est raisonnablement facile à adapter.

Notre objectif n'est pas de fournir une implémentation de chargeur d'exécution - juste une analyse du temps de compilation qui reflète le chargeur d'exécution que vous ciblez. Nous ne pouvons pas remapper toutes les importations sans un composant d'exécution, que nous n'avons pas, ni visons à avoir.

tsc ne doit-il pas être un chargeur de module fonctionnel quoi qu'il arrive ?

Pas à l'exécution. tsc doit comprendre comment le runtime choisi résoudra les spécificateurs et les implémentera au moment de la construction, mais le runtime est purement laissé à l'environnement.

Vous pourriez aussi y penser de cette façon : Si vous avez écrit const varFoo = "./Foo"; import(varFoo) ajouterions-nous d'une manière ou d'une autre l'extension, si nécessaire ?

@weswigham C'est un argument fort concernant les importations dynamiques, mais je ne pense pas que vous puissiez le faire avec des importations statiques ? Je peux comprendre l'argument selon lequel la stratégie devrait être la même pour les deux, mais je pense qu'il convient de mentionner que les importations statiques remplissent un rôle très différent des importations dynamiques et je ne pense pas qu'il soit carrément _déraisonnable_ d'avoir une stratégie différente pour les importations statiques. réécriture d'importation et réécriture d'importation dynamique.

N'est-ce pas une autre raison d'utiliser simplement les extensions de fichier .js dans des spécificateurs comme TypeScript les prend déjà en charge ? Cela résout tout sauf que ce serait formidable si tsc se trompait sur les importations sans extension.

@justinfagnani Il y a deux problèmes avec ça :

  1. Un environnement d'exécution qui exécute TS de manière native (tel que TS-Node) ne fonctionnera pas si vous spécifiez des extensions .js sur vos importations.
  2. Vous mentez au compilateur (IMO) si vous incluez des extensions .js dans vos importations.

Concernant (2), si j'ai deux fichiers TS a.ts et b.ts et a.ts fait import ... from './b.js' , je dis au compilateur "J'ai un fichier frère nommé b.js . Cette affirmation n'est pas vraie. Pour aggraver les choses, si vous avez à la fois .b.ts et b.js (qui ne sont peut-être pas les dérivés l'un de l'autre), il devient maintenant ambigu à laquelle vous faites référence _même si vous avez explicitement inclus une extension_.

Je suis d'avis que l'utilisateur devrait dire au compilateur ce qu'il veut réellement (en tant qu'utilisateur) et c'est soit "importer n'importe quel fichier avec un nom de X et n'importe quelle extension" (dans le cas de import ... from './foo' ) ou "importez spécifiquement ce fichier" (dans le cas de import ... from './foo.ext' ). Si le compilateur détecte que vous importez un fichier TS et qu'il émet un fichier .js , je pense que le compilateur doit mettre à jour l'importation pour importer correctement le fichier approprié. Cela peut signifier remplacer un .ts par un .js dans l'instruction d'importation.

@justinfagnani Il y a deux problèmes avec ça :

  1. Un environnement d'exécution qui exécute TS de manière native (tel que TS-Node) ne fonctionnera pas si vous spécifiez des extensions .js sur vos importations.

Il s'agit d'un bogue dans TS-Node. Cela ne correspond pas au comportement de tsc .

  1. Vous mentez au compilateur (IMO) si vous incluez des extensions .js dans vos importations.

C'est en fait le contraire - vous dites la vérité sur ce qui sera réellement importé. Vous n'importerez _pas_ un fichier .ts , mais un fichier .js . Il ne devrait pas non plus y avoir de différence visible entre une paire .d.ts / .js et un fichier .ts . Ils sont interchangeables. La seule façon appropriée d'y parvenir est d'importer le fichier .js - ce que sera le fichier .ts après la compilation.

@justinfagnani

Il ne devrait pas non plus y avoir de différence visible entre une paire .d.ts/.js et un fichier .ts

Ce n'est pas toujours vrai. Vous pouvez configurer votre serveur pour servir tous les JS, TS et DTS avec un type JS MIME, puis les importer tous séparément en JavaScript et le runtime les exécutera consciencieusement en tant que JS. ESM ne se soucie pas du tout des extensions.

C'est pourquoi je pense que les utilisateurs de TS devraient en fait être obligés d'inclure une extension .ts et sans extension serait une erreur à moins d'importer réellement un fichier sans extension ou ce nom. Et TS réécrirait les importations en .js dans la sortie. Et si un fichier JS existait (et non un fichier généré par TS), ce serait également une erreur.

Il s'agit d'un bogue dans TS-Node. Cela ne correspond pas au comportement de tsc.

Il s'agit d'une limitation du chargeur NodeJS, pas d'un bogue dans TS-Node : https://github.com/TypeStrong/ts-node/issues/783#issuecomment -507437929

Ce n'est pas toujours vrai. Vous pouvez configurer votre serveur pour servir tous les JS, TS et DTS avec un type JS MIME, puis les importer tous séparément en JavaScript et le runtime les exécutera consciencieusement en tant que JS. ESM ne se soucie pas du tout des extensions.

J'en suis très conscient, mais le navigateur n'exécutera pas non plus TypeScript. Il est presque universellement vrai que le fichier que l'environnement charge réellement est un fichier JavaScript.

Ce que je veux dire, c'est que si vous avez déjà une paire .js / .d.ts , disons à partir d'un package tiers, et que vous importez le fichier .js , tsc voir le fichier .d.ts et charger les types. c'est-à-dire, une paire .js / .d.ts _agit_ comme un fichier .ts , et c'est ainsi que cela devrait être, car c'est ainsi que vous pouvez transférer de manière transparente de JavaScript à TypeScript sans changer les importations des fichiers qui sont portés.

Il s'agit d'un bogue dans TS-Node. Cela ne correspond pas au comportement de tsc.

C'est une limitation du chargeur NodeJS, pas un bogue dans TS-Node : TypeStrong/ts-node#783 (commentaire)

C'est toujours un bogue que TS-Node s'écarte du comportement tsc . Cela fait des fichiers .ts qui ne fonctionnent pas à la fois dans tsc et TS-Node, et je considérerais fortement tsc comme le standard que TS-Node devrait suivre .

Mon point est que si vous avez déjà une paire .js/.d.ts, disons à partir d'un package tiers, et importez le fichier .js, tsc verra le fichier .d.ts et chargera les types. c'est-à-dire qu'une paire .js/.d.ts agit comme un fichier .ts, et c'est ainsi que cela devrait être, car c'est ainsi que vous pouvez transférer de manière transparente de JavaScript vers TypeScript sans modifier les importations des fichiers qui sont portés.

Si vous chargez un _package_ externe, vous aurez besoin d'un chargeur de package d'exécution quelconque (par exemple, des cartes d'importation nommées dans le navigateur) qui effectue le mappage du module nommé au fichier de point d'entrée. Cependant, je pense que votre argument est généralement valable, dans le cas où vous avez une paire relative .js/.d.ts. Je ne sais pas si dans ce cas vous devriez faire import ... from './foo.d.ts' ou import ... from './foo.js' .

Le fichier .d.ts est essentiellement un en-tête décrivant la structure qui ne contient aucune information sur l'extension à partir de laquelle il est mappé (l'hypothèse étant que généralement vous ne devriez pas avoir plusieurs fichiers avec le même nom mais des extensions différentes au même endroit, et nous avons une erreur lors de la construction si vous le faites) - même aujourd'hui, la "source" d'exécution associée pourrait être .js ou .jsx (en utilisant jsx: preserve ). Vous ne pouvez pas, en gros, remplacer une référence .d.ts par .js dans une importation au moment de l'émission et supposer que cela fonctionne...

Il est important que tsc ne soit pas trop opiniâtre quant au plus large
hypothèses de construction et de résolution.

Étant donné qu'il s'agit d'un multi-outil sur une frontière complexe, on s'attendrait à
cette configuration pourrait lui permettre de se comporter comme le souhaitent les utilisateurs.

Il y a eu un effort très délibéré pour ne pas exposer les changements de résolution comme
partie du processus de compilation tsc - cela en soi force l'opinion sur
utilisateurs et provoque des frictions dans leurs flux de travail.

Le mercredi 27 novembre 2019 à 16:48 Wesley Wigham [email protected]
a écrit:

Le fichier .d.ts est essentiellement un en-tête décrivant la structure qui contient
aucune information sur l'extension à partir de laquelle il est mappé (l'hypothèse étant que
généralement, vous ne devriez pas avoir plusieurs fichiers portant le même nom, mais
différentes extensions au même endroit) - aujourd'hui encore, les
La "source" d'exécution peut être .js ou .jsx (en utilisant jsx : preserve). Vous pourriez
pas, en gros, remplacer la référence .d.ts par .js dans une importation au moment de l'émission
et supposons que ça marche...


Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/microsoft/TypeScript/issues/16577?email_source=notifications&email_token=AAESFSQS2DQ23RR5KN3RTZ3QV3TLXA5CNFSM4DPRQTY2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFK2TPA#issuecomment-55
ou désabonnez-vous
https://github.com/notifications/unsubscribe-auth/AAESFSUAP2YO23ZFHCOWVQLQV3TLXANCNFSM4DPRQTYQ
.

Je ne sais pas comment gérer ce scénario, mais j'avais un doute lié à la même chose.

J'ai une carte d'importation comme celle-ci dans mon fichier html :

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

Et j'ai mon fichier ts où j'importe un fichier comme celui-ci :

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

Maintenant, cette configuration fonctionne bien dans le navigateur. Mais comment vais-je pouvoir naviguer/l'utiliser dans VSCode ? Je veux dire, je veux ctrl + cliquer sur l'importation et accéder au fichier, obtenir la saisie semi-automatique, taper def, etc.

De plus, étant donné que tsc ne réécrit pas les extensions d'importation de .ts à .js , existe-t-il un autre outil/package recommandé que je peux utiliser pour faire de même au moment de la construction ? Merci.

(J'utilise https://github.com/guybedford/es-module-shims pour les modules ES et les cartes d'importation)

Mais comment vais-je pouvoir naviguer/l'utiliser dans VSCode ?

Recherchez l'option de compilation paths .

De plus, étant donné que tsc ne réécrit pas les extensions d'importation de .ts à .js , existe-t-il un autre outil/package recommandé que je peux utiliser pour faire de même au moment de la construction ? Merci.

Utilisez simplement .js et cela fonctionnera bien, même si vous faites référence à un fichier .ts au moment de la construction.

@tvvignesh https://github.com/Zoltu/typescript-transformer-append-js-extension/ pour réécrire les importations sans extension en .js au moment de la compilation. Personnellement, je ne suis pas fan du "juste mettre .js dans vos fichiers TS" car votre code ne fonctionnera pas dans ts-node si vous le faites. Si vous n'avez pas besoin d'exécuter votre code dans ts-node, l'utilisation de .js fonctionnera.

Mais comment vais-je pouvoir naviguer/l'utiliser dans VSCode ?

Recherchez l'option de compilation paths .

De plus, étant donné que tsc ne réécrit pas les extensions d'importation de .ts à .js , existe-t-il un autre outil/package recommandé que je peux utiliser pour faire de même au moment de la construction ? Merci.

Utilisez simplement .js et cela fonctionnera bien, même si vous faites référence à un fichier .ts au moment de la construction.

Merci pour votre réponse rapide. J'avais déjà défini l'option paths dans tsconfig.json mais je ne parvenais toujours pas à naviguer par ctrl + clic.

Ceci est mon option de chemins dans tsconfig.json

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

Utilisez simplement .js et cela fonctionnera bien, même si vous faites référence à un fichier .ts au moment de la construction.

C'est assez peu pratique lorsqu'il y a des milliers d'importations.

Le problème avec "juste utiliser .js " est que si TypeScript émet des fichiers .mjs , votre programme ne fonctionne pas. Cela signifie que vous vous retrouvez dans une situation où vous écrivez TypeScript qui _soit_ fonctionne dans le navigateur _ou_ fonctionne dans NodeJS. Vous ne pouvez plus écrire de TypeScript qui fonctionne dans les deux.

Je crois que l'argument ici est, "Ce n'est pas la faute de TypeScript, c'est le navigateur et NodeJS divergent".

Node 13.2 prend très bien en charge les extensions .js.

@justinfagnani Pour les modules ES ? Je pensais que NodeJS ne chargerait les modules ES que s'ils avaient une extension .mjs , sinon les fichiers étaient traités comme CommonJS ?

J'ai l'impression que tout ce fil est un peu erroné. L'écriture explicite de l'extension de fichier résoudrait tout ce problème. Si vous importez un fichier JavaScript, écrivez l'extension .js. Si vous importez un fichier TypeScript, écrivez l'extension .ts. Ceci est autorisé dans la norme et le compilateur TypeScript le comprend tout aussi bien. Le seul problème est que le compilateur déclare que les extensions .ts sont des erreurs. Cela n'affecte pas une transpilation pure, mais n'est qu'une erreur de type. TypeScript devrait résoudre ce problème, car une extension de fichier .ts est évidemment valide, puisque nous créons en TypeScript. Pour contourner ce problème, Deno.js a une extension VS Code : https://marketplace.visualstudio.com/items?itemName=justjavac.vscode-deno

Avec l'avènement de WebAssembly, les applications Web vont commencer à importer de plus en plus de types de fichiers. Il deviendra de plus en plus important d'indiquer explicitement si vous importez un fichier .wasm, .js, .ts, .rs, .c, etc.

Quelqu'un a-t-il réellement utilisé le script que j'ai écrit ?

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

des retours si oui ?

@QuantumInformation Je n'ai pas utilisé votre script, mais le plugin de transformateur TypeScript que j'ai écrit fait essentiellement la même chose. 😊 https://github.com/Zoltu/typescript-transformer-append-js-extension/

Tout d'abord, je ne vais pas réessayer de convaincre Tapuscrit de l'implémenter, je comprends, vous ne ferez pas ça.
Cependant, je lis les commentaires et je me demande: toutes ces personnes qui disent que l'ajout .js aux chemins résoudra tout - n'utilisez-vous vraiment pas de packages tiers? Comment est-ce que j'ajoute des extensions à mes importations en corrigeant ce qui se trouve dans node_modules ?

@MicahZoltu oh sympa

Que veux-tu dire? Vous écririez explicitement l'extension de fichier du fichier que vous importez depuis node_modules, si vous utilisez un chemin. Mais ne serait-ce pas une simple importation de toute façon ?

Si vous spécifiez un chemin relatif, il ne sera pas nu. Je parle cependant des importations internes du package que j'importe, regardez rxjs par exemple.

@Draccoz Je pense que le point soulevé est que si quelqu'un écrit TypeScript comme import { ... } from './foo' puis le publie en tant que package NPM, un utilisateur ne peut pas utiliser cette bibliothèque directement dans un navigateur même si elle cible les modules ES. Je crois que l'argument de Microsoft ici est que le package est erroné s'il distribue du code comme celui-ci en s'attendant à ce qu'il fonctionne dans un navigateur.

Vous écririez l'extension du fichier qui existe dans node_modules. import * as stuff from 'rxjs/path/to/file.js'; s'il s'agit d'un fichier JavaScript, et import * as stuff from 'rxjs/path/to/file.ts'; s'ils ont distribué un fichier TypeScript. Cela fonctionne maintenant si je ne me trompe pas

@lastmjs Oui, mais que faire si rxjs/path/to/file.ts contient import foo from './bar' ? Vous ne pouvez pas changer cela, car vous ne pouvez pas modifier le fichier, car il s'agit d'une bibliothèque tierce.

C'est pourquoi nous devrions pousser à utiliser des extensions explicites partout, mais oui, je vois votre point. Mon outil (https://github.com/lastmjs/zwitterion) fait cette réécriture comme une solution provisoire pour les fichiers qui ont laissé des extensions.

Oui, mon point était exactement cela - le simple fait d'ajouter des extensions ne résoudra pas les bibliothèques tierces que nous ne pouvons pas modifier, donc ce n'est pas une solution.
Je comprends également le point de Microsoft, donc je ne le pousse plus (mis à part le fait que garder ce problème ouvert donne un espoir inutile qui empêche les mainteneurs de paquets de simplement ajuster la construction au lieu d'attendre que TS résolve cela), ce serait être génial cependant de n'avoir que du texte dactylographié comme outil de construction et aucune autre dépendance.

ouais mais clairement l'espoir est toujours bon pour beaucoup de gens

image

Pourtant, il a été déclaré à plusieurs reprises dans ces commentaires qu'il ne sera PAS mis en œuvre, alors pourquoi le garder ouvert ?

si quelqu'un écrit TypeScript comme import { ... } à partir de './foo' et le publie ensuite en tant que package NPM

Y a-t-il beaucoup de personnes qui publient des TS non compilés dans des packages NPM ? Je regardais cela pour mon propre usage interne. Je crée des bibliothèques de code commun partagé entre les projets et j'ai pensé que NPM était un moyen raisonnable de les empaqueter, et notre équipe est passée exclusivement à TS, donc je serais heureux d'éviter d'avoir à compiler les deps. Mais il semble que le cas d'utilisation le plus courant consiste à créer le package en JS avec des typages séparés, puis à pointer modules ou main vers le JS et types vers les typages.

Existe-t-il une convention pour la publication de TS non compilé vers NPM ? Si oui, est-ce documenté quelque part ? Je comprends que cela s'écarte du problème d'origine, mais je pense que c'est pertinent pour la réponse, car nous devons savoir si "TypeScript tiers" (packages) est un cas d'utilisation / objectif pris en charge.

@thw0rted Désolé de ne pas avoir été clair, je voulais dire :

... si quelqu'un écrit TypeScript comme import { ... } from './foo' puis transpile cela en JS en utilisant TSC aujourd'hui et publie ce JS en tant que package NPM...

S'il ne sera PAS mis en œuvre, je laisserai à MS le soin de fermer le problème maintenant.

Ah, je comprends maintenant. Oui, lorsque je transpile (avec target: ES2018 ) le JS émis laisse l'extension hors de l'instruction d'importation, mais cela fonctionne pour moi car le consommateur met tout via webpack/babel et il doit remplir l'extension manquante pour moi. Je suis au courant maintenant. Il ne m'était même pas venu à l'esprit que mon "paquet" ne fonctionnerait pas nativement dans le navigateur sans passer par Webpack au préalable.

Ouais, c'est difficile.

@thw0rted Je n'utilise pas webpack/babel, donc résoudre .js à partir de la boîte est un problème pour moi.
Une solution/contournement consiste à configurer le serveur Web pour les sources de résolution par défaut .

Désolé si je répète ce que d'autres ont dit, mais c'est quelque chose que je traite tous les jours, alors j'aimerais ajouter un autre de mes deux cents non sollicités.

Je sais que TypeScript n'a pas à répondre à un environnement particulier (Node.js, Webpack, etc.) mais le fait est qu'il existe de nombreux environnements où l'extension est toujours nécessaire, sauf configuration spéciale, donc je ne Je ne pense pas qu'ils doivent être ignorés. Les importations ne sont plus derrière un indicateur dans Node et le chemin d'importation doit correspondre au nom de chemin de l'URL sur le Web. Bien qu'il n'y ait aucun besoin technique d'avoir .js à la fin d'une URL, c'est la norme de facto.

Si les gens sympas de Microsoft veulent vraiment qu'aucune extension de fichier ne soit la valeur par défaut, je n'en discuterai pas. Vous êtes probablement plus intelligent que moi, mais je serais certainement plus heureux si, au lieu de déduire si des extensions sont nécessaires ou non en fonction d'autres importations dans le même fichier, cela pourrait être défini à l'échelle du projet afin que cela fonctionne pour les saisies semi-automatiques Intellisense pour le premier import ajouté à un fichier !

En attendant, est-ce que quelqu'un connaît des plugins VSCode qui résolvent ce problème ? L'ajout d'import/extensions à eslint est le mieux que j'ai pu faire pour gérer cela.

Actuellement, j'écris des lignes import sans extension .js, puis j'utilise sed pour ajouter l'extension .js dans les fichiers de sortie.
https://github.com/yoursunny/NDNts/blob/9f50fcec245b33c7649fa815bbb3dd404eee160e/mk/build.sh#L12 -L14
Je dois supprimer SourceMaps lors de la construction de production, car ils ne correspondraient plus après la modification des fichiers de sortie.

Je ne peux pas écrire l'extension .js dans les fichiers source .ts car elle casse ts-jest .
Bien qu'il soit possible d'exécuter Jest sur des fichiers .js compilés, cela casse Coveralls .

@yoursunny Oui, sed est une variante (je l'ai aussi utilisé mais je préfère remplacer dans le fichier à cause de la configuration qui peut être configurée par le mappage de fichiers importmap) pour remplacer les chaînes dans les fichiers js générés, mais ça ne sent pas bon =) Peut-être l'ajout d'extensions sera une fonctionnalité/option utile pour ttypescript avec le plugin de transformation (par exemple , typescript-transform-paths par @MicahZoltu).

@richardkazuomiller cette partie n'est pas vraie :

Si les gens sympas de Microsoft veulent vraiment qu'aucune extension de fichier ne soit la valeur par défaut

TypeScript uniquement :

  1. Permet une résolution de module de style Node-require (ils devraient l'étendre pour permettre une résolution de style Node-import, qui nécessite des extensions de fichier).
  2. Dans la même unité de compilation, résout les fichiers .js en une paire .js/.d.ts avant même qu'ils ne soient générés par le compilateur.
  3. Ne modifie pas les spécificateurs d'importation _du tout, jamais_.

La solution à tout cela consiste donc à simplement importer les fichiers .js avec l'extension .js . TypeScript résoudra le bon fichier .ts et ne modifiera pas le spécificateur d'importation, donc les choses fonctionneront simplement dans les navigateurs et Node >= 13.2.

@yoursunny avez-vous signalé un bogue contre ts-jest ? Ils s'écartent ici de la norme TypeScript de facto. Cela ressemble également à un bogue dans Coveralls s'il ne peut pas utiliser les cartes source sur les fichiers .js.

avez-vous signalé un bogue contre ts-jest ? Ils s'écartent ici de la norme TypeScript de facto.

Non, car je ne comprends pas parfaitement le fonctionnement de la résolution ts-jest.

Cela ressemble également à un bogue dans Coveralls s'il ne peut pas utiliser les cartes source sur les fichiers .js.

Coveralls reçoit un rapport lcov de mon processus de construction, puis affiche la couverture du code à l'aide de fichiers validés sur GitHub.
Je ne valide pas les fichiers de sortie .js sur GitHub. Si j'exécute des tests unitaires sur des fichiers .js, le rapport lcov référencera les fichiers .js qui n'existent pas sur GitHub.
Par conséquent, Coveralls est incapable de trouver les fichiers source. Il affichera le pourcentage de couverture, mais ne peut pas montrer quelles lignes ne sont pas couvertes.

La nouvelle ère est là !

Le nouveau Node.js v13 et tous les principaux navigateurs prennent en charge les modules ES natifs prêts à l'emploi, et il serait formidable que TypeScript prenne en charge ces environnements de manière simple.

La solution la plus simple pour les cas d'utilisation les plus élémentaires (un site Web servi via un simple serveur de fichiers statiques) serait d'ajouter une nouvelle option de compilateur comme "appendJsExtension": true ou similaire.

@mjbvz Le problème dans le référentiel de VS Code que vous avez fermé est légèrement différent : il s'agit d'utiliser la saisie semi-automatique pour ajouter automatiquement des instructions d'importation ; lorsque VS Code le fait, il ajoute l'instruction d'importation sans extension .js , et il est facile de l'ignorer jusqu'à un échec d'exécution.

Cependant, si TypeScript ajoute une option comme "appendJsExtension": true ou similaire, cela n'aura pas beaucoup d'importance et nous pourrons écrire du code TS sans .js dans la source.

Peut-être que le plugin VS Code devrait avoir une option pour activer/désactiver l'ajout automatique des extensions .js dans les instructions d'importation complétées automatiquement ?

@mjbvz Le problème VS Code / Intellisense est lié, mais ne doit pas être fermé en tant que dupe. Si ce problème est finalement fermé en tant que WONTFIX, cela augmenterait en fait l'importance du problème du code VS.

Je vois un point négligé et je ne comprends pas comment les solutions où l'extension JS est en boîtier spécial résoudraient cela: pour ESM, aucune extension n'a un statut spécial, même les fichiers sans extension sont tout à fait corrects tant que le serveur les sert au navigateur avec le type MIME text/javascript approprié. Cela signifie que le code tel que:

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

Tout cela est valable tant que les fichiers (indépendamment de leurs extensions) contiennent du code JavaScript et sont servis au navigateur avec le type JavaScript MIME.

Étant donné que TypeScript devrait être un sur-ensemble de JavaScript sécurisé, je ne vois pas comment autoriser les importations telles que celles ci-dessus, car le code est un JavaScript valide et si TypeScript ne l'accepte pas, il cesse d'être un sur-ensemble sûr. de JavaScript, n'est-ce pas ?

Donc, les solutions où l'extension JS est implicite ou la seule autorisée, je ne pense pas, peuvent réduire cela? De plus, même les extensions TS et DTS IMO ne peuvent pas être dans un cas particulier, car bien que ce ne soit normalement pas le cas, elles pourraient contenir du code JavaScript, pas du code TypeScript et servir au navigateur en tant que tel sans aucun problème en ce qui concerne ESM. , étant donné qu'ils sont servis avec le bon type MIME.

Ai-je raté quelque chose sur ce front? Est-il possible que TypeScript ne prenne pas en charge les extensions arbitraires (y compris manquantes) dans les importations de code, et est-il possible que TypeScript continue à supposer des extensions TS dans les importations de modules, étant donné que file.ts et file (pas d'extension) entraînerait alors un conflit ?

Les travailleurs du Web et des services bénéficient également d'un support pour l'import/export du module ES .

Je soutiens et approuve pleinement l'idée de @trusktr de mettre en œuvre leur idée en tant qu'option de compilateur. Ce n'est pas que je veuille me débarrasser des bundlers comme webpack et rollup. Mais je crois qu'une fonctionnalité comme celle-ci supprimera beaucoup de tracas et de temps passé à configurer des bundlers, alors que tout ce que vous voulez, c'est compiler un projet Typescript simple sans sauter à travers des cerceaux ou utiliser des solutions de contournement gênantes.

Veuillez considérer cela comme une option pour le compilateur Typescript. <3

Est-ce que quelqu'un connaît un moyen d'exécuter les fichiers js individuels compilés dans un navigateur sans webpack ou --outFile , en utilisant n'importe quel type de système de module ?

Mon problème est le suivant: le projet TypeScript assez volumineux avec lequel je travaille prend environ 35 secondes pour être compilé avec webpack dans un fichier js fourni en utilisant ts-loader .
La seule façon d'optimiser cela était d'utiliser transpileOnly qui réduisait le temps de compilation à 20 secondes, mais c'est toujours lent et je perds la vérification de type.
En me débarrassant de webpack, je pourrais obtenir environ 14 secondes en utilisant outFile mais c'est encore trop lent pour moi. L'utilisation incremental n'a fait aucune différence.

La seule façon d'obtenir quelques secondes de temps de compilation était d'émettre 1 fichier js pour 1 fichier ts et d'utiliser le drapeau incremental . Dans ce cas, j'imagine que ts détecte et compile uniquement les fichiers qui ont vraiment changé. Le problème est que je n'ai pas pu le faire fonctionner dans un navigateur dans aucune des cibles de module que j'ai essayées : system, amd, es6.
J'utilise le mappage paths dans tsconfig.json et dans les fichiers js compilés, les erreurs que j'obtiens sont principalement liées à l'impossibilité de résoudre ces alias.

Y'a-t-il une quelconque façon de réussir cela?

@andrewvarga J'exécute actuellement tous mes TypeScript compilés directement dans le navigateur sans regrouper ni compiler dans un seul fichier. La façon la plus simple de procéder est la suivante :

  1. Assurez-vous que toutes les importations dans les fichiers TypeScript ont l'extension .js .
  2. Exécutez un serveur de développement qui résout les importations de noms de packages npm pour les dépendances, si nécessaire. es-dev-server est le plus simple que je connaisse.
  3. Exécutez tsc --watch (assurez-vous que le module est esnext dans votre tsconfig)

C'est ça. Si vous écrivez simplement l'extension .js pour les importations dans votre TypeScript, vous n'avez pas besoin d'autres outils pour réparer les fichiers pour les navigateurs.

@justinfagnani mate, vous avez oublié l'information la plus importante - les types doivent être au format jsdoc, toute abstraction dactylographiée sur JavaScript natif fera échouer l'analyseur.

@Draccoz tsc affichera JavaScript, pas TypeScript.

@andrewvarga Le moyen le plus simple que je connaisse pour transpiler sans regrouper est mon projet Zwitterion . Il est conçu pour remplacer un serveur de fichiers statique, afin que vous n'ayez pas à modifier votre façon de développer. Vous pouvez importer et exporter avec des extensions de fichier explicites (.js pour JavaScript et .ts pour TypeScript), même dans des éléments de script. Il est très performant, effectue la mise en cache et le rechargement automatique lorsque les fichiers changent. Vous devrez cependant vous fier à votre éditeur pour l'analyse statique (erreurs de type)

@andrewvarga J'utilise https://github.com/Zoltu/typescript-transformer-append-js-extension/ et cible les modules ES natifs qui se chargent dans tous les navigateurs modernes (sauf Safari, le nouveau IE).

Si vos dépendances NPM d'exécution sont assez limitées, vous pouvez les charger avec es-modules-shim sans aucun regroupement. Vous pouvez voir un modèle de réaction que j'ai créé et qui montre que tout cela fonctionne ensemble : https://github.com/Zoltu/react-es2015-template

@MicahZoltu Safari prend en charge le module ES, je sais que c'est un fait, basé sur l'expérience caniuse et personnelle : https://caniuse.com/#search =modules

@justinfagnani awww désolé, j'ai raté la partie "TypeScript compilé", je pensais que vous parliez du typescript jsdoc.

Merci à tous pour les différents conseils !

Ce que j'ai trouvé, c'est qu'en utilisant le module hard-source-webpack-plugin npm pour webpack et transpileOnly: true dans les options ts-loader, le temps de construction est réduit à environ 4-5 secondes.
Bien sûr, cela ignorera les erreurs de dactylographie, donc ce n'est utile que pour des itérations rapides de construction, d'essai dans le navigateur et de s'appuyer sur l'IDE pour toute erreur potentielle, mais je pense que c'est très utile pendant le développement.

Pour obtenir à la fois les erreurs TS et une compilation rapide, je pense toujours que le seul moyen serait d'exécuter des modules dans le navigateur, mais le manque de prise en charge des extensions import-maps et js a rendu cela difficile.
@justinfagnani @MicahZoltu merci, je vais essayer ces options. En général, je préfère éviter d'utiliser un module npm de plus, mais cela semble inévitable.

J'ai aussi essayé de le faire fonctionner en utilisant systemjs mais je suis resté bloqué avec des cartes d'importation ..

@andrewvarga Vous pouvez essayer SystemJs par mon exemple léger avec importmap.
Vous pouvez également essayer mon exemple lourd - alternative systemjs & esm, mais les importmaps esm ne sont pas pris en charge par native, et nous devrions résoudre les modules manuellement (gulp-replace), ou vous pouvez essayer es-module-shims .

Donc, si j'utilise tsc comme mon seul compilateur, ciblant esnext ou es2015 comme type de module. Existe-t-il un moyen d'utiliser la sortie directement dans mon navigateur ?

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

Si je comprends bien le reste de ce fil, Typescript devrait être parfaitement heureux de compiler votre code si vous modifiez cette ligne pour dire from "./module.js" . Ensuite, le index.js compilé aura une instruction d'importation ES6 valide et tout devrait fonctionner.

C'est à moins que vous n'importiez une bibliothèque qui ne sait pas comment importer ES ou qui s'en moque :P.

J'ai créé un plugin pour Gulp qui ajoute .js pour importer des chemins de fichiers. (également une résolution de chemin ts bonus).

J'ai utilisé Gulp parce que je ne connais aucun autre exécuteur de tâches qui me permettrait d'attacher essentiellement une simple étape de post-traitement au compilateur tsc (à la fois en mode montre et en mode normal). Webpack et rollup sont tous deux exclusivement groupés, et je souhaite émettre des modules es.

Cela fonctionne mais c'est lent à regarder car il semble reconstruire le tout.

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

Cela devient de plus en plus important car l'équipe de nœuds a décidé de ne pas importer sans extension
https://github.com/nodejs/modules/issues/444

Ajouter des cartes d'importation également décidées contre les importations sans extension
https://github.com/WICG/import-maps/issues/194

Si nous voulons utiliser le module es compilé dactylographié dans un navigateur ou un nœud, nous devons ajouter des extensions par dactylographie? (pour les modules internes) et manuellement pour les modules externes ? @weswigham

@chyzwar encore une fois, si vous écrivez simplement les extensions .js dans votre source TypeScript, la sortie compilée aura les extensions correctes et les modules fonctionneront dans les navigateurs et Node. Vous n'avez pas besoin d'outils de transformation supplémentaires ou de tsc pour faire quoi que ce soit pour vous.

Il est plus simple pour le développeur de faire ce qui suit : S'il s'agit d'un fichier source TypeScript, écrivez une extension .ts. S'il s'agit d'un fichier source JavaScript, écrivez une extension .js. Cela compilera et fonctionnera également correctement dans le navigateur (.ts aura besoin d'un type MIME application/javascript). L'extension doit correspondre au type de fichier source. Les modules tsc et ES peuvent gérer cela (au moins les modules ES dans le navigateur, espérons que Node.js suit la même chose)

@justinfagnani tsc est assez satisfait de cela, et il est juste de dire "pas notre problème" ici, mais il ne semble pas y avoir de consensus ici sur ce qui est juste,

Entre tsc, vscode, webpack et ts-node, personne ne peut vraiment s'accorder contre une norme qui vient tout juste de devenir disponible en mode natif (navigateur et nœud désormais disponibles).

Exemple 1

Je souhaite écrire un package javascript moderne, le créer en tapuscrit et supprimer les types pour distribution en tant que module ecmascript (en conservant les instructions d'importation et d'exportation).

Exemple 2

Je construis un site Web statique en utilisant des modules dans vscode, par défaut, il importera automatiquement sans extension pour chaque première importation et vous devez l'ajuster manuellement.

Dans ces cas, tsc peut gérer cela, et même exporter des fichiers de descripteurs de côté qui prennent en charge la consommation de la distribution du module es à partir de tapuscrit avec des typages complets (génial).

Mais si je veux exécuter du code de test sur la source, je pourrais utiliser ts-node mais ici ts-node n'est pas content.

De même, le fait que tsc, vscode et webpack ont ​​évolué pour faire ce qui suit :

  1. importations automatiques vscode sans extension
  2. tsc se fera un plaisir de réécrire les importations dans un fichier js comme signifiant le fichier ts
  3. webpack fait ici diverses magies pour les extensions par défaut à rechercher

Sont toutes des choses qui devraient être remises en question maintenant que quatre implémentations (chrome, firefox, safari, node) s'attendent toutes à ce que le chemin d'importation pointe vers quelque chose qui peut se résoudre directement en un fichier.

L'ajout .js à une importation devrait être une solution de contournement temporaire, pas une solution définitive. Si quoi que ce soit, cela ressemble à un hack. Une façon de tromper le compilateur. Et essayer de déjouer un compilateur est une idéologie horrible à suivre à mon humble avis. Je ne peux qu'imaginer à quel point cela doit être déroutant pour les personnes qui découvrent Typescript. Un langage qui devrait aider les développeurs Javascript à écrire _meilleur_ code.

Comme nombre de personnes l'ont déjà mentionné, si vous ajoutez .js à l'importation, TypeScript les affichera et tout fonctionnera (au moins dans votre code). Raisonner que tsc devrait ajouter des extensions parce qu'elles ne fonctionnent pas dans le navigateur revient à demander à TypeScript de corriger les erreurs d'exécution causées par le développeur - ok, mais pourquoi le développeur ne peut-il pas les réparer lui-même ?
Ne vous méprenez pas, j'aimerais que tsc soit ma seule dépendance de développement, mais certaines choses n'arriveront tout simplement pas et resteront comme un rêve.

J'aimerais que tsc soit ma seule dépendance de développement, mais certaines choses n'arriveront tout simplement pas et resteront comme un rêve.

J'ai dû voir des dizaines de commentaires presque identiques sur plusieurs années sur # 3469, dont certains de l'équipe Typescript. "C'est un vérificateur de type, il est censé bien faire une chose, ne vous attendez pas à ce qu'il remplace toute votre chaîne d'outils..." Cela a pris 3 ans, mais ils ont quand même ajouté le mode de construction, car il a été prouvé que c'était la bonne direction à prendre.

Webpack et rollup sont tous deux exclusivement groupés, et je souhaite émettre des modules es.

@alshdavid Rollup peut fonctionner pour vous si vous définissez le format de sortie sur esm et définissez preserveModules sur true : https://rollupjs.org/guide/en/#preservemodules

peut-être que les importations "sans extension" étaient un péché originel, non compatible avec le fonctionnement des navigateurs

il est maintenant temps de corriger notre code source et d'inclure les extensions .js : nous constatons que lorsque vous ajoutez des extensions .js à votre code source aujourd'hui, tout fonctionne : le navigateur est satisfait, le texte dactylographié est agnostique, et les groupeurs s'en foutent

alors peut-être que sans extension était une faille dans notre code source que notre ancien outillage compensait

Écrire l'extension .js dans les importations dans le code source dactylographié est un non-sens complet. Cela fonctionne, cela préserve l'extension dans la sortie, mais cela échouera probablement avec des erreurs "Impossible de résoudre le fichier" dans les règles ESLint (ou TypeScript) dans VSCode ou dans l'éditeur que vous utilisez. Sans parler du moment où vous testez par rapport à ce code source tapuscrit. Ensuite, l'outil de test devrait également connaître ce comportement de conneries. Je suis presque sûr qu'il lancera des erreurs qu'il ne peut pas résoudre les fichiers.

Exemple de base

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

src/foot.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);
});

Désolé pour l'utilisation "conneries", mais c'est la vérité.

Je ne pense pas qu'il soit si difficile d'implémenter l'option de base que lorsque le compilateur voit l'extension ( .ts ) dans les importations pour la convertir en .js (ou même éventuellement permettre de spécifier ce que la sortie ext à être). Lorsqu'il n'y a pas d'extension, ne conservez pas les extensions (comportement semi-courant ?).

Écrire l'extension .js dans les importations dans le code source dactylographié est un non-sens complet. Cela fonctionne, cela préserve l'extension dans la sortie, mais cela échouera probablement avec des erreurs "Impossible de résoudre le fichier" dans les règles ESLint (ou TypeScript) dans VSCode ou dans l'éditeur que vous utilisez.

Ce n'est tout simplement pas vrai. ESLint, TypeScript, VS Code et tous les autres outils liés à TypeScript que j'ai utilisés _just work_ avec cette méthode. Ce n'est pas un hack, et il y a une justification très raisonnable autour de lui : que le fichier que vous importez est en fait le fichier .js , et que vos extensions ne doivent pas changer simplement parce qu'un fichier importé fait partie du fichier local projet, ou pré-compilé dans le cadre d'un package tiers.

Encore une fois, j'écris tout mon code TypeScript de cette façon et cela résout tous les problèmes soulevés dans ce fil. La sortie fonctionne très bien dans les navigateurs et Node. Ce n'est pas des conneries, ça marche, _aujourd'hui_.

Non ce n'est pas. Au moins dans le cas le plus courant où le répertoire de sortie est dist ou build ou lib et etc. Vos fichiers compilés ne sont pas dans le même répertoire, ils n'existent tout simplement jamais là (dans src/ ) - ni pendant les tests, ni pendant le codage dans l'éditeur.

Avoir/voir et importer ./foo.js dans les src/index.ts ci-dessus n'a AUCUN sens pour moi - sauf bien sûr si vous voulez vraiment importer le fichier js/json, ce qui est tout à fait acceptable. Mais écrire ./foo.js quand vous voulez vraiment dire un autre fichier source dactylographié ( ./foo.ts ) est... brutal. C'est trompeur et déroutant, et certainement faux.

Je suis presque sûr que si j'exécute le test/index.ts ci-dessus avec Jest, il échouera avec l'erreur qu'il ne peut pas trouver/résoudre ./foo.js car il n'y a que ./foo.ts .

Si nous laissons tout de côté, pourquoi est-il permis d'avoir l'extension .js mais pas .ts (ts report error in the editor) ? C'est une incohérence basique, simple et stupide. Comme beaucoup d'autres problèmes "juste parce que" dans TypeScript.

En fait, j'ai perdu la logique pour laquelle ce problème est nommé de cette façon alors qu'il est en fait possible de se terminer avec l'extension .js . Je pense que le problème est tout le contraire - qu'il ne peut pas se terminer par .ts (à partir de 3.7+)

pourquoi l'extension .ts dans les importations est totalement interdite ? !

Et clarifions. Je parle du temps de développement et de l'expérience. Je comprends pourquoi nous pouvons conserver l'extension .js dans la sortie compilée, et pourquoi nous pouvons ajouter .js ext aux importations dans un fichier .ts sans signaler d'erreurs, et je Je suis d'accord avec ça.

TypeScript est un sur-ensemble de JavaScript mais ce n'est pas du JavaScript. JavaScript est une cible de compilation pour TypeScript.

Dans cet esprit, malgré le fait que TS compilera en JS, je m'attendrais à ce que le code TypeScript se comporte de manière entièrement autonome.

L'écriture d'un .js lors d'une tentative d'importation d'un fichier .ts suppose la connaissance du type de compilation cible et suppose que la cible de compilation est toujours JavaScript.

Que se passe-t-il si nous compilons TypeScript dans un binaire d'assemblage Web ou exécutons du code TypeScript à l'aide d'un environnement d'exécution alternatif tel que Deno ou ts-node.

Les instructions d'importation se terminant par .js n'ont aucun sens dans de tels contextes.

Je préférerais être obligé de taper .ts dans mes chemins d'importation ou de ne pas avoir d'extension spécifiée pour un fichier source TypeScript.

C'est triste que le tapuscrit ait inventé sa propre extension au lieu d'être juste un sucre de syntaxe comme le flux.

@phaux Je ne voudrais jamais travailler avec un projet qui mélange des fichiers source et dist sous la même extension, même s'ils résident dans des dossiers différents. C'est comme nommer tous les fichiers index.js seulement parce qu'ils vivent dans des dossiers différents...

Ce problème (qui est plus important que TypeScript) semble empêcher IntelliSense de Visual Studio Code de fonctionner dans les navigateurs Web et Node, ce qui nécessite des chemins de fichier complets (relatifs) dans les spécificateurs d'importation. Sans cela, les instructions import générées qu'il crée ne fonctionnent qu'avec des transpilers et des bundlers, comme WebPack et TypeScript lui-même.

La réponse de l'équipe VSCode a été que les extensions doivent être ajoutées par le code qui fournit des suggestions d'importation automatique. Je soupçonne qu'il s'agit du serveur de langage TypeScript (et non tsc , sur lequel porte la discussion ici).

Quelqu'un qui sait réellement les choses peut-il confirmer (ou corriger) que VSCode reçoit des suggestions d'importation automatique du serveur de langage TypeScript ?

la situation est un peu compliquée et nuancée, alors que les extensions ".js" vont initialement à l'encontre des intuitions et des idéaux élégants de nombreuses personnes, il peut être imprudent et déroutant que le texte dactylographié s'écarte beaucoup des normes de navigateur ratifiées et des implémentations livrées

alors peut-être considérons-nous le paradigme actuel comme suit :
les importations dactylographiées décrivent ce qui est importé au moment de l' exécution - c'est-à-dire que vos importations s'exécutent dans votre répertoire "dist", pas "src" - comme les appels fetch et le reste - si nous pouvons tolérer cette idée, le reste devient simple et cohérent

il semble certainement une mauvaise idée d'avoir dactylographié joignant aveuglément ".js" aux importations sans extension comme node le fait pour commonjs (il convient de noter que la prise en charge de node esm nécessite ".js" de la même manière que le dactylographié aujourd'hui) - aveuglément attacher ".js" créerait de nouveaux problèmes, comme l'importation de fichiers javascript vraiment sans extension, ou même d'autres types de fichiers comme css ou json - cela rendrait les extensions significatives et nécessiterait une logique d'analyse spéciale, créant une différence nette entre la sémantique du navigateur et celle du tapuscrit - et nous n'allons évidemment pas pour réécrire les appels fetch la même manière, alors peut-être que import devrait rester similaire ?

cependant, je me demande - est-il relativement inoffensif pour le tapuscrit de convertir les extensions ".ts" en ".js"?

bien sûr, cela rendrait impossible l'importation d'un fichier javascript avec une extension ".ts" - mais peut -être que c'est un peu de magie funky que nous pourrions tolérer ? d'un autre côté, c'est une différence idiosyncrasique magique géniale entre la sémantique du navigateur et celle du tapuscrit que les développeurs devraient apprendre et comprendre (créant sûrement des gotchya étranges) - donc mon instinct est de laisser les choses là où elles se trouvent aujourd'hui

d'un autre côté, si nous gardons les choses telles quelles, la magie est simplement déplacée vers le tapuscrit, qui doit relier les importations ".js" aux fichiers source ".ts" correspondants - cela me semble être un emplacement plus raisonnable pour abrite la magie, étant interne au tapuscrit au lieu de piétiner la sémantique du navigateur

🥃 chasse

@rconnamacher , @TomasHubelbauer

Ce problème (qui est plus important que TypeScript) semble empêcher IntelliSense de Visual Studio Code de fonctionner dans les navigateurs Web et Node, ce qui nécessite des chemins de fichier complets (relatifs) dans les spécificateurs d'importation. Sans cela, les instructions d'importation générées qu'il crée ne fonctionnent qu'avec des transpilers et des bundlers, comme WebPack et TypeScript lui-même.

je pense qu'il y a juste une certaine confusion ici - il est très possible aujourd'hui de créer une bibliothèque ou une application dactylographiée qui fonctionne très bien avec vscode et intellisense, qui fonctionne dans les navigateurs et les nœuds, et fonctionne dans esm ou commonjs - une solution vraiment universelle est possible aujourd'hui

j'ai travaillé sur une poignée de bibliothèques ouvertes qui présentent cela - renraku , cynic , redcrypto , autoritaire

Envoyez-moi un e-mail et je serais heureux de vous expliquer plus

:wave: poursuite

Un autre point est qu'il en résulte une confusion dans le fichier auquel vous accédez. Il existe déjà une ambiguïté sur ce que tsc regarde après la résolution du module lorsque vous avez un fichier .js et .ts côte à côte.

/folder
  a.ts
  a.js
  index.ts

Si dans index.ts , lors de l'utilisation moduleResolution: 'node'

// 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` 

Il y a déjà une ambiguïté sur ce que tsc regarde après la résolution du module lorsque vous avez un fichier .js et .ts côte à côte.

OK, bien sûr, en quelque sorte, mais si a.js est autre chose que la version transpilée de a.ts alors quelque chose a mal tourné et ce n'est pas la faute de TypeScript.

@thw0rted si vous compilez dans un seul fichier de bundle JS, TypeScript ne générera pas d'homologues JS pour les fichiers TypeScript d'entrée, uniquement le fichier de bundle unique. Dans ce cas, il est tout à fait légal d'avoir un fichier JS pour et un fichier TS du même nom qui ne correspondent en rien.

Ce n'est pas "illégal", mais cela ne veut pas dire que c'est une bonne idée. Avez-vous un exemple concret d'où vous voudriez réellement cela ?

Ce serait simplement bien d'utiliser TypeScript sans bundlers, loaders et d'une manière qui émet du JavaScript qui peut être utilisé directement par les navigateurs modernes.

Par exemple:
https://github.com/alshdavid/tsc-website

Mais je ressens la douleur du problème. L'équipe TypeScript ne souhaite pas implémenter la résolution de module. C'est la même raison pour laquelle le compilateur TypeScript ne peut pas convertir paths en leurs chemins relatifs réels au moment de la compilation.

La conversion d'une importation de .ts en .js ou l'ajout d'un .js à une importation sans extension signifie que l'équipe TypeScript implémenterait la résolution de module, ce qui est hors de portée.

Une solution pour cela est que l'équipe TypeScript fournisse un moyen d'introduire des extensions afin que nous puissions implémenter ces choses.

Une solution pour cela est que l'équipe TypeScript fournisse un moyen d'introduire des extensions afin que nous puissions implémenter ces choses.

Ils le font, il n'est tout simplement pas exposé via tsc (uniquement via l'invocation programmatique du compilateur). Heureusement, quelqu'un a construit un wrapper autour du compilateur principal qui fonctionne _exactement_ comme tsc sauf qu'il prend en charge les extensions via la configuration. En utilisant ce wrapper tsc, vous pouvez utiliser une extension comme https://github.com/Zoltu/typescript-transformer-append-js-extension/ pour ajouter automatiquement l'extension .js .

@alshdavid votre exemple dans GitHub fonctionne dans les navigateurs sans bundler si vous incluez simplement l'extension .js sur les importations. J'ai déposé un PR pour y remédier.

@alshdavid Peut-être êtes-vous intéressant dans mon exemple de projet (esm for modern & IE11 with SystemJS).
Mais je suis obligé de résoudre manuellement les modules esm =(

Je n'ai aucun problème en principe à mettre .js dans tous mes import s, mais malheureusement cela expose une mauvaise interaction avec certains outils. Par exemple, ts-node s'étouffe : https://github.com/TypeStrong/ts-node/issues/783. Il ne semble pas y avoir d'accord clair sur la responsabilité de qui en est - TypeScript pour émettre l'extension .js (dans certaines circonstances) ou chaque outil qui consomme des sources TypeScript pour effectuer la traduction. Et tant que tout le monde se renvoie la balle, les utilisateurs souffrent de plugins mal documentés ou de travailleurs de service maladroits pour contourner les incompatibilités d'interopérabilité.

Y a-t-il des mises à jour à ce sujet ? Honnêtement, je ne peux pas croire qu'il ne semble pas possible d'utiliser TypeScript normalement aujourd'hui sans un chargeur de module externe ou un bundler comme Webpack. Cela me semble tellement bizarre et aussi frustrant. Si je dois utiliser un module externe pour que TypeScript fonctionne pleinement, cela devrait être démarré.

J'essaie de l'utiliser dans mon application Electron, c'est pourquoi je ne vois pas de raison d'utiliser un bundle Web et je voudrais également ne pas installer de chargeur de module externe s'il n'est pas nécessaire. Mais cela me rend fou. Ne même pas être en mesure d'obtenir une configuration de base TypeScript + Electron bien que les deux soient salués partout comme étant la meilleure solution sur le marché. C'est fou, pour être honnête. Je ne sais pas s'il me manque quelque chose, mais ne pas pouvoir trouver une solution adéquate est plus que frustrant.

Et si ce n'est vraiment pas moi, je ne comprends pas pourquoi ce problème n'a pas été résolu en 3 ans ...

J'ai récemment terminé le didacticiel Typescript, puis lorsque j'ai essayé de créer des fichiers ts, j'ai rencontré ce problème. Je suis complètement nouveau dans ce monde js-ts, alors pardonnez-moi si quelque chose est faux ou trompeur / mal informé.

ce que j'ai fait était, lors de l'importation

Je viens de mettre l'extension .js dans le fichier ts , puis lorsque j'ai vérifié l'intellisense, cela a également fonctionné lorsque je l'ai transpilé à l'aide de tsc, il a également ajouté l'extension .js au fichier de sortie généré.

Voici ce que j'ai fait.
tsc -p tsconfig.json

{
"optionscompilateur": {
//"module": "amd",
"module": "es6",
"cible":"es6",
"noImplicitAny": faux,
"removeComments": vrai,
"preserveConstEnums": faux,
//"outFile": "js",
"outDir":"js",
"sourceMap": faux
},
"inclure": [
"testscript.ts"
]
}

Bien que cela ait fonctionné pour moi.

Mon doute est que puisqu'il n'y a pas de svgwrapper.js à importer depuis
pourquoi/comment cela a-t-il fonctionné ? (Je suppose qu'il ne prend pas en compte l'extension)

Je joins la capture d'écran pour référence.

ts-js-ext-issue

@yogeshjog c'est exactement comme ça que tsc est et est censé fonctionner. Vous importez le module avec le nom de fichier qui sera généré. Que le module importé soit écrit à l'origine sous la forme d'un fichier $# .ts ou d'une paire .d.ts / .js ne devrait pas être observable à partir du module d'importation.

@yogeshjog c'est exactement comme ça que tsc est et est censé fonctionner. Vous importez le module avec le nom de fichier qui sera généré. Que le module importé soit écrit à l'origine sous la forme d'un fichier $# .ts ou d'une paire .d.ts / .js ne devrait pas être observable à partir du module d'importation.

Merci! @justinfagnani pour clarification 👍

Vous importez le module avec le nom de fichier qui sera généré.

Mais TypeScript permet également d'omettre l'extension, ce qui n'est pas autorisé selon ECMAScript. Il omet même l'extension lors de l'utilisation de la fonction d'importation automatique dans VSCode, ce qui est la chose la plus ennuyeuse. Vous écrivez du JS et TS dit que tout va bien, puis il se bloque lors de l'exécution.

Mais TypeScript permet également d'omettre l'extension

Lors de l'utilisation de la résolution de nœud. tsconfig est au moins configuré pour autoriser d'autres modes de résolution qui avertiraient à ce sujet, mais je crois comprendre que l'équipe a laissé la prise en charge du module natif s'installer avant d'ajouter d'autres modes.

ce qui n'est pas autorisé selon ECMAScript.

ECMAScript ne dit rien sur les spécificateurs d'importation. C'est laissé aux environnements hôtes comme HTML et Node. TypeScript prend en charge la résolution des nœuds lors du chargement des modules et interprète la résolution par rapport au compilateur _output_, et non au compilateur _input_. De cette façon, les spécificateurs fonctionnent après la compilation et ils fonctionnent indépendamment du fait que vous essayiez d'importer un module compilé ou non.

Parce que TypeScript utilise la résolution de nœud qui effectuera une recherche de chemin pour retourner './foo' info './foo.js' , './foo' est valide. Mais la résolution de nœud ne transformera pas './foo.ts' en './foo.js' , donc './foo.ts' n'est pas valide.

Mais c'est dans la résolution de Node. Si vous essayez d'utiliser un autre environnement comme HTML ou le support de module natif de Node, alors TypeScript et l'hôte ne seront pas d'accord sur ce qui est valide.

Espérons que la prise en charge du module natif soit suffisamment réglée maintenant pour que TypeScript ajoute un autre paramètre de résolution.

@leontepe Vous n'avez pas besoin d'un bundler/loader. Vous pouvez soit utiliser https://github.com/Zoltu/typescript-transformer-append-js-extension/ (ma solution préférée) ou vous pouvez ajouter .js à toutes vos instructions d'importation (attention : cela faire échouer votre code dans ts-node ).

@leontepe Vous n'avez pas besoin d'un bundler/loader. Vous pouvez soit utiliser https://github.com/Zoltu/typescript-transformer-append-js-extension/ (ma solution préférée) ou vous pouvez ajouter .js à toutes vos instructions d'importation (attention : cela faire échouer votre code dans ts-node ).

@MicahZoltu Eh bien, merci, mais toujours un peu frustrant que cela ne fonctionne pas simplement "prêt à l'emploi". Comme @phaux l' a dit, VSCode suggère à ses utilisateurs de faire des déclarations d'importation sans l'extension et cela ne fonctionne tout simplement pas en cours d'exécution. Je remets sérieusement en question la compétence de l'équipe TypeScript ici ou je me suis trompé pendant tout ce temps et je suis tout simplement stupide. Mais qui sait...

Edit : envisagez sérieusement de supprimer TypeScript pour JavaScript + Babel à ce stade.

Je n'ai pas écrit d'application Electron, mais existe-t-il une possibilité de lui faire faire une résolution de style nœud, où il existe un algorithme pour essayer de résoudre les importations qui essaie plusieurs choses dans un ordre fixe ? On dirait que ça devrait aller étant donné que toutes les sources sont chargées à partir de ressources locales...

Il est peut-être temps d'ajouter une nouvelle résolution de module à TS ? Node.js a maintenant un support ESM natif, mais sans extensions explicites dans les chemins relatifs, il oblige à utiliser l'indicateur --experimental-specifier-resolution=node , ce qui est un peu ennuyeux. Il y a aussi Deno et les navigateurs. Idéalement, il devrait y avoir quelque chose comme ça :
tsconfig.json :

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

puis Tapuscrit :

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

compile en Javascript :

import foo from './foo.js';

"strict": vrai signifie beaucoup de travail !
2020, toujours pas réparé, ridicule.

J'interviens juste pour dire que ce problème bloque également notre équipe 😢

Nous aimerions vraiment pouvoir disposer d'une source unique qui s'appuie sur des modules natifs et qui soit également consommable dans node et avec webpack. Webpack semble avoir un problème si vous insérez manuellement .js dans vos importations dans votre code TS. Cependant, vous pouvez en quelque sorte faire fonctionner Webpack si vous mettez l'extension de fichier .ts dans vos importations, mais bien sûr, le tapuscrit se plaint. Ne pas avoir d'extension de fichier signifie ne pas avoir de modules natifs. Ainsi, aucune combinaison ne semble satisfaire le navigateur et les bundlers. Si nous pouvions écrire .ts dans nos importations et que cela devienne .js dans la sortie, le problème serait résolu je crois (et vous obtiendriez également deno compat). Quelque chose comme @ evg656e suggère que cela devrait fonctionner.

@EisenbergEffect y a-t-il un bogue déposé contre WebPack pour cela ? Cela ressemble vraiment à un problème WebPack qui s'écarte du tsc normal.

@justinfagnani Je ne sais pas si le problème réside dans le webpak, le ts-loader ou ailleurs. J'ai passé beaucoup de temps à essayer de mettre en place ma configuration de construction optimale et je n'ai trouvé aucune solution qui cochait toutes les cases. Il existe probablement des moyens de le faire avec des transformateurs personnalisés ou des étapes post-construction, mais j'hésite à adopter des configurations non standard car cela peut affecter négativement les développeurs en aval.

@EisenbergEffect si le chargeur TypeScript de WebPack ne vous permet pas d'importer des fichiers TypeScript via une extension .js comme le fait tsc , alors c'est un bogue. Comme vous l'avez dit, le comportement empêche d'avoir la même version source avec WebPack et tsc .

Il est peut-être temps d'ajouter une nouvelle résolution de module à TS ? Node.js a maintenant un support ESM natif, mais sans extensions explicites dans les chemins relatifs, il oblige à utiliser l'indicateur --experimental-specifier-resolution=node , ce qui est un peu ennuyeux. Il y a aussi Deno et les navigateurs. Idéalement, il devrait y avoir quelque chose comme ça :
tsconfig.json :

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

puis Tapuscrit :

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

compile en Javascript :

import foo from './foo.js';

Les gens (par exemple, moi) aimeraient laisser un morceau de code fonctionner entre Node.js, Deno et le Web en même temps. Je pense que ce serait une étape importante pour la programmation TypeScript/JavaScript.

Si vous utilisez vscode et avez besoin d'une solution provisoire, l'ajout de ceci à settings.json semble résoudre les problèmes :

"typescript.preferences.importModuleSpecifierEnding": "js"

Il ajoutera .js à vos chemins d'importation (ce qui résoudra les fichiers *.ts dans src sans erreur, mais conservera les .js lors de la transpilation). C'est utile lorsque vous utilisez tsc sans bundler.

Pendant que nous attendons une solution tsc, une solution low-tech consiste à

  1. Copiez tous les fichiers source dans un dossier temporaire
  2. Supprimer l'extension pour les importations et les exportations avant la construction

Je voulais partager ce one-liner au cas où d'autres pourraient l'utiliser. Il copie le dossier src/ dans tmp/ et y modifie les fichiers.

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

Dans le cadre d'un script de construction dans package.json (après avoir fait un yarn add --dev shx rexreplace ), cela pourrait ressembler à ceci

"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"
}

Je garde actuellement .js hors des chemins d'importation dans les sources TypeScript, pour garder Jest heureux.
Ensuite, j'ai une étape de post-traitement pour ajouter .js .
Les cartes source ne sont pas prises en charge avec cette méthode.

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

Le script de post-traitement build-post.js effectue les opérations suivantes.

Ajouter .js à import et export des chemins relatifs

Par exemple,

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

devient

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

Notez que je n'utilise index.ts nulle part, mais plutôt mod.ts suivant la convention Deno. Ainsi, je n'ai pas besoin de considérer le cas de l'ajout de /index.js .

Remplacez import par require pour les packages CommonJS

Mon code s'exécute sur les nœuds ^ 12.17 et ^ 14.1, en mode modules. Je ne publie que des modules ES.
Cependant, de nombreuses dépendances ont encore CommonJS dans leur champ "main" .
Ainsi, je devrais les changer en CommonJS, à l'exception des modules intégrés NodeJS.

Par exemple,

import { Server as WsServer } from "ws";

devient

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

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

Mais alors, webpack n'est pas satisfait de ces require s, donc je dois utiliser :

/// #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

Dans webpack, tout package important mon projet doit utiliser ifdef-loader , puis webpack verrait la ligne originale import .

Nous sommes également touchés par cela et je ne comprends pas comment cela n'est pas résolu 3 ans après avoir été signalé.
Nous utilisons WebStorm afin que le paramètre spécifique à VSCode ne fonctionne pas.
Utiliser un script séparé pour corriger la sortie est ridicule.
Cela devrait fonctionner sans avoir à utiliser d'outils tiers.

+1

Ceci est ma solution de contournement en utilisant un site Web asp.net core 3.1 (fonctionne probablement sur les versions inférieures)
Dans le fichier 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!");
                });
            });
        }

Le middleware de réécriture ajoutera l'extension ".js" à toute requête ciblant le dossier /js.
Attention : l'ordre du middleware est important ici, les UseStaticFiles doivent être placés après le UseRewriter ou cela ne fonctionnera pas.

Comme tout le monde ici, je préférerais une solution prête à l'emploi mais jusque-là...

Il est peut-être temps d'ajouter une nouvelle résolution de module à TS ? Node.js a maintenant un support ESM natif, mais sans extensions explicites dans les chemins relatifs, il oblige à utiliser l'indicateur --experimental-specifier-resolution=node , ce qui est un peu ennuyeux. Il y a aussi Deno et les navigateurs. Idéalement, il devrait y avoir quelque chose comme ça :
tsconfig.json :

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

puis Tapuscrit :

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

compile en Javascript :

import foo from './foo.js';

J'ai configuré la règle node/file-extension-in-import dans eslint-plugin-node à la configuration de linting avec l'idée d'ajouter manuellement l'extension aux instructions d'importation (car c'est mieux ainsi) et le "moduleResolution": "node" dans TypeScript config et tout ce que je peux voir est ts(2691) .

Espérons que ce que @ evg656e a dit vaille la peine d'être mis en œuvre.

Je ne peux pas croire que ce soit toujours un problème.

quand vous utilisez
"baseUrl": ".", "paths": { "/*": ["./*"] },

vous pouvez faire un import de module absolu comme ceci :
`importer ws depuis "/hey/connection" ;

mais lors de l'ajout de l'extension ".js", du coup le compilateur ne trouve plus la déclaration connection.ts et dit :

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.

en utilisant un chemin relatif, tout fonctionne bien.

Merci de corriger cela

Je veux aussi un correctif pour cela.

Merci.

C'est ridicule que ce soit encore un problème ! :00

J'ai finalement décidé de passer à TypeScript et ce fut l'un des premiers problèmes que j'ai rencontrés. Cela casse la résolution des modules dans l'implémentation native de Node, et je n'ai pu le contourner qu'en utilisant le package esm qui semble être plus flexible pour accepter les noms sans extensions, ou (étrangement) en utilisant les extensions .js dans les chemins d'importation dans mes fichiers .ts même lorsque l'importation fait référence à un fichier .ts ou .tsx. Je ne sais pas pourquoi le compilateur TypeScript accepte cela, mais au moins la sortie de construction inclut alors l'extension .js. Solution terriblement hacky cependant.

Je n'utilise même pas beaucoup le tapuscrit côté client ces jours-ci, cela n'a pas trop affecté la qualité de mon code et a rendu les choses beaucoup plus simples. JavaScript aura probablement des types facultatifs d'un point et ce problème n'aura plus d'importance.

Je laisse de côté l'extension sur les lignes d'importation, pour rendre Jest et Webpack heureux.
Lorsque je compile, j'invoque tsc --listEmittedFiles et dirige la sortie vers un script de post-traitement. Ce script ajoute les extensions .js , pour rendre Node (en mode module) heureux.
https://github.com/yoursunny/NDNts/blob/fa6b2eb68a9f32a6a2e24e5475275f803236b8f8/mk/build-post.js

@kj

(étrangement) en utilisant des extensions .js dans les chemins d'importation à l'intérieur de mes fichiers .ts même lorsque l'importation fait référence à un fichier .ts ou .tsx. Je ne sais pas pourquoi le compilateur TypeScript accepte cela, mais au moins la sortie de construction inclut alors l'extension .js. Solution terriblement hacky cependant.

Ce n'est pas bizarre et certainement pas hacky, et fonctionne parfaitement avec la résolution du navigateur et du module natif Node.

La ressource que vous importez _est_ le fichier .js. Le type peut être soit dans un fichier .ts, soit dans un fichier .d.ts. Un fichier .d.ts n'a même pas besoin d'être un frère du module .js, et il n'est pas nécessaire qu'il y ait une relation 1 à 1 entre les fichiers .d.ts et les fichiers .js.

L'importation du module .js est l'option la plus fiable et la plus stable que tsc aurait pu choisir. Sinon, il y aurait des cas où vous importez les types et tsc ne connaît pas la bonne façon de les réécrire dans un chemin de module réel.

@justinfagnani Ah, je pense que c'est logique. Je ne voulais pas dire que tout ce que TypeScript faisait ici était hacky (je ne suis pas en mesure de faire une telle affirmation), juste que je sentais que ce que je faisais n'était peut-être pas typique. Je suppose que j'y ai pensé dans le mauvais sens. Ce n'est pas TypeScript qui importe le module, c'est ce qui évalue la sortie de construction (ou ai-je mal compris)? Dans ce cas, je peux voir pourquoi cela fonctionnerait de cette façon.

La ressource que vous importez _est_ le fichier .js

Vous faites référence au module construit ici, n'est-ce pas ? Pas un fichier .js dans le répertoire source, mais la version construite du module .ts ?

Ne se pourrait-il pas que si vous spécifiez explicitement l'extension .ts ou .tsx dans un chemin de module, la sortie remplacera .js ?

Je pense qu'il peut y avoir un malentendu sur ce qui se passe @kj. Lorsque vous spécifiez une extension .ts sans avoir compilé votre code, il fait référence au fichier ts. Mais lorsque vous compilez à l'aide de tsc, il convertit le contenu du fichier ts en un fichier js exécutable dans l'environnement dans lequel vous vous trouvez (nœud ou navigateur).

Je comprends que @ mkay581 , mais disons que j'ai cette ligne dans un fichier foot.ts :

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

Le 'Component.js' auquel je fais référence est en fait 'Component.tsx' sur le système de fichiers (il n'y a pas de fichier .js, à moins que TypeScript comprenne que cela fait référence à l'éventuelle version transpilée du fichier?), Pourtant TypeScript accepte très bien cela et la même ligne d'importation est alors présente dans la sortie (avec l'extension .js qui fonctionne alors avec Node ou le navigateur).

La manière traditionnelle de TypeScript (AFAIK) serait de spécifier cette ligne d'importation sans l'extension, comme suit :

import { Component } from './Component';

Cela se compile évidemment bien aussi, sauf que la ligne d'importation dans le fichier .js transpilé n'inclut pas l'extension .js sur './Component', qui est requise par certains environnements (et peut-être que cela ressemble à la spécification, bien que je n'aie pas ' t le lire pour être sûr).

D'autre part, si je spécifie la ligne avec le nom de fichier réel du fichier source :

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

Ensuite, TypeScript ne reconnaît pas le chemin et suggère que je devrais essayer la ligne d'importation sans l'extension de fichier (si je me souviens bien, je ne suis pas sur mon ordinateur pour le moment).

Donc, le premier exemple me semble un peu étrange, car j'écris TypeScript, je m'attendrais à pouvoir importer avec l'extension .ts ou .tsx, mais il n'accepte que le chemin sans extension (ce qui semble être en contradiction avec d'autres implémentations du système de module ES) ou avec l'extension .js qui ne pouvait faire référence qu'au fichier de sortie car je n'ai pas un tel fichier source.

@justinfagnani

La ressource que vous importez _est_ le fichier .js.

Je ne sais pas comment fonctionne tsc mais cela ne me semble pas juste. Lorsque vous écrivez votre code, il n'y a pas encore de fichier .js. C'est au compilateur de le créer.

TS agit comme une couche d'abstraction au-dessus de JS et les fichiers .js sont la sortie de l'étape de compilation. Compter sur leur présence avec cette extension spécifique semble briser l'abstraction, IMO.

Pour le dire autrement, lorsque vous utilisez C ou C++, vous ne faites pas #include les fichiers .o dans votre code, vous incluez le .h ou au plus le .c ou .cpp .

Je suis prêt à accepter une explication raisonnable de ce comportement dans Typescript, mais à moins qu'il ne me manque quelque chose, celui-ci ne semble pas l'être.

@kj

Ce n'est pas bizarre et certainement pas hacky

Difficile d'être en désaccord. Pour moi, c'est la définition même de bizarre et hacky. 😛 Ce que vous faites ici, c'est référencer un fichier hypothétique. Un fichier dont l'existence n'est pas garantie. (Par exemple, lors du regroupement de code, en utilisant AssemblyScript ou deno) Vous assumez le format de sortie. Mais lors de l'écriture de code agnostique (par exemple, des modules tiers), c'est une chose _dangereuse_ à supposer.

@borfast @frzi Oui, c'est essentiellement ce que je ressentais à ce sujet, et je suis heureux de voir que je ne suis pas le seul à ne pas être à l'aise avec cela. J'essaie juste de ne pas faire trop d'hypothèses étant si nouveau sur TypeScript !

@frzi

Ce que vous faites ici, c'est référencer un fichier hypothétique. Un fichier dont l'existence n'est pas garantie

Pas hypothétique, tsc sait qu'il le générera. Il est garanti d'exister, lors de l'utilisation de tsc.

Une autre façon de voir les choses est que si vous importez le fichier .ts, vous importez un fichier qui ne sera plus là après la compilation.

lors du regroupement de code

Les bundlers s'exécutent après tsc

@kj a mentionné les fichiers .tsx, et ils me font encore plus comprendre. .tsx n'existe que pour signaler au compilateur de ce module, _localement_, que le module contient JSX. Les importateurs du module n'ont pas besoin de savoir qu'il y avait du JSX dans le fichier, et ils ne peuvent pas le dire après la compilation. Les fichiers peuvent être portés de manière transparente entre les paires .tsx, .ts et .js/.d.ts.

Supposons que vous importiez un fichier .ts :

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

Et vous souhaitez ensuite utiliser JSX pour le composant, vous le renommez donc en component.tsx. Toutes les importations doivent-elles échouer ? Supposons que vous migrez de .ts vers .js/.d.ts, les importations devraient-elles échouer à nouveau ?

@borfast

TS agit comme une couche d'abstraction au-dessus de JS et les fichiers .js sont la sortie de l'étape de compilation. Compter sur leur présence avec cette extension spécifique semble briser l'abstraction, IMO.

L'abstraction n'est pas aussi complète que vous le sous-entendez ici. Vous pouvez importer des fichiers .js depuis l'intérieur ou l'extérieur de votre projet TS. Vous pouvez ajouter des types à un fichier .js avec un fichier .d.ts qui se trouve n'importe où dans votre projet. Les fichiers .js sont ce qui est réel après la compilation. Tout le reste ne fait qu'aider le compilateur.

@justinfagnani Je suis un peu perdu avec ce que vous dites, mais pourquoi TypeScript ne peut-il pas simplement supposer que si vous lui donnez un chemin d'importation avec .ts ou .tsx, il générera un fichier .js pour ce module et devrait donc remplacer cette dernière extension dans la sortie ?

@justinfagnani

Pas hypothétique, tsc _sait_ qu'il le générera. Il est garanti d'exister, lors de l'utilisation de tsc.

Mais il y a une symétrie implicite ici que vous n'admettez pas.

Cette "garantie" dont vous parlez vaut dans les deux sens. Si, comme vous le dites, "tsc _sait_ qu'il va générer [fichiers js]", alors c'est une question tout aussi valable à poser : "Eh bien, alors pourquoi tsc n'agit PAS sur cette garantie et applique les extensions .js qu'il _sait_ est manquant dans le js compilé ? »

Interpréter le fait que "tsc garantit les fichiers js" va dans les deux sens.

Alors je suis d'accord, @justinfagnani , votre interprétation _est_ valable, d'un certain point de vue. Mais l'interprétation inverse est que "tsc devrait donc _agir sur sa connaissance_ et effectuer ce processus pour le développeur". Et ce qui me dérange dans tout ce débat depuis le début, c'est à quel point cette interprétation est reçue _négativement_, presque au point d'être ridiculisée. C'est déraisonnable.

En fin de compte, ce débat porte sur _une décision esthétique, pas une décision logique_. Et mon espoir est qu'un ton de voix ampliatif et accommodant - comme il est propre à l'opinion esthétique (et non à la déduction logique) - soit porté sur cette question par ses détracteurs.

En bref, veuillez admettre que la question du PO est une interprétation parfaitement valable - peut-être avec la vôtre. Pas besoin de débat acharné.

Merci

@justinfagnani

Une autre façon de voir les choses est que si vous importez le fichier .ts, vous importez un fichier qui ne sera plus là après la compilation.

Bien sûr, ce ne sera pas le cas, tout comme un fichier .h n'est pas distribué avec l'exécutable d'un programme C. C'est exactement le point : vous dites à un compilateur d'inclure les fichiers source , pas les fichiers compilés .

Ok, je suis trop spammé avec cette conversation pour l'ignorer davantage.
L'instruction import ne fait PAS partie du texte dactylographié, elle fait partie de l'environnement JavaScript qui l'a exécutée. Maintenant, le mot clé ici est environnement JavaScript , car c'est CECI qui résout les chemins. Montrez-moi une seule application qui, dans le runtime, importe et exécute des fichiers .ts (bien sûr, il peut y en avoir, mais ils sont ce que j'appellerais hacky).
TypeScript permet d'ajouter des extensions .js car il autorise le JavaScript natif dans ses fichiers source. aucun des navigateurs de node.js n'exécutera le fichier .ts, même ts-node transpile les fichiers .ts à la volée, garde simplement le résultat en mémoire au lieu de l'écrire sur le disque dur (pas hacky du tout ?).

Maintenant, le bon correctif tsc serait:

  • nous avons .ts fichier
  • nous le référençons dans un autre fichier
  • tsc transpile ce fichier .ts en fichier .js
  • tsc réécrit ensuite toutes les références directes au fichier .ts avec le fichier .js (il sait exactement comment il s'est transpilé et peut donc le mettre à jour correctement)

Problème : "modern web dev" n'est pas un véritable développeur Web et utilise la méthode d'importation node.js, en sautant l'extension (et le chemin complet du fichier). tsc ne sait plus quelle sera la sortie, car l'importation my-awesome-module/test peut être n'importe quoi, à partir d'un fichier test.js dans node-modules/my-awesome-module , jusqu'au fichier index.js à l'intérieur du dossier test dans node-modules/my-awesome-module , se terminant par des réécritures locales avec des fichiers non-js comme ./local-mocks/my-awesome-module/mock.json .

C'est là que le problème se pose : comment un tsc peut-il savoir quelle est la configuration funky webpack/rollup/super-awesome-new-and-shiny-bundler pour votre projet particulier ?

Encore une fois: je suis tout à fait pour que tsc réécrive les chemins d'importation, mais cela ne fonctionnerait que pour des projets simples, et le faire fonctionner uniquement pour des projets simples (ce qui est aujourd'hui une minorité car même les pages de présentation simples réagissent avec une configuration Webpack sur-conçue) ne vaut pas la peine passer du temps dessus, si cela peut être fait avec un simple script écrit personnalisé.

Encore une fois: je suis tout à fait pour que tsc réécrive les chemins d'importation, mais cela ne fonctionnerait que pour des projets simples, et le faire fonctionner uniquement pour des projets simples (ce qui est aujourd'hui une minorité car même les pages de présentation simples réagissent avec une configuration Webpack sur-conçue) ne vaut pas la peine passer du temps dessus, si cela peut être fait avec un simple script écrit personnalisé.

Comment le feriez-vous dans un projet simple sans webpack, juste avec tsc je veux dire ?

Je lis les commentaires de tout le monde et il semble y avoir un désaccord fondamental sur les attentes de l'utilisation du tapuscrit ici.

Lorsque les fichiers source .ts font référence à des fichiers .js, le problème a déjà commencé.

Typescript a été conçu pour ~exécuter~ compiler les fichiers source .ts - pas les fichiers .js. Si un développeur souhaite utiliser TypeScript sur son projet, il doit convertir son projet _entier_ en typescript et ne pas laisser de fichiers .js orphelins et essayer de les référencer. Et si vous n'avez pas le temps de modifier le contenu des fichiers js en syntaxe Typescript, renommez simplement les fichiers js en fichiers ts (ou utilisez le mappage de chemin de TS pour mapper les importations aux fichiers .js). Problème résolu. :man_shrugging:

EDIT : Corrigé "exécuter" en "compiler", c'est ce que je voulais dire, mais je peux voir comment cela peut avoir été interprété différemment.

@ mkay581 TypeScript n'a jamais été conçu pour exécuter quoi que ce soit, juste pour générer des fichiers JS.

@valeriob Un projet simple aurait probablement au maximum quelques fichiers, qui n'ont pas besoin d'être regroupés. De nos jours, les navigateurs ont des importations intégrées, pas besoin de contourner cela. Ensuite, ce serait aussi simple que d'écouter les événements de navigation dans le navigateur, puis de mapper chaque événement sur l'itinéraire correspondant, chaque itinéraire pourrait importer des données avec fetch et une fois renvoyé pourrait être rendu avec des moteurs de modèles non compilés (lit- html, HyperHTML ou plus anciens comme Moustache, Guidon, Carlin, etc.). Terminé, pas besoin de fantasmer sur le webpack, le framework ou les bibliothèques utilitaires, juste même les écouteurs, les expressions régulières, la récupération, les promesses et un simple moteur de template js.

Merci @Draccoz , pouvez-vous me dire comment faire fonctionner ce scénario simple ? https://github.com/valeriob/Typescript_Non_SPA
C'est un simple fichier .ts faisant référence à une bibliothèque JS (rxjs par exemple) et je veux le consommer en tant que module dans une page html.

@valeriob Ce n'est pas aussi trivial que ça devrait l'être. La plupart des bibliothèques tierces, même lorsqu'elles déclarent être compatibles avec les modules ES, ne sont pas dans le monde des navigateurs.
RxJS est quelque chose qui m'intéressait surtout lors de son passage au flux natif, mais ils attendent que ce ticket soit résolu avant de décider de l'implémenter eux-mêmes (drôle...).
Dans l'architecture que je concevais, j'ai d'abord utilisé sed pour corriger toutes les importations, mais j'ai ensuite changé d'avis pour utiliser un simple serveur de développement avec réécriture de chemin. Mon concept est de n'avoir aucune dépendance externe dans mes applications à part rxjs, tapuscrit et lit-html (node_modules avec 4 dossiers et tests/builds CI ULTRA rapides). Si TS réécrivait les chemins, cela éliminerait le besoin de mon serveur, même s'il s'agit de toute façon d'environ 90 lignes de code. C'est open source, si quelqu'un veut un lien, il suffit de demander ou de vérifier les organisations dans mon profil.

En ce qui concerne les pages simples, je faisais référence à celles qui n'ont pas vraiment besoin de bibliothèque, comme cliquer sur une URL -> récupérer des données -> l'afficher -> répéter.

Ne pas avoir besoin d'utiliser une bibliothèque dans Js est une pure fantaisie puisque Js n'a pas de bibliothèque de base.

Le scénario simple est celui que j'ai lié, et ça ne marche pas. C'est aussi le scénario le plus courant pour les personnes qui ne veulent pas plonger dans le monde fou du webpack/compilation qui complique les choses sans réel avantage, limite beaucoup vos options, oblige les développeurs à combattre les outils plus qu'à écrire votre application, et ralentissez votre dev boucle.

Beaucoup de gymnastique mentale se déroule ici pour nier que ce problème existe et qu'il s'agit d'une préoccupation importante pour la productivité de nombreux développeurs.

Expliquer que cela _ne devrait pas être un problème_ ne _résout pas le problème_. Le logiciel doit se conformer aux modèles mentaux des utilisateurs, et non imposer son propre modèle d'implémentation aux utilisateurs. (trucs UX)

Si les utilisateurs conceptualisent tsc comme un compilateur de type C, selon @borfast , alors c'est le mode mental privilégié qui doit être pris en compte, malgré les détails d'implémentation de tsc.

La question de l'OP a plus de 200 pouces levés, plus que tous les autres problèmes du référentiel.

Cette question mérite un vote communautaire. Veuillez envisager de lancer un sondage.

Si la plupart des utilisateurs souhaitent que tsc réécrive leurs importations, c'est la bonne réponse. C'est du moins la manière UX de voir les choses.

C'est encore plus simple que cela, si le typescript en tant que langage est un sur-ensemble de JavaScript, la sortie de tsc (même le commutateur de fichier de sortie non unique) devrait être assimilable par JavaScript lui-même.

@weoreference si vous définissez de manière claire (pas d'écriture de code, juste de conception) comment EXACTEMENT doit-il réécrire les chemins, en tenant compte de plusieurs environnements (node.js, navigateur), de plusieurs possibilités de configuration de bundle (en étudiant toutes les fonctionnalités actuelles, prévues et futures possibles de webpack, rollup and parcel et tout autre bundler) alors bien sûr, alors je pense que l'équipe TypeScript serait pleine de votre côté.

Si vous n'êtes pas disposé à le faire ou si vous pensez que c'est trop difficile, arrêtez de leur demander de créer une fonctionnalité que personne ne peut réellement décrire, c'est comme "Je me fiche de savoir comment, mais faites voler cette vache"...

@Draccoz , vous voulez que votre voiture change de vitesse pour pouvoir la conduire à plus de 10 km/h, mais je suis sûr que le constructeur ne vous a jamais demandé d'apprendre comment fonctionne un train d'engrenages, et encore moins d'en concevoir un.

Quant à la question des bundlers et ainsi de suite, pourquoi est-ce un blocage pour cela ?

Écoutez, je veux juste utiliser les modules ES, je ne veux pas faire face à toute la folie Babel et Webpack. Pourquoi ne peut-il pas s'agir d'une option facultative du compilateur qui modifie simplement l'extension de fichier en .js ? Si ce comportement est en conflit avec d'autres options de configuration définies par l'utilisateur, il doit être automatiquement désactivé, ou un avertissement/erreur doit être affiché et la compilation arrêtée lorsque tsc est exécuté, afin que l'utilisateur sache qu'il doit modifier la configuration.

Je ne vois vraiment pas pourquoi c'est impossible.

@Draccoz Bonjour :) Eh bien, comme je le vois, vous demandez deux choses :

  1. Comment peut-il être mis en œuvre

  2. Comment moi, le développeur, puis-je signaler à tsc que je veux que les importations soient renommées d'une certaine manière, pour mon environnement particulier

Voici mes pensées.

  1. Veuillez consulter la réponse de @borfast ; c'est une réponse "d'ordre supérieur", mais succincte :)

  2. Peut-être que je peux passer un indicateur à tsc/tsconfig, tel que "renameImports":true, ou un autre signal qui est capté par tsc. Si plus de précision est nécessaire, alors peut-être que le drapeau ne devrait pas être booléen mais plutôt prendre une chaîne, peut-être quelque chose comme ceci :

standardImportExtension : 'js'

donc toutes les importations sans extensions de fichier par défaut sont .js

Conclusion:
Cette fonctionnalité ne semble difficile à mettre en œuvre que parce que vous supposez que Q2 (schéma de changement de nom d'importation) doit être connu à l'avance par Q1 (c'est-à-dire par tsc). Mais en fait, non. Moi, le développeur humain, je peux facilement fournir cette "connaissance du monde" à tsc sans qu'il ait besoin de savoir comment fonctionnent webpack/navigateurs/etc. Tout cela avec un simple drapeau.

@borfast Transmission n'a pas été demandé par un utilisateur, il a été fourni avec une voiture par un fabricant, l'utilisateur vient de convenir qu'il s'agit d'une nouvelle fonctionnalité et a commencé à l'utiliser - désolé, ce n'est pas un argument approprié. Par rapport à votre exemple utilisateur - constructeur automobile, cela ressemble plus à "Je veux que ma voiture soit une voiture entièrement électrique avec une autonomie de 100 000 km et une vitesse maximale atteignant la vitesse d'un jet. Je me fiche de savoir comment y parvenir, je le veux et c'est tout - période.
@weoference un peu d'incompréhension dans mes questions. Je demandais: comment faire comprendre à tsc ce vers quoi pointe le chemin? Est-ce un fichier js directement? Ou est-ce un dossier avec index.ts à l'intérieur ? Ou est-ce un module avec package.json qui contient le champ main ? Ou champ suivant ? Ou tout autre qui n'est pas standard ? Ou est-ce un chemin qui est réécrit par webpack ? Ou roll up ? Si oui, où est la config ? C'est peut-être un autre bundler ? Certains moins connus ? Et quels sont les autres cas d'utilisation auxquels je n'ai pas pensé dans la phrase ci-dessus ?

Peut-être que je peux passer un indicateur à tsc/tsconfig, tel que "renameImports":true, ou un autre signal qui est capté par tsc.

@weoference ne pouvez-vous pas déjà le faire avec le mappage de chemin ? L'option paths dans le fichier TSconfig nous donne le contrôle pour mapper les chemins d'importation aux fichiers JS. Désolé si j'interprète mal.

@Draccoz Merci pour votre réponse, s'il vous plaît laissez-moi clarifier

Et quels sont les autres cas d'utilisation auxquels je n'ai pas pensé dans la phrase ci-dessus ?

Oh oui, il serait très difficile pour tsc d'avoir des connaissances sur toutes ces combinaisons environnement/outil de construction.

Mais tsc pourrait avoir un utilitaire simple qui aide les développeurs à couvrir _la plupart_ des cas d'utilisation, et c'est la valeur de configuration "standardImportExtension" que j'ai expliquée.

Bien sûr, vient le problème de la « garantie ». Plus tôt dans ce fil, il a été avancé que tsc devrait "garantir" que le js compilé fonctionnera en fait [sur un environnement].

Eh bien... peut-être que c'était un engagement trop dur. Il est en effet très difficile pour tsc de garantir que le js fonctionnera [sur certains environnements], car, comme vous venez de le décrire, cet environnement est très difficile à définir dans le paysage js actuel.

Mais le simple utilitaire de drapeau proposé par @borfast résout _la plupart_ des erreurs d'importation js rencontrées par les nouveaux utilisateurs essayant tsc.

L'utilisation avancée, qui comme vous le mentionnez consiste en toutes ces considérations —-

Est-ce un fichier js directement? Ou est-ce un dossier avec index.ts à l'intérieur ? Ou est-ce un module avec package.json qui contient le champ principal ? Ou champ suivant ? Ou tout autre qui n'est pas standard ? Ou est-ce un chemin qui est réécrit par webpack ? Ou roll up ? Si oui, où est la config ? C'est peut-être un autre bundler ?

- eh bien, cette utilisation peut en effet être laissée à des scripts utilisateur personnalisés, des bundlers et d'autres outils.

Mais ce n'est pas parce que l'utilisation avancée est difficile à résoudre que nous devons éviter de résoudre les cas faciles.

Et le cas le plus simple consiste à ajouter une extension .js aux importations ; que nous pouvons résoudre, et devrions résoudre.

@weoference donc je suis déclassé par vous pour avoir posé une question et essayé d'être utile, puis vous ignorez la question. On dirait que vous voulez juste discuter et débattre au lieu de progresser vers une solution productive. Vous avez rejeté la tentative de tout le monde de le faire. Dernier message pour moi sur ce fil. Toutes mes excuses pour tous les spams, tout le monde.

@weoreference regarde le tout début de cette conversation, dans les commentaires de @DanielRosenwasser . Il explique pourquoi ils ne le mettraient pas en œuvre ("pour le moment" ? Un espoir inutile). Après sa déclaration, personne dactylographié n'a commenté davantage le sujet. Pour moi, cette discussion devrait être close et Microsoft devrait déclarer officiellement sa position. Point final.
Juste comme remarque - personnellement, je suis tout à fait pour cette fonctionnalité, cela simplifierait BEAUCOUP. J'ai perdu mon espoir car je comprends aussi les arguments de l'équipe dactylographiée.

@weoference

Pas hypothétique, tsc sait qu'il le générera. Il est garanti d'exister, lors de l'utilisation de tsc.

Mais il y a une symétrie implicite ici que vous n'admettez pas.

Cette "garantie" dont vous parlez vaut dans les deux sens. Si, comme vous le dites, "tsc sait qu'il va générer [fichiers js]", alors c'est une question tout aussi valable à poser : "Eh bien, alors pourquoi tsc n'agit PAS sur cette garantie et applique les extensions .js dont il sait qu'elles sont manquant dans le js compilé ? »

La symétrie ne tient pas en fait. Ce n'est pas aussi simple que "d'appliquer une extension .js" - tsc devrait résoudre et réécrire le spécificateur, et la résolution peut dépendre des déclarations de type. TypeScript et Babel prennent en charge les modes de compilation à module unique (isolatedModules pour tsc) et dans ce cas, si vous importez des types au lieu de JavaScript, tsc devra charger les déclarations de type pour déterminer où se trouverait le fichier .js correspondant, afin de réécrire le spécificateur. Pour garder les choses cohérentes et ne pas avoir de cas extrêmes, il est plus simple de ne prendre en charge que l'importation des fichiers .js qui existent avant la compilation ou qui sont un résultat connu du projet en cours.

@justinfagnani @Draccoz Merci ; ok, oui je comprends.

Mon dernier commentaire : "Ce n'est pas parce que les cas difficiles ne peuvent pas être résolus que nous ne pouvons pas résoudre les cas faciles".

Merci

J'ai supposé que TypeScript va à l'encontre des spécifications ici (et produit du JavaScript invalide), mais je ne trouve nulle part dans la spécification qui exige réellement que le chemin d'importation corresponde exactement aux noms de fichiers (avec extension). C'est très difficile à digérer, donc je ne suis pas complètement confiant, mais tout ce que je peux trouver, c'est que la spécification exige que le 'ModuleSpecifier' dans le 'FromClause' soit un 'StringLiteral'. Cela semble être une définition très vague, mais je suppose que cela peut permettre une flexibilité dans la résolution des modules dans les nombreux environnements différents dans lesquels ECMAScript existe. Quelqu'un peut-il confirmer si je lis ceci correctement? Si c'est vraiment le cas, je devrais adoucir ma position sur la façon dont TypeScript gère cela. Cependant, je préférerais toujours qu'il y ait plus d'interopérabilité entre TypeScript, Node et le Web. La situation actuelle n'est pas idéale.

Je suis venu à ce problème après avoir lu ceci . Ce problème m'a donné l'impression que le système de Node fonctionne comme il le fait (correspondant strictement aux noms de fichiers) en raison de la spécification ES, mais je peux voir maintenant que j'ai mal lu cela (ils ne faisaient pas référence à la spécification ES), et peut-être ni Node, ni TypeScript ne font réellement quelque chose de "mal". Ensuite, ce problème concerne vraiment les incompatibilités entre des approches également valables de résolution de modules entre différents environnements. Pourtant, il est clair que les principaux environnements cibles de TypeScript sont Node et le Web, et bien que Node puisse théoriquement changer son approche, je ne pense pas qu'il soit très probable que les navigateurs le fassent, donc je pense toujours que ce problème est valable.

Edit : Je pense que cela pourrait être cette section de la spécification qui semble spécifier que la résolution du module est "définie par l'hôte" ?

@kj le texte de spécification pertinent se trouve dans la spécification HTML : https://html.spec.whatwg.org/multipage/webappapis.html#resolve -a-module-specifier

Il indique que les spécificateurs d'importation doivent être des URL complètes ou des chemins absolus ou relatifs. Si le spécificateur n'analyse pas comme une URL (commençant généralement par http:// ou https:// ) ou commence par / , ./ ou ../ , une erreur est renvoyée. Les spécificateurs de chemin sont résolus par rapport à l'URL de base des importateurs.

Aucune autre recherche de chemin ou résolution n'est effectuée. Cela signifie que le spécificateur doit résoudre l'URL complète du module et vous devez inclure l'extension si le serveur l'exige. Les serveurs ont la possibilité de renvoyer des réponses pour les URL sans extension.

La raison pour laquelle Node a opté pour un algorithme de résolution plus restrictif pour les modules est d'être plus compatible avec le Web, de sorte qu'il est plus courant que les modules publiés sur npm n'aient pas besoin d'outils supplémentaires pour s'exécuter nativement dans les navigateurs. L'importation par nom de package est toujours une fonctionnalité très importante, donc Node le prend en charge, mais vise à être compatible avec la proposition d'importation de cartes (que Deno et SystemJS prennent déjà en charge).

Tout compte fait, la prise en charge par tsc de l'importation avec les extensions .js fonctionne parfaitement dans les navigateurs Node et Web. Ce sont en fait les importations sans extension qui causent des problèmes sans outils supplémentaires. Cependant, généralement, les outils qui prennent en charge la résolution de nœud pour les noms de packages utilisent également la résolution de style de classe require() et résolvent les chemins relatifs et ajoutent également leurs extensions. C'est ce que fait es-dev-server .

Merci @justinfagnani. Donc, au moins dans le navigateur, cela dépend vraiment de la façon dont le serveur l'implémente. C'est bon à savoir. C'est encore assez peu intuitif et déroutant et je pense qu'il doit y avoir plus de convergence entre les projets pour le bien de la communauté, mais je ne sais plus à quoi cela pourrait ressembler.

Edit : Pour l'instant, cela me suffira (surtout compte tenu des explications ci-dessus, je me sens plus à l'aise avec) :

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

Je ne sais pas si cette option est référencée dans la documentation TypeScript, mais si ce n'est pas le cas, c'est peut-être pour éviter toute confusion. Cela ne semble pas être le cas, en recherchant ' site:typescriptlang.org specifier-resolution' ou ' site:staging-typescript.org specifier-resolution'. Bien que, comme c'est encore assez nouveau dans Node, ce n'est pas trop surprenant.

@justinfagnani Je suis d'accord que l'extension .js fonctionne dans la plupart des cas, sauf dans les cas où quelqu'un prend une position idéologique _contre_ (par exemple https://github.com/TypeStrong/ts-node/issues/783, que vous connaissez).

J'ai créé une version sans dépendance du script de @quantuminformation ici . Cette version contient également une expression régulière qui ne remplacera que les modules qui ne se terminent pas déjà par .js .

même besoin

Obtenir des extensions .js pour la compatibilité ESM en utilisant .js dans les instructions d'importation ne fonctionne pas pour moi. Lorsque j'importe un fichier TS et que j'omets toute extension, il se compile bien. Lorsque j'ajoute une extension .js à l'importation, j'obtiens de nombreuses erreurs (qui ne devraient pas exister) du compilateur TS.

Il semble que la principale raison pour laquelle cette fonctionnalité n'est pas développée est due à la difficulté/impossibilité de compatibilité avec divers bundlers, mais Node.js et les bundlers ont développé leurs propres schémas de modules en l'absence de prise en charge des modules dans ECMAScript. Maintenant que nous avons la MES, aussi inadéquate que certaines personnes puissent la considérer, c'est la voie à suivre. Au fur et à mesure que de plus en plus de code est développé dans ESM et des composants Web, l'utilisation de bundles diminuera, et ce point douloureux entre TS et ESM développera plus de friction. Ce serait bien, même si le support initial est bogué et ne prend pas en compte tous les cas d'utilisation, s'il pouvait commencer à être supporté.

Jusqu'à ce qu'il y ait une meilleure solution, il s'agit d'un script de nœud sans dépendances à utiliser comme tâche de génération

configurer dans votre 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)

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

Quelqu'un peut-il se souvenir de ce qu'il faisait il y a 3 ans lorsque ce problème a été ouvert ?

La solution non groupée consiste à écrire des projets distribués sur le Web avec .js comme extension.

Cela fonctionne à 100%. Le plus gros problème est d'essayer d'écrire des modules qui ciblent le Web et Node.js, mais c'est un problème pour JS en général.

S'il y avait quelque chose à faire, ce serait d'ajouter --moduleResolution=web , mais ce n'est pas la portée de ce problème ici.

J'ai dû écrire ce script post-build pour ajouter l'extension .js.

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

J'ai un script similaire, en JavaScript :
https://github.com/yoursunny/NDNts/blob/743644226fe18d48e599181e87ad571a2708a773/mk/build-post.js

Il est invoqué comme :

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

L'inconvénient majeur de ce type de scripts est qu'ils cassent les mappages de sources, de sorte que le débogage devient moins efficace.

en utilisant des outils modernes et des extensions .js dans la source, tout fonctionne parfaitement dans les nœuds et les navigateurs

  • manuscrit
  • modules es
  • cumul

Je ne peux que supposer que les gens qui ont des problèmes ici sont en fait coincés dans un hybride cassé de modules e et de résolution de nœuds, alors que les développeurs s'accrochent aux points de repère familiers de leurs anciens flux de travail - Webpack est probablement à blâmer...

- Webpack est probablement à blâmer...

Et donc - le chat est sorti du sac.

en utilisant des outils modernes et des extensions .js dans la source, tout fonctionne parfaitement dans les nœuds et les navigateurs

_La plupart_ des choses fonctionnent parfaitement, et je suis d'accord que les fichiers sources devraient tous avoir des extensions .js dans leurs exportations. D'après mon expérience, la seule chose qui ne fonctionne pas bien avec ceci est ts-node, en raison de leur refus obstiné de prendre en charge les extensions .js . Oui, vous pouvez ajouter une étape de pré-transpilation avant d'exécuter le nœud, et les importations .js fonctionneront, mais si vous voulez exécuter le code ou les tests .ts directement avec le nœud et également dans le navigateur, vous n'avez actuellement pas de chance. (Pour clarifier, je pense qu'il s'agit d'un bogue ts-node, pas d'un bogue TypeScript).

Merci @chase-moskal.

J'ai refactorisé le repo et le fichier tsconfig, et maintenant
import {something} from './something.js'
ne jette pas
typescript force overwrite error TS5055: Cannot write file because it would overwrite input file
plus, et je n'ai plus besoin du piratage fix-ts-imports .

Dans plus de 250 commentaires, il y a eu très peu de clarté. Résumer:

Contexte

Modules de navigateur

Les navigateurs résolvent les modules EcmaScript en fonction de l'URL, y compris les URL relatives. ( WHATWG )

Modules Node.js

Node.js résout les modules (à la fois EcmaScript et le CommonJS spécifique à Node.js) via un algorithme beaucoup plus complexe qui implique plusieurs solutions de secours et l'analyse des fichiers package.json. ( Node.js ) Cela peut être personnalisé, par exemple avec --experimental-specifier-resolution=explicit qui nécessite un chemin complet.

Modules TypeScript

TypeScript dispose de plusieurs algorithmes de résolution de modules disponibles et d'une variété d'options pour les personnaliser davantage. ( TypeScript ) L'intention est que les utilisateurs écrivent les mêmes spécificateurs de module que ceux utilisés dans la sortie produite, en ajustant la résolution de tsc avec des options telles que baseUrl et pathMappings.

En pratique, la plupart des utilisateurs utilisent le nœud moduleResolution, ciblant un environnement Node.js ou un bundler compatible. Cette demande se concentre sur les utilisateurs ciblant les navigateurs sans bundler.

résolution du module ts-node

Apparemment, ts-node ne prend pas en charge les identifiants de module avec des extensions. Bien que l'on ne sache pas pourquoi, puisque Node.js et TypeScript le font, et ts-node est apparemment la fusion de ceux-ci.

Les faits

Fait 1 : Vous pouvez utiliser les extensions .js

Pour une compatibilité plus large (à savoir les navigateurs), vous pouvez utiliser les extensions .js aujourd'hui. À l'exception étrange de ts-node (bogue IMO), tout fonctionne en ce moment en spécifiant le chemin complet (c'est-à-dire, y compris l'extension).

Fait 2 : Ce n'est pas aussi simple que "ajouter une extension"

Cette demande est mieux résumée par "transformer l'identifiant du module en chemin de fichier". Par exemple, ./example devient ./example/index.js et 'lodash' devient '.node_modules/lodash/index.js' .

Notez que parfois il n'y a même pas de chemin de fichier résolu, comme avec les déclarations de module ambiant.

declare module "lodash" {
}

Peut-être que la réécriture du module est limitée aux modules TS dans le projet/la compilation en cours.

Dans tous les cas, nous enfreignons maintenant l'un des paramètres de conception de TS, à savoir que d'autres modules affectent la sortie de l'actuel.

Conclusion

Il est possible d'utiliser le chemin pour les identifiants de module qui fonctionnent pour le Web. (Par exemple ./foo/index.js au lieu de ./foo .)

(Bien que pratiquement parlant, vous aurez probablement besoin d'un groupeur de toute façon cibler les navigateurs. À savoir, si les packages npm sont utilisés.)

@pauldraper il y a un problème important avec "Fact 2":

Cette demande est mieux résumée par "transformer l'identifiant du module en chemin de fichier". Par exemple, ./example devient ./example/index.js et 'lodash' devient 'node_modules/lodash/index.js'.

Vous ne voulez vraiment pas résoudre les spécificateurs en dehors de votre package au moment de la compilation, car ce ne sont peut-être pas les chemins disponibles lorsque le package est installé ailleurs. Vous devez exécuter la résolution de module Node dans chaque installation de package unique. Sinon, nous pourrions écrire et publier import {} from './node_modules/lodash/index.js' et en finir.

@justinfagnani , je suis d'accord, mais cela démontre que les identifiants de module sont abstraits et que vous manipulez les emplacements des modules en dehors de tsc. Et que tsc ne peut/n'a pas besoin de se préoccuper de telles manipulations.

Cette demande est mieux résumée par "transformer l'identifiant du module en chemin de fichier". Par exemple, ./example devient ./example/index.js et 'lodash' devient '.node_modules/lodash/index.js'.
Notez que parfois il n'y a même pas de chemin de fichier résolu, comme avec les déclarations de module ambiant.

Ce n'est pas le sujet de cette demande. Il s'agit d'ajouter une extension lors de l'émission de code. Nous voulons écrire des modules compatibles avec le type : "module" sans étape de construction hacky supplémentaire. Les modules externes comme lodash continueraient à fonctionner même sans .js car ce sont des CommonJs.

Exemple:

// ./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'

En plus du tapuscrit ci-dessus, ne prend pas en charge les "exportations" et "type" de package.json. Il n'y a pas de voie vers une véritable ESM dans les projets que je gère.

Cette demande se concentre sur les utilisateurs ciblant les navigateurs sans bundler.

C'est faux. J'écris rarement TS/JS pour les navigateurs, je travaille principalement sur du code côté serveur et j'en ai également besoin parce que je veux utiliser le chargement ESM dans le nœud et ne pas dépendre des bundlers et du code supplémentaire pour le chargement du module.

Les modules externes comme lodash continueraient à fonctionner même sans .js car ce sont des CommonJs.

A moins qu'ils ne le soient pas.

Lorsqu'il est émis.

Cela pourrait être ./moduleA.js . Ou peut-être ./moduleA/index.js , n'est-ce pas ? La résolution du module Node.js autorise un certain nombre de chemins.

A moins qu'ils ne le soient pas.

Pouvez-vous donner un exemple lorsque cela ne fonctionnerait pas ? Node.js vient de prendre en charge l'importation d'exportations nommées à partir de CommonJS.
https://nodejs.org/api/esm.html#esm_import_statements

Il peut s'agir de ./moduleA.js. Ou cela pourrait être ./moduleA/index.js, n'est-ce pas ? La résolution du module Node.js autorise un certain nombre de chemins.

Pas en mode ESM. index.js ne serait plus pris en charge tel qu'il est actuellement. Le chargeur ESM lirait les métadonnées package.json "exports" et "type".
https://nodejs.org/api/esm.html#esm_mandatory_file_extensions

Pour les projets basés sur dactylographie + node.js, nous avons besoin d'une meilleure histoire ESM native. Cela peut se produire via des outils (typescript) ou dans node.js Le problème est qu'il n'y a pas de consensus sur ce qui doit être fait.

Modifier le lien supprimé vers le nœud PR car il était trompeur.

Cette page vous a été utile?
0 / 5 - 0 notes