Typescript: Proporcione una forma de agregar la extensión de archivo '.js' al final de los especificadores del módulo

Creado en 16 jun. 2017  ·  273Comentarios  ·  Fuente: microsoft/TypeScript

Para usar módulos es6 en el navegador, necesita una extensión de archivo .js. Sin embargo, la salida no lo agrega.

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

Idealmente, me gustaría que esto sea una salida.
import { ModalBackground } from './ModalBackground.js';

De esa manera puedo usar la salida en 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

Relacionado con https://github.com/Microsoft/TypeScript/issues/13422

ES Modules Needs Proposal Suggestion

Comentario más útil

Además, para generalizar un poco este problema, no creo que se trate de agregar una extensión .js , sino de resolver el especificador del módulo en una ruta real, sea cual sea la extensión.

Todos 273 comentarios

No solo está relacionado con el #13422, es el mismo problema. Pero las respuestas han sido bastante negativas, a pesar de que creo que es un tema importante, así que espero que su problema sea mejor recibido.

Bueno, espero que se agregue, teníamos muchas ganas de discutir mi POC usando esto en mi próximo podcast de TypeScript, pero parece que tendremos que esperar para usar TypeScript sin herramientas de compilación.

Por el momento, TypeScript no reescribe las rutas. Definitivamente es molesto, pero actualmente puede agregar la extensión .js usted mismo.

@justinfagnani @rictic

Gracias por la sugerencia, escribiré un script de shell/nodo para hacer esto.

@DanielRosenwasser , ¿tendría sentido recopilar los problemas del módulo ES6 nativo bajo una etiqueta?

Además, para generalizar un poco este problema, no creo que se trate de agregar una extensión .js , sino de resolver el especificador del módulo en una ruta real, sea cual sea la extensión.

Me encontré con otro problema que no es realmente el dominio de mecanografiado, pero es para mi caso de uso.

No estoy seguro de cómo manejar node_modules. Normalmente, el paquete web los incluye en el código a través de ts-loader, pero obviamente, el navegador no lo entiende:

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

Agregar una extensión js aquí no tiene sentido.

Supongo que tendría que haber una expansión de ruta por mecanografiado o una resolución de URL ejecutándose en el servidor.

Aprecio que sea un caso bastante especializado, pero creo que sería una forma en que TS podría brillar temprano en esta área. ¿Tal vez podría ser un complemento para el compilador tsc?

Para cualquiera que llegue a esto y quiera una solución provisional, escribí un script para agregar una extensión de archivo js para importar declaraciones:

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

  })
});

Podría convertir esto en una herramienta CLI.

El comentario de @justinfagnani da en el clavo.

Además, para generalizar un poco este problema, no creo que se trate de agregar una extensión .js, sino de resolver el especificador del módulo en una ruta real, sea cual sea la extensión.

cuando escribes

import { KeyCodes } from 'vanilla-typescript';

o para el caso

import { KeyCodes } from 'vanilla-javascript';

está importando desde un especificador de módulo, puede ser o no un archivo, pero agregar .js al final en este caso probablemente no resulte en una resolución válida.

Si está escribiendo una aplicación NodeJS, el algoritmo Require de NodeJS intentará varias resoluciones, pero probablemente _no_ intentará resolverlo en 'vanilla-typescript.js' porque hace referencia a un nombre abstracto y, por convención y por configuración, se resolverá ( tal vez en varios intentos) a algo como '../../../node_modules/vanilla_typescript/index.js' .

Otros entornos, como AMD, tienen diferencias en cuanto a cómo realizan esta resolución, pero una cosa que todos estos entornos tienen en común es cierta noción de un especificador de módulo abstracto.

Menciono esto porque las implementaciones del Módulo ES que se envían en varios navegadores implementan algo que está incompleto. Si consideramos incluso nuestras dependencias más simples, y tan pronto como abordemos el tema de las transitivas, queda claro que tendrá que haber una forma de configurar la cosa maldita.

Eso puede estar lejos, pero como está descubriendo, no es realista escribir sobre esta (cortésmente) implementación de prueba de concepto que nos han dado.

Además, no veo cómo TypeScript podría ayudar aquí, ya que el problema es específico del entorno.

@QuantumInformation , su programa para agregar .js a las rutas se ve bien, liviano, incluso elegante, pero finalmente está implementando su propio paquete de módulos. Es un trabajo divertido e interesante, pero demuestra las deficiencias de las implementaciones actuales disponibles en los navegadores. Incluso si escribe en JavaScript puro, aún necesita algo para compilar y empaquetar sus dependencias importadas transitivamente.

Básicamente, solo estoy despotricando sobre el hecho de que la implementación de los módulos ES que se lanzó está tremendamente lejos de ser adecuada.

Nuevamente, NodeJS, RequireJS AMD, Dojo AMD, Sea Package Manager, CommonJS, Browserify, Webpack, SystemJS, todos tienen sus propias formas diferentes de hacer las cosas, pero todos brindan una resolución de nombre abstracto. Lo tienen que dar porque es _fundamental_.

Gracias por leer mi diatriba.

No estoy seguro de qué versión de TS lo agregó, pero las importaciones como ' ./file.js' ahora funcionan (incluso si el archivo es realmente file.ts).
TypeScript resuelve bien el archivo y genera la importación completa .js en el destino.
lit-html úsalo: https://github.com/PolymerLabs/lit-html/blob/master/src/lib/repeat.ts#L15

Es posible desde TS 2.0. Pero herramientas como el paquete web no lo admiten, por lo que al final es inútil.

Es inútil si uno está usando ts-loader en fuentes (el caso de uso más común).
Todavía es posible agrupar el destino (generalmente la carpeta "dist"), ya que el archivo js real existe allí y el proceso de resolución puede encontrarlo.

Me pregunto si podría implementar una transformación rápida en ts-loader que elimine las extensiones .js del código de destino, lo que permite agrupar directamente desde las fuentes.

Siéntase libre de hacerlo, eso sería genial. Publiqué el problema en los principales webpack ts loaders, como ts-loader, hace unos meses, y he sido bastante mal recibido...

Para información, no hay ningún problema con el complemento mecanografiado acumulativo, como prueba de que es factible.

No veo qué bien hace esto hasta que las implementaciones del cargador del navegador y la especificación del cargador WGATWG admiten al menos _alguna_ configuración porque la mayoría de las dependencias no se cargarán correctamente.

Desde mi punto de vista, nada de esto importa hasta que sea práctico usar el cargador nativo en una importación que se refiera a un especificador literal de cadena arbitrario, algo que aún no puede ser una URL, y que pase por una transformación que produzca el URL real.

Hasta entonces seguiremos dependiendo de herramientas como SystemJS y Webpack.

Creé un pequeño transformador que elimina el '.js' de las declaraciones de importación/exportación.
Usé guardias de tipo tsutils , así que yarn add tsutils --dev . (el paquete generalmente se instala de todos modos si tiene tslint en su proyecto, por lo tanto, dependencia adicional)

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

Con esto, uno puede agrupar archivos ts que contienen importaciones de archivos que terminan en .js (usando webpack y ts-loader ), y aún transpilar fuentes a módulos esm que pueden cargarse en el navegador (usando tsc ).

Probablemente hay un número limitado de casos de uso en los que esto es útil.

EDITAR: actualicé la esencia para trabajar también con exportaciones. es ingenuo y no está optimizado, pero funciona.

¿Algún movimiento sobre este tema?

Este asunto de la extensión nos lleva de regreso al comienzo de TypeScript y por qué se necesitaba un tsconfig.json y por qué se agregó una opción module #$1$#$ a la configuración compilerOptions .

Dado que el asunto de extension de extensión solo importa para ES2015+, ya que require puede resolverse bastante bien, deje que el compilador lo agregue cuando el código de destino sea ES2015+.

  1. .js por .ts
  2. .jsx por .tsx

Hola, llego tan tarde pero me gustaría ayudar. Tengo problemas para entender cuál es el problema aquí. Del ejemplo OP es:

import { ModalBackground } from './ModalBackground';

¿El problema es que no sabemos qué es './ModalBackground' ? ¿Podría ser una carpeta o algo más?

Si ejecutamos tsc en todo el proyecto y sabemos que ModalBackground.ts existe, entonces sabríamos que es seguro agregar la extensión, ¿no?

Este problema también es algo en lo que la comunidad RxJS está muy interesada. ¿Cuál es el cronograma de una solución para esto? ¿Es siquiera priorizado? ¿Hay transformaciones de terceros que ayudarían?

No estoy muy seguro de si esto es un problema si el objetivo de salida es ES2015, ¿verdad? Esto tal vez podría caer en el dominio de una capacidad de navegador ES2015. Más aún, @justinfagnani , ¿no podemos presionar para que esto sea un objetivo de la plataforma del que preocuparnos? (Tal vez necesite bifurcarse en un hilo separado).

Más aún, @justinfagnani , ¿no podemos presionar para que esto sea un objetivo de la plataforma del que preocuparnos? (Tal vez necesite bifurcarse en un hilo separado).

Sí, por supuesto, muchas personas quieren que la plataforma admita algún tipo de especificación simple, pero el hecho actual es que no es así y no hay ninguna propuesta para agregarlos. Necesitamos pasar por todo ese proceso, probablemente de varios años.

Incluso si finalmente obtenemos soporte de especificación simple, es increíblemente poco probable que sea en forma de resolución de módulo de nodo tal como está. Por lo tanto, habrá una discrepancia entre el algoritmo de resolución utilizado por tsc para buscar archivos y el algoritmo de resolución utilizado por los navegadores (y posiblemente incluso el soporte del módulo nativo del nodo, afaik).

Sería genial si tsc pudiera reificar qué ruta usó para encontrar otro módulo para que las herramientas y los entornos posteriores no interpreten los especificadores con una opinión contradictoria.

@justinfagnani ya se interpretan con una opinión contradictoria. TS produce un archivo JS al que no apunta el código JS que produce. ES6 es lo más parecido a una forma oficialmente correcta de hacer JavaScript, por lo que si el código ES6 producido por TypesScript es incorrecto, se trata de un error simple y llanamente. No hay necesidad de esperar por ninguna propuesta y demás, simplemente solucione el error de TypeScript. Pero hoy en día la gente siente que si no encuentra fallas en algo y lo somete a 10 capas de propuesta antes de actuar, entonces no está actuando intelectualmente. Dáme un respiro.

@aluanhaddad Es cierto que muchos proyectos no se beneficiarán, pero hay algunos proyectos que no usan dependencias npm (o que son capaces de manejar las dependencias npm de alguna manera), por lo que esos proyectos se beneficiarían.

También es muy útil para las bibliotecas de TypeScript, que se compilan en ES6. En este momento, esas bibliotecas no se pueden usar de forma nativa en el navegador, pero si TypeScript generara una extensión .js , entonces funcionarían.

@justinfagnani Todavía no está estandarizado ni implementado, pero hay una propuesta para hacer que los paquetes npm funcionen en el navegador.

El mapa de nombres de paquetes puede ser generado automáticamente por el compilador de TypeScript o por otra herramienta.

Así que estoy revisando esto nuevamente, ¿hubo alguna buena solución para esto, aparte de mi secuencia de comandos de nodo?

He estado usando esta solución:
https://github.com/Microsoft/TypeScript/issues/16577#issuecomment-343610106

Pero creo que si el módulo no tiene la extensión de archivo pero se sirve con el tipo MIME correcto, eso debería resolverse.

¿Algún movimiento al respecto?

¿Quizás https://github.com/Microsoft/TypeScript/pull/25073 podría resolver esto?

@Kingwl ¿Admitirá otras extensiones de archivo? como .mjs .es .esm .

tal vez no, esta es otra característica

¿Cómo es esto siquiera una cosa? El compilador TypeScript _sabe_ que la salida de destino es un archivo JS. He estado navegando por estos hilos durante 15 minutos y todavía no entiendo por qué omite la extensión.

Por la cantidad de referencias a este problema, asumo que se está moviendo en la dirección correcta. Tendré otro intento pronto.

¿Cómo es esto siquiera una cosa? El compilador TypeScript _sabe_ que la salida de destino es un archivo JS. He estado navegando por estos hilos durante 15 minutos y todavía no entiendo por qué omite la extensión.

Hay casos de uso comunes, que la gente usa, donde la falta de extensión permite una infraestructura más flexible. Node require hook y webpack loader son dos de estos casos.

¿Cómo es esto siquiera una cosa? El compilador TypeScript _sabe_ que la salida de destino es un archivo JS. He estado navegando por estos hilos durante 15 minutos y todavía no entiendo por qué omite la extensión.

Hay casos de uso comunes, que la gente usa, donde la falta de extensión permite una infraestructura más flexible. Node require hook y webpack loader son dos de estos casos.

Ninguno de los cuales se preocupa por los módulos del navegador.

¿Simplemente mataría al equipo de mecanografiado para agregar un indicador de suscripción para emitir una extensión .js? Nosotros _sabemos_ lo que estamos haciendo aquí, o no habría una docena de hilos (tanto abiertos como cerrados) aún obteniendo respuestas y preguntas confusas. Entendemos que no es una deficiencia con TS, pero si TS está aquí para resolver nuestros problemas de JS, agregue este problema a la lista, por favor.

DESCARGO DE RESPONSABILIDAD:

Sí, entiendo que esto puede llevar a que un montón de personas publiquen problemas aquí que "usted brincó el paquete web", pero en realidad, tetas difíciles para esas personas. Debería ser opcional.

Por cierto, al buscar en la fuente de TypeScript, veo importModuleSpecifierEnding : ¿se puede (ab)usar para hacer que el emisor use terminaciones .js ?

¿Quizás triturar esta propuesta con el esquema tsconfig? https://github.com/domenic/paquete-nombre-mapas

En este punto, estaría feliz si TypeScript solo pudiera reescribir automáticamente las importaciones usando el paths especificado en tsconfig. Incluso sin el soporte del navegador, eso probablemente resolvería la mayoría de los puntos débiles para mí.

¿Alguna actualización? ¿Algún intento de resolver este problema? Tenemos todos los principales navegadores que admiten módulos es de forma predeterminada, el estándar para aquellos requiere que la extensión esté allí. Entiendo que podemos agregarlo manualmente y tsc lo entenderá, pero esto no debería ser obligatorio, ¿por qué no puede funcionar?
Lo siento por quejarme, pero este problema es muy antiguo y aún no se ha hecho nada...

¿Cómo es esto siquiera una cosa? El compilador TypeScript _sabe_ que la salida de destino es un archivo JS. He estado navegando por estos hilos durante 15 minutos y todavía no entiendo por qué omite la extensión.

Hay casos de uso comunes, que la gente usa, donde la falta de extensión permite una infraestructura más flexible. Node require hook y webpack loader son dos de estos casos.

Entonces, tal vez el compilador de TypeScript podría aceptar una opción para agregar las extensiones o no. Tal vez incluso podría aceptar un conjunto de expresiones regulares para agregar (o no) la extensión, como la opción de inclusión (https://www.typescriptlang.org/docs/handbook/tsconfig-json.html).

Sí, ya se ha propuesto al menos una vez, ¿por qué no tenerlo en cuenta? TS ya tiene algunas funciones experimentales que podrían cambiar en el futuro una vez implementadas en el navegador, pero TS ya tiene indicadores para esas especificaciones inestables. ¿Por qué no tener incluso una bandera experimental addImportsExtensions donde solo haría el module += '.js' , eso es todo! Sin lógica funky, sin características adicionales. Podría ser un objetivo diferente si prefiere mantenerlo como un objetivo separado. Más que eso, si acepta alguno de los anteriores, buscaré personalmente el código tsc y haré una PR para eso, simplemente no quiero perder mi tiempo si no se acepta de todos modos.

Simplemente puede usar una transformación personalizada para reescribir las importaciones en el código emitido (agregando '.js' o usando la ruta resuelta de las importaciones de módulos).

Cómo escribir una transformación de TypeScript
ttypescript: contenedor para tsc que aplica transformaciones durante la compilación

Tal vez ya haya una transformación existente que haga lo que necesita.

Sé que es posible, he jugado un poco con la API del compilador (aunque no tanto como me gustaría). La cuestión es que agrega una herramienta adicional al proyecto y las herramientas adicionales tienen mantenedores adicionales que pueden o no responder a los problemas lo suficientemente rápido (a menudo no por su culpa, todos tenemos vidas y trabajo). Los proyectos pequeños a menudo se abandonan, y hacer todo nosotros solo nos traslada la responsabilidad a nosotros, por lo que, en lugar de ocuparnos del código comercial, dedicamos tiempo a las herramientas.
Teniendo en cuenta lo anterior, muchos proyectos ni siquiera lo considerarán como una solución y, en su lugar, agregarán pasos de compilación adicionales, como resumen, etc., lo que agrega una sobrecarga de configuración adicional y nos devuelve al costo de mantenimiento adicional.
Para resumir: prefiero gastar mi tiempo en una PR para el TS oficial, donde tanto yo como la comunidad nos beneficiaríamos, que gastarlo en una solución personalizada que eventualmente podría abandonar (por no tener tiempo o por muchas otras razones ), o que no pueda ser utilizado por nadie más en el mundo.

@ajafff ​​Podría ser una solución, pero creo que el principal problema es el siguiente: el transpiler Typescript genera un código fuente incorrecto en los navegadores. Es bueno tener transformaciones, pero lo veo como una solución. Me pregunto si debo preocuparme por los detalles de la transpilación y necesito implementar mi propia transformación o si es algo que el compilador debería administrar.

Las transformaciones son una herramienta realmente poderosa, podríamos escribir un transpiler completamente nuevo como una transformación, pero creo que esta no es la forma correcta.

Sí, ya se ha propuesto al menos una vez, ¿por qué no tenerlo en cuenta? TS ya tiene algunas características experimentales

TypeScript tiene exactamente una marca experimental que se agregó hace 3 años y fue para una propuesta de ECMAScript que ya no es compatible con la propuesta actual.

el transpiler Typescript genera un código fuente incorrecto en los navegadores

Entiendo sus expectativas, pero dado que el compilador no reescribe las rutas que escribió, me sorprende que no considere que las importaciones de su propio código son "incorrectas". 😉

Lo siento @DanielRosenwasser , ¿has oído hablar de algo llamado npm? La gente publica sus paquetes allí para que todos podamos usarlo. Entiendo que pienses muy bien de mí, pero lamentablemente no soy autor de la gran mayoría de ellos, por lo que no puedo editarlos agregando las extensiones.
Si mis proyectos solo usaran mi código, estaría más agradecido por lo que trae el mecanografiado, ya que es realmente mi mano derecha en la codificación (aparte de WebStorm). Sin embargo, estoy usando paquetes de terceros como creo que la mayoría de nosotros y esos no necesariamente contienen las extensiones. Algunos proyectos, como rxjs, literalmente esperan con la esperanza de que TypeScript proporcione la forma de agregar extensiones; de lo contrario, sería necesario cambiar todo el proceso de compilación, por lo que volvemos a dedicar más tiempo a las herramientas en lugar del producto.
Ahora, por favor, ¿podría simplemente responder 3 preguntas?

  1. ¿El equipo de mecanografiado está dispuesto a enviar esta característica?
  2. En caso afirmativo, ¿aceptaría un PR?
  3. Si no, ¿cuándo planeas lanzar esto?

Si la respuesta a la primera pregunta es 'no', cierre este problema declarando oficialmente que NO está dispuesto a enviar esta función, no haga esperar a otros si no llega.

Sí, ya se ha propuesto al menos una vez, ¿por qué no tenerlo en cuenta? TS ya tiene algunas características experimentales

TypeScript tiene exactamente una marca experimental que se agregó hace 3 años y fue para una propuesta de ECMAScript que ya no es compatible con la propuesta actual.

el transpiler Typescript genera un código fuente incorrecto en los navegadores

Entiendo sus expectativas, pero dado que el compilador no reescribe las rutas que escribió, me sorprende que no considere que las importaciones de su propio código son "incorrectas". 😉

Es un buen punto @DanielRosenwasser , solo consideré correcto mi propio código porque parece estar bien al leer la especificación de Typescript (https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#11.3).

Estoy bastante seguro de que ha leído las especificaciones de ECMAScript. En la especificación no se determina si un módulo debe terminar con una extensión o no. En las especificaciones, la importación de módulos se resuelve mediante el algoritmo HostResolveImportedModule, pero la definición es ambigua. El problema no es la especificación ECMAScript. El problema es que los navegadores resuelven los módulos como si [ModuleRequest] como se define en las especificaciones fuera una ruta a los recursos.

Teniendo esto en cuenta, basta con ir a la página de inicio del idioma: https://www.typescriptlang.org/ .

En el pie de página se pueden leer las siguientes líneas:

Comienza y termina con JavaScript

TypeScript parte de la misma sintaxis y semántica que millones de desarrolladores de JavaScript conocen hoy. Use el código JavaScript existente, incorpore bibliotecas JavaScript populares y llame al código TypeScript desde JavaScript.

TypeScript se compila en código JavaScript simple y limpio que se ejecuta en cualquier navegador , en Node.js o en cualquier motor de JavaScript compatible con ECMAScript 3 (o posterior).


Prometes un código que se ejecuta en todos los navegadores, pero no parece ser cierto, por eso este problema persiste durante más de un año.

Como señala @Draccoz , solo queremos saber qué está haciendo con este problema. Pero es un poco frustrante leer una cosa en su página de inicio y lo contrario en este número.

No, no estamos dispuestos a enviar nada relacionado con esto hasta que haya al menos claridad sobre cosas como la interoperabilidad de ES en Node y una estrategia razonable para enviar dependencias transitivas que usaría desde npm en primer lugar. Si no estuviera utilizando TypeScript, tendría el mismo problema con respecto a la gestión y resolución de dependencias, por lo que no tiene sentido que propongamos algo que el ecosistema JS en general podría desarrollar de forma independiente. Pero incluso si esos problemas se resolvieran, no puedo garantizar que hagamos ningún cambio aquí, punto.

Prometes un código que se ejecuta en todos los navegadores, pero no parece ser cierto, por eso este problema persiste durante más de un año.

Creo que esta interpretación es demasiado literal. var fs = require('fs') no funciona cuando lo ejecuta en el navegador, HTMLDivElement no está definido en Node y String.prototype.startsWith no funciona en navegadores más antiguos. Para resolver esto, la gente ha creado herramientas y bibliotecas/polyfills fuera de TypeScript porque se aplican al ecosistema de JavaScript más amplio.

Entonces, ¿puedes cerrar este problema? Este es un bloqueador para otros proyectos que esperan que TS lo haga o declare que no lo está haciendo. Si no puede simplemente agregar una bandera simple, cierre este problema y haga que otros conozcan sus decisiones.

@DanielRosenwasser Gracias por su rápida respuesta, realmente lo aprecio. Creo que es una sabia elección.

Creo que esta interpretación es demasiado literal. var fs = require('fs') no funciona cuando lo ejecuta en el navegador, HTMLDivElement no está definido en Node y String.prototype.startsWith no funciona en navegadores más antiguos. Para resolver esto, la gente ha creado herramientas y bibliotecas/polyfills fuera de TypeScript porque se aplican al ecosistema de JavaScript más amplio.

Por supuesto que lo es, pero ¿qué más puede pensar alguien que no sabe nada de Typescript? El hecho de que mi interpretación sea demasiado literal es tan cierto como el hecho de que este texto puede "confundir" a cualquiera que no sepa nada de Typescript 😉.

Tal vez podría actualizar sus documentos (https://www.typescriptlang.org/docs/handbook/modules.html) para reflejar el comportamiento real.

@DanielRosenwasser gracias nuevamente por su respuesta. He estado esperando algo similar durante un año.

La razón por la que quería esta función era para poder ver qué tipo de aplicación web podía crear sin ninguna herramienta de compilación. Hasta entonces, puedo usar ese guión que escribí antes.

Para las personas como yo que buscan una solución para poder usar módulos ES y TypeScript en el navegador hoy, encontré https://github.com/guybedford/es-module-shims. Actúa como una especie de relleno múltiple para los mapas de nombres de paquetes mientras esperamos la finalización de las especificaciones y la implementación del navegador. Resuelve el problema de @QuantumInformation de querer no usar ninguna herramienta de compilación (mi problema también) al crear una aplicación web simple en TypeScript (aparte del compilador 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 teoría, una vez que los mapas de nombres de paquetes son compatibles con los navegadores, puede simplemente buscar/reemplazar type='module-shim' con type='module' en sus archivos HTML y cambiar la secuencia de comandos del mapa del paquete a lo que termine siendo finalizado para la inclusión del mapa del paquete en el Especificaciones.

Probablemente también valga la pena señalar que la extensión .js no es obligatoria para los navegadores ni nada por el estilo: siempre puede configurar su servidor web para que sea más unpkg y sirva .js archivos desde URL de solicitud sin extensión. Todo es configurable en el lado del servidor web.

Sin embargo, @weswigham eso puede ser muy problemático, porque tsc (y la resolución clásica del módulo de nodo) sabrán que ./foo y ./foo.js se refieren al mismo archivo, pero los navegadores los tratarán de manera diferente, incluso si el redirecciones del servidor web. Debería asegurarse de hacer referencia a un archivo exactamente de la misma manera en cada importación.

Por cierto, este problema no impide que los módulos generados por TypeScript se utilicen en los navegadores actuales. Importe siempre archivos con la extensión .js . tsc hace lo correcto y resuelve los tipos del archivo .ts , y obtiene compatibilidad con el navegador.

@weswigham Tenga en cuenta que hay situaciones en las que entrega archivos sin tener acceso al servidor web. GitHub Pages, IPFS, S3, etc. Con la llegada de los marcos de aplicación de una sola página, se está volviendo cada vez más común ejecutar "sin servidor" (donde sin servidor aquí significa sin un servidor que usted controle/configure para atender sus activos), por lo que no puede confiar en los filtros del lado del servidor para servir apple.js cuando se realiza una solicitud de apple .

Debería asegurarse de hacer referencia a un archivo exactamente de la misma manera en cada importación.

Siempre puede hacer uno u otro 404 dependiendo de su preferencia de autor. Si usó enlaces simbólicos dentro de su proyecto, causarían un problema similar que también tendría que elegir cómo tratar.

Solo importa siempre archivos con la extensión .js

Sí, eso también funciona bien.

@QuantumInformation ¿Su fragmento utilizado aquí es para uso abierto? ¿Puedo usarlo en un proyecto? 😃

@distante sí, puedes usarlo

Para su información, si está utilizando Jest para probar y cambiar las extensiones a .js en la fuente, se rompe
pero puede agregar lo siguiente a su configuración de broma para arreglar eso

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

Hola @MrAntix ,

Creo que jest es la biblioteca que debería adaptarse a TypeScript, no al revés.

Tengo otro sitio con el que no quiero usar una herramienta de compilación. ¿Es esto lo mejor que estamos en:

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

Como solución alternativa, puede hacerlo así (aunque es un archivo ts, no js) 😢

Screenshot 2019-06-05 at 22 47 49

Si alguien quiere probarlo:
https://github.com/QuantumInformation/web-gen-bot

Sin embargo, no puedo hacer que la depuración de la fuente funcione con el tsconfig actual, informaré de nuevo.

Al final, volví al paquete web, node_modules fue el asesino cuando intenté alejarme de las herramientas de compilación en el navegador.

No es solo broma: si usa tsc para compilar TypeScript antes de publicarlo, cualquier módulo JS que importe el paquete resultante se romperá debido a las diferencias en la resolución del módulo.

La discusión aquí parece haberse bifurcado un poco en dos cuestiones relacionadas pero en última instancia separadas:

  • Typescript debe generar archivos que se puedan cargar de forma nativa en un navegador
  • Typescript debería resolver el hecho de que las rutas de los módulos de nodos no siempre son direcciones URL válidas.

Creo que debemos centrarnos en el primer problema, ya que el segundo es claramente algo que el mecanografiado no puede resolver por sí solo.

Sin embargo, el primer problema es absolutamente algo que Typescript puede resolver y debe priorizar, ya que es un obstáculo importante para la mayoría de las personas que desean usar Typescript para crear aplicaciones web dirigidas a los navegadores modernos.

En mi opinión, el problema se reduce a esto:

Si ejecutar tsc genera un archivo con una extensión .js y luego otro archivo que importa el primer archivo .js , no hay ambigüedad sobre qué extensión usar, y debería haber un opción de incluir la extensión.

Para todas las declaraciones de importación que apuntan a archivos que no sean los archivos que genera Typescript, creo que está bien dejarlos sin cambios (como lo hace Typescript hoy).

Según la primera opción, creo que un argumento de línea de comando sería mejor y estaría desactivado de forma predeterminada. Digo esto porque, si uso un paquete web, no quiero que se agregue .js a las importaciones, ya que el paquete web se encarga de la agrupación de módulos.

De todos modos, node_modules fue el asesino que me impidió usar el truco para las aplicaciones de navegador de módulos nativos.

Digo esto porque, si uso un paquete web, no quiero que se agregue .js a las importaciones, ya que el paquete web se encarga de la agrupación de módulos.

Sin embargo, Webpack maneja la extensión .js perfectamente bien, por lo que no hay diferencia.

De hecho, a veces es necesario usar .js con Webpack (en las situaciones en las que hay varios archivos con el mismo nombre pero diferentes extensiones).

Entonces, ¿podría explicar más sobre por qué no desea importar .js con Webpack?

Cuando digo I don't want quise decir que no necesito para mis casos de uso.

No veo una razón convincente por la que no debería ser el comportamiento predeterminado entonces (siempre reacio a agregar otra bandera de configuración...)

Establecer las importaciones en .js hace que ts-node deje de funcionar correctamente para el archivo. Esto se debe a que ts-node solo compila un archivo a la vez y si el contenido del archivo emitido termina en require('./foo.js') , cuando nodejs procese ese archivo, intentará cargar ./foo.js que no existe en cualquier lugar del disco y, por lo tanto, fallará. Cuando el código requiere ( ./foo ), por otro lado, se llamará al controlador de ts-node, momento en el que puede compilar ./foo.ts en JS y devolverlo.

Si TypeScript emite .js extensiones en todos los casos, ts-node se encontrará con el mismo problema. Sin embargo, si hay una opción para alternar si una extensión se agrega automáticamente o no, entonces ts-node puede desactivar esa opción del compilador, lo que permitirá que el sistema actual continúe funcionando.

Dado que Node.js --experimental-modules requiere extensiones de archivo obligatorias, la API para esto es sencilla sin necesidad de un análisis de dependencia: una opción como --jsext puede reescribir cualquier extensión .ts en .js extensión. Las importaciones de JSON/otro formato también pueden funcionar bien con esto, siempre que el usuario ya haya incluido explícitamente todas sus extensiones. El único caso problemático es un nombre de paquete que termina en .ts como import 'npmpkg.ts' . Este caso es extremadamente raro, pero para manejarlo de manera integral en la resolución, la regla podría ser hacer una excepción para _especificadores básicos_ en la línea de - si el especificador básico (no una URL o ruta relativa) es un nombre de paquete npm válido ( haciendo coincidir /^(@[-_\.a-zA-Z\d]+\/)?[-_\.a-zA-Z\d]+$/ , de https://github.com/npm/validate-npm-package-name), luego ignore las extensiones .ts en la reescritura.

Creé un transformador de compilador de TypeScript que agregará una extensión de archivo .js a cualquier ruta de importación relativa. Esto significa que si su archivo .ts tiene import { Foo } from './foo' , emitirá import { Foo } from './foo.js' . Está disponible en NPM, y las instrucciones sobre cómo usarlo se pueden encontrar en el archivo Léame del proyecto.

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

Si se integrara algo como esto en el compilador de TypeScript (como una opción del compilador), probablemente debería ser más inteligente decidir cuándo agregar la extensión .js y cuándo no. En este momento, busca cualquier ruta que comience con ./ o ../ y que no tenga . en ningún otro lugar de la ruta. Esto significa que no hará lo correcto en varios escenarios de casos extremos, aunque me pregunto si alguien _en realidad_ se encontrará con esos casos extremos o no.

@MicahZoltu genial para ver soluciones de usuario para esto. Sin embargo, creo que es bastante importante que el modelo mental siempre incluya extensiones de archivo , de modo que la opción de extensión de TypeScript pueda convertirse en _convertir extensiones .ts en extensiones .js en compilación_. Eso evita los casos extremos de resolución, dejando solo el caso de los nombres de paquetes npm que terminan en ".ts", que se pueden manejar como discutí en mi comentario anterior.

@guybedford Incluir la extensión .js en un archivo .ts hace que el archivo no se pueda ejecutar en ts-node. Resolver el problema en ts-node está lejos de ser trivial debido a la forma en que NodeJS resuelve los archivos. Esto significa que si publica una biblioteca con extensiones .js codificadas, la biblioteca no funcionará para nadie que use ts-node. Vea la discusión sobre esto en https://github.com/TypeStrong/ts-node/issues/783.

@MicahZoltu Me refiero a incluir la extensión .ts en un archivo .ts .

@guybedford Incluir la extensión .js en un archivo .ts hace que el archivo no se pueda ejecutar en ts-node.

Esta es otra razón más por la cual la ejecución automática de TypeScript en nodos y navegadores es una mala idea.

@MicahZoltu Me refiero a incluir la extensión .ts en un archivo .ts.

Creo que el problema con esto es que rompe la equivalencia entre un archivo .ts y un par .js / .d.ts . Esto significa que si está importando un archivo que está compilado con el proyecto actual, usa .ts , y si mueve el archivo a un proyecto diferente, necesita cambiar las importaciones para usar .js .

También significa que la salida no funciona en entornos estándar sin el transformador. Dado que no hay forma de instalar un transformador desde un archivo .tsconfig , eso significa que siempre debe usar un compilador personalizado. Esa es una barrera bastante grande para implementar por el pequeño beneficio de usar .ts en lugar de .js .

Esto significa que si está importando un archivo que está compilado con el proyecto actual, usa .ts, y si mueve el archivo a un proyecto diferente, necesita cambiar las importaciones para usar .js.

Los límites de importación externos/internos son cosas bien definidas. Si una dependencia pasa de ser un archivo interno .ts de la misma compilación actual a ser un archivo externo .js de otra importación de paquete que tiene su propia compilación separada o quizás incluso no es TypeScript , entonces sí, tienes que cambiar la extensión ya que es un concepto completamente diferente.

También significa que la salida no funciona en entornos estándar sin el transformador.

Si bien un transformador puede ayudarnos a explorar esto, se necesita mucho un indicador/opción de compilador --ts-to-js o similar para resolver este problema.

@guybedford Me convenciste de que poner .ts era lo correcto para el complemento. Sin embargo, al intentar implementarlo, aprendí que TypeScript en realidad no lo permite.

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

Hola, ¿Qué tal esto?


aporte:

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

console.log(result);

producción:

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

console.log(result);

número 30076

Una sola extensión .ts en un archivo TypeScript me parece más apropiada. A menudo, no se sabe hasta el momento de la compilación cuál es el objetivo. Por ejemplo, en muchos de mis proyectos de biblioteca, tengo varios archivos tsconfig.json que se dirigen a diferentes entornos, como navegadores modernos que deberían emitir archivos .js y asignar rutas de importación a .js , o apuntar a un nodo moderno, que debería emitir archivos .mjs y asignar rutas de importación a .mjs .

@MicahZoltu que importar archivos que terminan en .ts es un error es posiblemente para nuestro beneficio en realidad. Porque esto significa que la extensión .ts a .js reescrita en la compilación se puede agregar siempre que se usen las extensiones .ts sin necesidad de una bandera :)

Tal vez un PR para permitir que las extensiones finales .ts sean compatibles y reescritas a extensiones de .js (posiblemente bajo una bandera para habilitar esta función, pero una bandera que se puede eliminar a tiempo) sería una excelente manera para emprender este camino.

//cc @DanielRosenwasser

Este problema ya es muy largo, por lo que es posible que alguien ya lo haya dicho, por lo que corre el riesgo de repetir lo que ya se ha dicho:

TypeScript debería permitir a los desarrolladores especificar extensiones en import s porque es JavaScript válido. ¡Y esto no se trata solo de la extensión JS/TS! En ESM, cualquier extensión es válida siempre que el tipo MIME sea correcto.

import actuallyCode from './lookLikeAnImage.png';

…debería ser válido siempre que el servidor sirva JavaScript válido en ese archivo y establezca el tipo MIME correcto. ¡Esto va más allá ya que lo mismo podría ser cierto para TS! Un archivo TS podría ser solo un código fuente JS servido con el tipo JS MIME y, por lo tanto, una ruta válida para la importación de un módulo ESM.

IMO TypeScript solo debe considerar las importaciones sin una extensión (como lo quiere hoy) y dejar las que no tienen errores, advertencias, etc. De lo contrario, rechaza el código JavaScript válido, lo cual es bastante desafortunado para algo que dice ser un superconjunto de JS.

Lo siento si este no es el lugar correcto para plantear esto, vi algunos otros problemas: #18971, #16640, #16640 pero los problemas sobre este tema parecen cerrarse de izquierda a derecha, así que asumo que este es el "principal". ya que se le permitió permanecer abierto.

Jugando con 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'
}

Ahora, no estoy seguro de por qué esto es molesto...

Por el momento, TypeScript no reescribe las rutas. Definitivamente es molesto, pero actualmente puede agregar la extensión .js usted mismo.

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

¿Qué pasa con la implementación detrás de una opción? ¿Te gusta --rewrite-paths ( rewritePaths: true )?

@ viT-1 Aquí hay una solución por el momento: https://github.com/microsoft/TypeScript/issues/16577#issuecomment -507504210

@MicahZoltu Acabo de resolver mi caso de uso mediante el paquete SystemJS (opción tsconfig outFile)

No he leído todos los comentarios que la gente ha escrito sobre esto, pero no entiendo por qué tengo que escribir .js un millón de veces. Quiero que la computadora lo haga por mí.

@richardkazuomiller Todos lo hacemos, pero @DanielRosenwasser declaró en https://github.com/microsoft/TypeScript/issues/16577#issuecomment -448747209 que no están dispuestos a hacer eso por ahora (me sorprende que este problema siga abierto engañosamente tanto tiempo después de la declaración anterior). Si desea que la computadora haga eso por usted, considere usar un paquete o alguna herramienta de terceros para manejar las reescrituras de rutas de importación.

Quien quiere que cierre este tema?

No cierre, todavía estoy esperando ver cómo responderá el equipo de TypeScript sobre cómo abordarán las importaciones de ESM que permiten el uso de cualquier extensión y confían en el tipo MIME en su lugar. Por el momento esto es posible en JavaScript pero no en TypeScript. (Por favor vea mi comentario anterior para más detalles.)

@TomasHubelbauer Esta es la razón por la que propuse una bandera en el archivo de configuración, podría indicar que todas las importaciones sin extensión deberían tener la extensión .js (o cualquier otra configurada) agregada. Esto sería opcional, por lo que el valor predeterminado podría ser falso, haciendo que los proyectos existentes o los proyectos con diferentes necesidades funcionen tal como están.

Como se dijo anteriormente:

No estoy seguro de qué versión de TS lo agregó, pero las importaciones como ' ./file.js' ahora funcionan (incluso si el archivo es realmente file.ts).
TypeScript resuelve bien el archivo y genera la importación completa .js en el destino.

Esto tiene sentido porque cualquier JavaScript válido es TypeScript válido. Ya que puedes hacer:

import foo from './bar.js'

...en JS, también debería poder hacerlo en TS. Si hace eso, resuelve el problema de usar módulos ES6 nativos porque tiene las extensiones correctas.


Tampoco olvidemos que cuando el navegador ve una importación de ./foo/bar , en realidad lo solicita. El hecho de que no se sirviera nada se debió al servidor. Puede configurarlo de manera que las solicitudes de /foo/bar se satisfagan con /foo/bar.js . No digo que esta sea una buena solución, o incluso una buena idea , pero técnicamente funcionaría.

indicador en el archivo de configuración, podría indicar que todas las importaciones sin extensión deben tener la extensión .js (o cualquier otra configuración configurada) agregada

Esto resolvería la gran mayoría de los casos. ¿Estaría el equipo de TypeScript dispuesto a considerar un PR para esta opción de configuración?

NodeJS ahora _por defecto_ se comporta de la misma manera que los navegadores cuando se trata de la resolución del módulo de ruta relativa. Ya no inferirá una extensión .js de forma predeterminada. Esto significa que el comportamiento actual de TSC da como resultado la emisión de JS que no es válido en todos los contextos de tiempo de ejecución. Parece que este problema ahora debe abordarse, ya que hay claridad en el comportamiento del navegador y de NodeJS para ESM.

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

El nuevo resolutor para esm necesita un nuevo modo de resolución: moduleResolution: node realmente es solo el resolutor de cjs para lo que ahora puedo llamar "versiones antiguas de nodo". Si tiene la intención de apuntar al nuevo solucionador de esm, necesitaremos un nuevo modo de resolución para que coincida de manera más adecuada. Especialmente porque el nodo aún es totalmente compatible con el viejo resolver en todas las configuraciones existentes. (Nota: hacer que un nuevo solucionador de este tipo sea _nuestro predeterminado_ sería difícil)

¡Aunque! Si bien hay _desacuerdo_ al respecto y _algunas personas optarán por declarar la opinión como un hecho_, todavía hay un indicador --es-module-specifier-resolution=node que devuelve el comportamiento de extensión esperado y aún puede convertirse en el predeterminado, como dicen los documentos, a pesar de no estar marcado. , los módulos es en el nodo son _todavía de naturaleza experimental_.

Además, como recordatorio de la solicitud original: no reescribimos las importaciones. Siempre. En absoluto. Especificador de entrada === especificador de salida. Los especificadores describen la intención estructural y no es nuestro objetivo hacer un mapa implícito de una estructura prevista a otra. También podría pensarlo de esta manera: si escribiera const varFoo = "./Foo"; import(varFoo) , ¿de alguna manera agregaríamos la extensión allí, si es necesario? No, eso es ridículo, para manejar todas las formas de entrada dinámica necesitaríamos envolver la importación dinámica en el tiempo de ejecución, y de repente nos convertimos en un cargador de módulos propio, capa sobre el cargador de plataforma integrado. En su lugar, proporcionaríamos un modo de resolución que genera errores de forma adecuada cuando omites la extensión (para lo cual, por supuesto, ya puedes encontrar reglas de lint).

Si encuentra este hilo y _realmente quiere_ que sus fuentes de entrada no tengan extensiones, y _realmente necesita_ que su salida siga funcionando con eso cuando se dirige a módulos (nodos), debe proporcionar sus comentarios en https://github.com/ nodejs/modules/issues/323 con su justificación, para que pueda funcionar de esa manera en la plataforma de destino, ya que eso es en última instancia a lo que nos referimos.

de repente nos hemos convertido en un cargador de módulos propio

¿No tiene que ser tsc un cargador de módulos funcional pase lo que pase? No puede verificar el tipo de una importación si no puede encontrar el módulo del que proviene. Solo quiero ver que todos los diversos cargadores de módulos se comporten de una manera ampliamente compatible, o al menos de una manera predeciblemente diferente que sea razonablemente fácil de acomodar.

NodeJS ahora se comporta de manera predeterminada de la misma manera que los navegadores cuando se trata de la resolución del módulo de ruta relativa. Ya no inferirá una extensión .js de forma predeterminada. Esto significa que el comportamiento actual de TSC da como resultado la emisión de JS que no es válido en todos los contextos de tiempo de ejecución.

¿No es esta otra razón para usar las extensiones de archivo .js en especificadores como los que TypeScript ya admite? Eso resuelve todo, excepto que sería genial si tsc tuviera un error en las importaciones sin extensión.

¿No tiene que ser tsc un cargador de módulos funcional pase lo que pase? No puede verificar el tipo de una importación si no puede encontrar el módulo del que proviene. Solo quiero ver que todos los diversos cargadores de módulos se comporten de una manera ampliamente compatible, o al menos de una manera predeciblemente diferente que sea razonablemente fácil de acomodar.

No pretendemos proporcionar una implementación de cargador de tiempo de ejecución, solo un análisis de tiempo de compilación que refleje cualquier cargador de tiempo de ejecución al que se dirija. No podemos reasignar todas las importaciones sin un componente de tiempo de ejecución, que no tenemos ni pretendemos tener.

¿No tiene que ser tsc un cargador de módulos funcional pase lo que pase?

No en tiempo de ejecución. tsc necesita comprender cómo el tiempo de ejecución elegido resolverá los especificadores e implementará eso en el momento de la compilación, pero el tiempo de ejecución se deja exclusivamente en manos del entorno.

También podría pensarlo de esta manera: si escribió const varFoo = "./Foo"; import (varFoo) ¿de alguna manera agregaríamos la extensión allí, si es necesario?

@weswigham Este es un argumento sólido con respecto a las importaciones dinámicas, pero no _creo_ que pueda hacer eso con las importaciones estáticas. Puedo apreciar el argumento de que la estrategia debería ser la misma para ambos, pero creo que vale la pena mencionar que las importaciones estáticas cumplen un papel muy diferente al de las importaciones dinámicas y no creo que sea totalmente _irrazonable_ tener una estrategia diferente para las importaciones estáticas. reescritura de importación y reescritura de importación dinámica.

¿No es esta otra razón para usar las extensiones de archivo .js en especificadores como los que TypeScript ya admite? Eso resuelve todo, excepto que sería genial si tsc tuviera un error en las importaciones sin extensión.

@justinfagnani Hay dos problemas con eso:

  1. Un tiempo de ejecución que ejecuta TS de forma nativa (como TS-Node) no funcionará si especifica extensiones .js en sus importaciones.
  2. Le está mintiendo al compilador (IMO) si incluye extensiones .js en sus importaciones.

Con respecto a (2), si tengo dos archivos TS a.ts y b.ts y a.ts hace import ... from './b.js' , le digo al compilador que tengo un archivo hermano llamado b.js . Esta afirmación no es cierta. Para empeorar las cosas, si tiene .b.ts y b.js (que en realidad pueden no ser derivados uno del otro), es ahora se vuelve ambiguo a cuál te refieres _a pesar de que explícitamente incluyeste una extensión_.

Soy de la opinión de que el usuario debe decirle al compilador lo que realmente quiere (como usuario) y eso es "importar cualquier archivo con un nombre de X y cualquier extensión" (en el caso de import ... from './foo' ) o "importar específicamente este archivo" (en el caso de import ... from './foo.ext' ). Si el compilador detecta que está importando un archivo TS y procede a emitir un archivo .js , entonces creo que el compilador debería actualizar la importación para importar correctamente el archivo apropiado. Esto puede significar cambiar .ts a .js en la declaración de importación.

@justinfagnani Hay dos problemas con eso:

  1. Un tiempo de ejecución que ejecuta TS de forma nativa (como TS-Node) no funcionará si especifica extensiones .js en sus importaciones.

Este es un error en TS-Node. No coincide con el comportamiento de tsc .

  1. Le está mintiendo al compilador (IMO) si incluye extensiones .js en sus importaciones.

En realidad, es lo contrario: está diciendo la verdad sobre lo que realmente se importará. _No_ importará un archivo .ts , sino un archivo .js . Tampoco debería haber una diferencia visible entre un par .d.ts / .js y un archivo .ts . Son intercambiables. La única forma adecuada de lograrlo es importar el archivo .js #$6$#$, lo que será el archivo .ts después de la compilación.

@justinfagnani

Tampoco debería haber una diferencia visible entre un par .d.ts/.js y un archivo .ts

Esto no siempre es cierto. Puede configurar su servidor para servir todos los JS, TS y DTS con un tipo JS MIME y luego importarlos todos por separado en JavaScript y el tiempo de ejecución los ejecutará debidamente como JS. A ESM no le importan las extensiones en absoluto.

Es por eso que creo que los usuarios de TS deberían verse obligados a incluir una extensión .ts y sin extensión sería un error a menos que realmente importen un archivo sin extensión o ese nombre. Y TS reescribiría las importaciones a .js en la salida. Y si existiera un archivo JS (no uno generado por TS) eso también sería un error.

Este es un error en TS-Node. No coincide con el comportamiento de tsc.

Es una limitación del cargador NodeJS, no un error en TS-Node: https://github.com/TypeStrong/ts-node/issues/783#issuecomment -507437929

Esto no siempre es cierto. Puede configurar su servidor para servir todos los JS, TS y DTS con un tipo JS MIME y luego importarlos todos por separado en JavaScript y el tiempo de ejecución los ejecutará debidamente como JS. A ESM no le importan las extensiones en absoluto.

Soy muy consciente de eso, pero el navegador tampoco ejecutará TypeScript. Es casi universalmente cierto que el archivo que el entorno realmente carga es un archivo JavaScript.

Sin embargo, mi punto es que si ya tiene un par .js / .d.ts , digamos de un paquete de terceros, e importe el archivo .js , tsc vea el archivo .d.ts y cargue los tipos. es decir, un par .js / .d.ts _actúa_ como un archivo .ts , y así es como debería ser, ya que así es como puede migrar de forma transparente de JavaScript a TypeScript sin cambiar las importaciones de los archivos que se portan.

Este es un error en TS-Node. No coincide con el comportamiento de tsc.

Es una limitación del cargador NodeJS, no un error en TS-Node: TypeStrong/ts-node#783 (comentario)

Todavía es un error que TS-Node se esté desviando del comportamiento tsc . Eso hace que los archivos .ts no funcionen tanto en tsc como en TS-Node, y consideraría firmemente a tsc como el emisor de estándares que debería seguir TS-Node .

Sin embargo, mi punto es que si ya tiene un par .js/.d.ts, digamos de un paquete de terceros, e importe el archivo .js, tsc verá el archivo .d.ts y cargará los tipos. es decir, un par .js/.d.ts actúa como un archivo .ts, y así es como debería ser, ya que así es como puede migrar de forma transparente desde JavaScript a TypeScript sin cambiar las importaciones de los archivos que se transfieren.

Si carga un _paquete_ externo, entonces necesitará un cargador de paquetes en tiempo de ejecución de algún tipo (por ejemplo, mapas de importación con nombre en el navegador) que haga la asignación del módulo con nombre al archivo de punto de entrada. Sin embargo, creo que su punto generalmente se mantiene, en el caso de que tenga un par relativo .js/.d.ts. Estoy indeciso si en ese caso deberías hacer import ... from './foo.d.ts' o import ... from './foo.js' .

El archivo .d.ts es esencialmente un encabezado que describe la estructura que no contiene información sobre la extensión desde la que se asigna (suponiendo que, por lo general, no debe tener varios archivos con el mismo nombre pero con diferentes extensiones en el mismo lugar, y cometemos un error en la compilación si lo hace), incluso hoy en día, la "fuente" de tiempo de ejecución asociada podría ser .js o .jsx (usando jsx: preserve ). En términos generales, no podría reemplazar una referencia .d.ts con .js en una importación en el momento de la emisión y asumir que funciona...

Es importante exactamente que tsc no sea demasiado obstinado en cuanto a la más amplia
supuestos de construcción y resolución.

Dado que es una herramienta múltiple en un límite complejo, se esperaría
esa configuración podría permitirle comportarse de la manera que los usuarios quieren.

Ha habido un esfuerzo muy deliberado para no exponer los cambios de resolución como
parte del proceso de compilación de tsc; esto en sí mismo fuerza la opinión sobre
usuarios y causa fricciones en sus flujos de trabajo.

El miércoles 27 de noviembre de 2019 a las 16:48 Wesley Wigham [email protected]
escribió:

El archivo .d.ts es esencialmente un encabezado que describe la estructura que contiene
no hay información sobre la extensión desde la que se mapea (suponiendo que
por lo general, no debería tener varios archivos con el mismo nombre, pero
diferentes extensiones en el mismo lugar) - incluso hoy en día, el asociado
la "fuente" en tiempo de ejecución podría ser .js o .jsx (usando jsx: preserve). Tú podrías
no, en términos generales, reemplazar la referencia .d.ts con .js en una importación en el momento de la emisión
y supongamos que funciona...


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/microsoft/TypeScript/issues/16577?email_source=notifications&email_token=AAESFSQS2DQ23RR5KN3RTZ3QV3TLXA5CNFSM4DPRQTY2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFK2TPA#issuecomment-555
o darse de baja
https://github.com/notifications/unsubscribe-auth/AAESFSUAP2YO23ZFHCOWVQLQV3TLXANCNFSM4DPRQTYQ
.

No estoy seguro de cómo manejar este escenario, pero tenía una duda relacionada con lo mismo.

Tengo un mapa de importación como este en mi archivo html:

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

Y tengo mi archivo ts donde estoy importando un archivo como este:

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

Ahora, esta configuración funciona bien en el navegador. Pero, ¿cómo podré navegar/usarlo en VSCode? Quiero decir, quiero hacer ctrl+clic en la importación y navegar hasta el archivo, obtener autocompletar, escribir definición, etc.

Además, teniendo en cuenta que tsc no reescribe las extensiones de importación de .ts a .js, ¿hay alguna otra herramienta/paquete recomendado que pueda usar para hacer lo mismo en el momento de la compilación? Gracias.

(Estoy usando https://github.com/guybedford/es-module-shims para módulos ES e importar mapas)

Pero, ¿cómo podré navegar/usarlo en VSCode?

Busque la opción del compilador paths .

Además, teniendo en cuenta que tsc no reescribe las extensiones de importación de .ts a .js, ¿hay alguna otra herramienta/paquete recomendado que pueda usar para hacer lo mismo en el momento de la compilación? Gracias.

Simplemente use .js y funcionará bien, incluso si se refiere a un archivo .ts en el momento de la compilación.

@tvvignesh https://github.com/Zoltu/typescript-transformer-append-js-extension/ para reescribir importaciones sin extensión a .js en tiempo de compilación. Personalmente, no soy un fanático de "simplemente coloque .js en sus archivos TS" porque su código no se ejecutará en ts-node si lo hace. Si no necesita ejecutar su código en ts-node, entonces usar .js funcionará.

Pero, ¿cómo podré navegar/usarlo en VSCode?

Busque la opción del compilador paths .

Además, teniendo en cuenta que tsc no reescribe las extensiones de importación de .ts a .js, ¿hay alguna otra herramienta/paquete recomendado que pueda usar para hacer lo mismo en el momento de la compilación? Gracias.

Simplemente use .js y funcionará bien, incluso si se refiere a un archivo .ts en el momento de la compilación.

Gracias por su respuesta rápida. Ya había configurado la opción de rutas en tsconfig.json pero aún no podía navegar con ctrl+clic.

Esta es mi opción de rutas en tsconfig.json

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

Simplemente use .js y funcionará bien, incluso si se refiere a un archivo .ts en el momento de la compilación.

Esto es bastante poco práctico cuando hay miles de importaciones.

El problema con "simplemente use .js " es que si TypeScript emite archivos .mjs , entonces su programa no funciona. Esto significa que termina en una situación en la que está escribiendo TypeScript que _o_ funciona en el navegador _o_ funciona en NodeJS. Ya no puede escribir TypeScript que funcione en ambos.

Creo que el argumento aquí es: "Eso no es culpa de TypeScript, es que el navegador y NodeJS divergen".

Node 13.2 admite extensiones .js muy bien.

@justinfagnani ¿ Para módulos ES? Pensé que NodeJS solo cargaría módulos ES si tenían una extensión .mjs , de lo contrario, los archivos se tratarían como CommonJS.

Siento que todo este hilo está un poco equivocado. Escribir explícitamente la extensión del archivo resolvería todo este problema. Si está importando un archivo JavaScript, escriba la extensión .js. Si está importando un archivo TypeScript, escriba la extensión .ts. Esto está permitido en el estándar y el compilador de TypeScript lo entiende todo igualmente bien. El único problema es que el compilador indica que las extensiones .ts son errores. Esto no afecta una transpilación pura, sino que es solo un error de tipo. TypeScript debería arreglar esto, ya que obviamente una extensión de archivo .ts es válida, ya que estamos creando en TypeScript. Para solucionar este problema, Deno.js tiene una extensión de VS Code: https://marketplace.visualstudio.com/items?itemName=justjavac.vscode-deno

Con la llegada de WebAssembly, las aplicaciones web comenzarán a importar más y más tipos de archivos. Será cada vez más importante indicar explícitamente si está importando un archivo .wasm, .js, .ts, .rs, .c, etc.

¿Alguien realmente usó el guión que escribí?

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

¿Algún comentario si es así?

@QuantumInformation No he usado su secuencia de comandos, pero el complemento de transformador de TypeScript que escribí hace básicamente lo mismo. 😊 https://github.com/Zoltu/typescript-transformer-append-js-extension/

En primer lugar, no intentaré nuevamente convencer a TypeScript para que lo implemente, lo entiendo, no lo harás.
Sin embargo, estoy leyendo los comentarios y me pregunto: todas esas personas que dicen que agregar .js a las rutas lo resolverá todo, ¿realmente no usan paquetes de terceros? ¿Cómo agrego extensiones a mis importaciones arreglando lo que hay en node_modules?

@MicahZoltu oh bueno

¿Qué quieres decir? Debe escribir explícitamente la extensión de archivo del archivo que está importando desde node_modules, si usa una ruta. Pero, ¿no sería eso una simple importación de todos modos?

Si especifica una ruta relativa, no estará vacío. Sin embargo, estoy hablando de importaciones internas del paquete que estoy importando, mire rxjs, por ejemplo.

@Draccoz Creo que lo que se quiere decir es que si alguien escribe TypeScript como import { ... } from './foo' y luego lo publica como un paquete NPM, un usuario no puede usar esa biblioteca directamente en un navegador, incluso si apunta a módulos ES. Creo que el argumento de Microsoft aquí es que el paquete es incorrecto si está distribuyendo código como ese con la expectativa de que funcione en un navegador.

Escribiría la extensión del archivo que existe en node_modules. import * as stuff from 'rxjs/path/to/file.js'; si es un archivo JavaScript y import * as stuff from 'rxjs/path/to/file.ts'; si distribuyeron un archivo TypeScript. Esto funciona ahora mismo si no me equivoco

@lastmjs Sí, pero ¿y si rxjs/path/to/file.ts contiene import foo from './bar' ? No puede cambiar eso, ya que no puede modificar el archivo, ya que es una biblioteca de terceros.

Es por eso que deberíamos impulsar el uso de extensiones explícitas en todas partes, pero sí, entiendo su punto. Mi herramienta (https://github.com/lastmjs/zwitterion) hace esta reescritura como una solución provisional para aquellos archivos que no tienen extensiones.

Sí, mi punto era exactamente ese: solo agregar extensiones no arreglará las bibliotecas de terceros que no podemos modificar, por lo que no es una solución.
También entiendo el punto de Microsoft, por lo tanto, no lo presionaré más (aparte del hecho de que mantener este problema abierto da una esperanza innecesaria que impide que los mantenedores de paquetes solo ajusten la compilación en lugar de esperar a que TS resuelva esto), sería Sin embargo, sería increíble tener solo mecanografiado como herramienta de compilación y ninguna otra dependencia.

sí, pero claramente la esperanza sigue siendo buena para muchas personas

image

Aún así, se dijo un par de veces a través de esos comentarios que NO se implementará, entonces, ¿por qué mantenerlo abierto?

si alguien escribe TypeScript como importar {...} desde './foo' y luego lo publica como un paquete NPM

¿Muchas personas publican TS sin compilar en paquetes NPM? Estaba mirando esto para mi propio uso interno. Estoy creando bibliotecas de código común compartidas entre proyectos y pensé que NPM es una forma razonable de empaquetarlas, y nuestro equipo se ha mudado a TS exclusivamente, por lo que me complacería evitar tener que compilar las dependencias. Pero parece que el caso de uso más común es compilar el paquete para JS con tipos separados, luego apuntar modules o main al JS y types a los tipos.

¿Existe una convención para publicar TS sin compilar en NPM? Si es así, ¿está esto documentado en alguna parte? Entiendo que esto es OT errante del problema original, pero creo que es relevante para la respuesta, porque necesitamos saber si "TypeScript de terceros" (paquetes) es un caso de uso / objetivo compatible.

@thw0rted Perdón por no ser claro, quise decir:

...si alguien escribe TypeScript como import { ... } from './foo' y luego transpila eso a JS usando TSC hoy y publica ese JS como un paquete NPM...

Si NO se implementará, dejaré que MS cierre el problema ahora.

Ah, lo entiendo ahora. Sí, cuando transpilo (con target: ES2018 ) el JS emitido deja la extensión fuera de la declaración de importación, pero funciona para mí porque el consumidor está poniendo todo a través de webpack/babel y debe estar completando la extensión que falta para mi. Estoy al día ahora. Ni siquiera se me había ocurrido que mi "paquete" no funcionaría de forma nativa en el navegador sin un viaje primero a través del paquete web.

Sí, esta es una pregunta difícil.

@thw0rted No uso webpack/babel, por lo tanto, resolver .js desde el cuadro es un problema para mí.
Alguna solución/solución alternativa es configurar el servidor web para las fuentes de resolución predeterminadas .

Lo siento si estoy repitiendo lo que otros han dicho, pero esto es algo con lo que trato todos los días, así que me gustaría aportar otro de mis dos centavos no solicitados.

Sé que TypeScript no tiene que adaptarse a ningún entorno en particular (Node.js, Webpack, etc.), pero el hecho es que hay muchos entornos en los que la extensión siempre es necesaria, a menos que se configure de otra manera, así que no No creo que deban ser ignorados. Las importaciones ya no están detrás de una bandera en Node y la ruta de importación debe coincidir con el nombre de la ruta URL en la web. Si bien no existe una necesidad técnica de tener .js al final de una URL, ese es el estándar de facto.

Si la buena gente de Microsoft realmente quiere que la extensión de archivo no sea la predeterminada, no lo discutiré. Probablemente sea más inteligente que yo, pero sin duda sería más feliz si, en lugar de inferir si se necesitan extensiones o no en función de otras importaciones en el mismo archivo, eso podría configurarse en todo el proyecto para que funcione para autocompletar de Intellisense por primera vez. ¡Importación añadida a un archivo!

Mientras tanto, ¿alguien sabe de algún complemento de VSCode que solucione esto? Agregar importación/extensiones a eslint es lo mejor que he podido hacer para lidiar con esto.

Actualmente escribo líneas import sin la extensión .js y luego uso sed para agregar la extensión .js en los archivos de salida.
https://github.com/yoursunny/NDNTs/blob/9f50fcec245b33c7649fa815bbb3dd404eee160e/mk/build.sh#L12 -L14
Tengo que eliminar SourceMaps durante la compilación de producción, porque ya no coincidirían después de modificar los archivos de salida.

No puedo escribir la extensión .js en los archivos fuente .ts porque rompe ts-jest .
Si bien es posible ejecutar Jest en archivos .js compilados, rompe Coveralls .

@yoursunny Sí, sed es una variante (también lo usé, pero prefiero reemplazar en el archivo debido a la configuración que se puede configurar mediante la asignación de archivos importmap) para reemplazar cadenas en archivos js generados, pero no huele bien =) Puede ser agregar extensiones será una característica/opción útil para ttypescript con complemento de transformación (por ejemplo , typescript-transform-paths de @MicahZoltu).

@richardkazuomiller esta parte no es cierta:

Si la buena gente de Microsoft realmente quiere que la extensión de archivo no sea la predeterminada

Solo mecanografiado:

  1. Permite una resolución de módulo de estilo de requisito de nodo (deberían expandir esto para permitir una resolución de estilo de importación de nodo, que requiere extensiones de archivo).
  2. En la misma unidad de compilación, resuelve los archivos .js en un par .js/.d.ts incluso antes de que el compilador los genere.
  3. No modifica los especificadores de importación _en absoluto, nunca_.

Así que la solución a todo esto es simplemente importar los archivos .js con la extensión .js . TypeScript se resolverá en el archivo .ts correcto y no modificará el especificador de importación, por lo que todo funcionará en navegadores y Node >= 13.2.

@yoursunny , ¿presentó un error contra ts-jest ? Se están desviando del estándar TypeScript de facto aquí. También parece un error en Coveralls si no puede utilizar mapas de origen en los archivos .js.

¿archivó un error contra ts-jest ? Se están desviando del estándar TypeScript de facto aquí.

No, porque no entiendo completamente cómo funciona la resolución ts-jest.

También parece un error en Coveralls si no puede utilizar mapas de origen en los archivos .js.

Coveralls recibe un informe lcov de mi proceso de compilación y luego muestra la cobertura del código usando archivos confirmados en GitHub.
No envío archivos de salida .js a GitHub. Si ejecuto pruebas unitarias en archivos .js, el informe lcov hará referencia a los archivos .js que no existen en GitHub.
Por lo tanto, Coveralls no puede encontrar los archivos de origen. Mostrará el porcentaje de cobertura, pero no puede mostrar qué líneas no están cubiertas.

¡La nueva era está aquí!

El recién lanzado Node.js v13 y todos los principales navegadores son compatibles con los módulos ES nativos listos para usar, y sería genial que TypeScript admitiera estos entornos de una manera simple.

La solución más simple para los casos de uso más básicos (un sitio web servido a través de un servidor de archivos estático simple) sería agregar una nueva opción de compilador como "appendJsExtension": true o similar.

@mjbvz El problema en el repositorio de VS Code que cerró es ligeramente diferente: se trata de usar autocompletar para agregar declaraciones de importación automáticamente; cuando VS Code hace esto, agrega la declaración de importación sin una extensión .js , y es fácil pasar esto por alto hasta que se produce una falla en el tiempo de ejecución.

Sin embargo, si TypeScript agrega una opción como "appendJsExtension": true o similar, entonces no importará mucho y podremos escribir código TS sin .js en el código fuente.

¿Tal vez el complemento VS Code debería tener una opción para habilitar/deshabilitar la adición automática de extensiones .js en declaraciones de importación autocompletadas?

@mjbvz El problema de VS Code / Intellisense está relacionado, pero no debe cerrarse como un engaño. Si este problema finalmente se cierra como WONTFIX, eso en realidad aumentaría la importancia del problema del Código VS.

Estoy viendo un punto pasado por alto y no entiendo cómo las soluciones donde la extensión JS tiene un caso especial resolverían esto: para ESM, ninguna extensión tiene un estado especial, incluso los archivos sin extensión están completamente bien siempre que el servidor los sirva al navegador con el tipo MIME de texto/javascript apropiado. Eso significa que el código como:

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

Todo esto es válido siempre que los archivos (independientemente de sus extensiones) contengan código JavaScript y se sirvan al navegador con el tipo JavaScript MIME.

Dado que TypeScript debería ser un superconjunto de JavaScript con seguridad de tipos, no veo una forma de evitar permitir importaciones como las anteriores, porque el código es JavaScript válido y si TypeScript no lo acepta, deja de ser un superconjunto seguro. de JavaScript, ¿no es correcto?

Entonces, ¿las soluciones donde la extensión JS está implícita o es la única permitida que no creo que pueda cortar esto? Además, incluso las extensiones TS y DTS IMO no pueden tener mayúsculas y minúsculas, porque aunque normalmente no es el caso, podrían contener código JavaScript, no código TypeScript y servidor para el navegador como tal sin ningún problema en lo que respecta a ESM. , dado que se sirven con el tipo MIME correcto.

¿Me estoy perdiendo algo en este frente? ¿Es posible que TypeScript no implemente soporte para extensiones arbitrarias (incluidas las que faltan) en las importaciones de código, y es posible que TypeScript continúe asumiendo extensiones TS en las importaciones de módulos, dado que file.ts y file (sin extensión) daría lugar a un conflicto?

Web and Service Workers también está recibiendo soporte para la importación/exportación del Módulo ES .

Apoyo y apruebo totalmente la idea de @trusktr de implementar su idea como una opción de compilación. No es que quiera deshacerme de paquetes como webpack y rollup. Pero sí creo que una característica como esta eliminará muchas molestias y el tiempo dedicado a configurar paquetes, cuando todo lo que desea es compilar un proyecto de TypeScript simple sin pasar por los aros o usar soluciones incómodas.

Considere esto como una opción para el compilador de TypeScript. <3

¿Alguien sabe de alguna manera en la que pueda ejecutar los archivos js individuales compilados en un navegador sin paquete web o --outFile , utilizando cualquier tipo de sistema de módulos?

Mi problema es este: el proyecto TypeScript bastante grande con el que estoy trabajando tarda unos 35 segundos en compilarse con webpack en un archivo js incluido usando ts-loader .
La única forma en que pude optimizar esto fue usando transpileOnly lo que redujo el tiempo de compilación a 20 segundos, pero aún es lento y pierdo la verificación de tipos.
Al deshacerme del paquete web, podría llegar a unos 14 segundos usando outFile, pero eso todavía es demasiado lento para mí. Usar incremental no hizo ninguna diferencia.

La única forma en que pude obtener unos segundos de tiempo de compilación fue emitiendo 1 archivo js por 1 archivo ts y usando el indicador incremental . En este caso, imagino que ts detecta y compila solo los archivos que realmente han cambiado. El problema es que no pude hacer que esto se ejecutara en un navegador en ninguno de los objetivos del módulo que probé: system, amd, es6.
Estoy usando el mapeo paths en tsconfig.json y en los archivos js compilados, los errores que recibo están relacionados principalmente con no poder resolver esos alias.

¿Hay alguna manera de lograr esto?

@andrewvarga Actualmente ejecuto todo mi TypeScript compilado directamente en el navegador sin agrupar o compilar en un solo archivo. La forma más fácil de hacer esto es:

  1. Asegúrese de que todas las importaciones en archivos TypeScript tengan la extensión .js .
  2. Ejecute un servidor de desarrollo que resuelva las importaciones de nombres de paquetes npm para dependencias, si es necesario. es-dev-server es el más simple que conozco.
  3. Ejecute tsc --watch (asegúrese de que el módulo sea esnext en su tsconfig)

Eso es todo. Si solo escribe la extensión .js para importaciones en su TypeScript, no necesita otras herramientas para arreglar los archivos para los navegadores.

@justinfagnani amigo, olvidó la información más importante: los tipos deben estar en formato jsdoc, cualquier abstracción de mecanografiado sobre JavaScript nativo hará que el analizador falle.

@Draccoz tsc generará JavaScript, no TypeScript.

@andrewvarga La forma más sencilla que conozco de transpilar sin agrupar es mi proyecto Zwitterion . Está diseñado para ser un reemplazo de un servidor de archivos estático, para que no tenga que cambiar la forma en que desarrolla. Puede importar y exportar con extensiones de archivo explícitas (.js para JavaScript y .ts para TypeScript), incluso en elementos de script. Es muy eficaz, almacena en caché y se recarga automáticamente cuando cambian los archivos. Sin embargo, tendrá que confiar en su editor para el análisis estático (errores de tipo)

@andrewvarga Uso https://github.com/Zoltu/typescript-transformer-append-js-extension/ y apunto módulos ES nativos que se cargan en todos los navegadores modernos (excepto Safari, el nuevo IE).

Si sus dependencias NPM de tiempo de ejecución son bastante limitadas, puede cargarlas con es-modules-shim sin ningún paquete. Puede ver una plantilla de reacción que creé que muestra todo esto trabajando en conjunto: https://github.com/Zoltu/react-es2015-template

@MicahZoltu Safari tiene soporte para módulos ES, lo sé de hecho, basado en mi experiencia personal y caniuse: https://caniuse.com/#search =modules

@justinfagnani awww lo siento, me perdí la parte "Mecanografiado compilado", pensé que estabas hablando del mecanografiado jsdoc.

¡Gracias a todos por los diversos consejos!

Lo que encontré es que al usar el módulo hard-source-webpack-plugin npm para webpack y transpileOnly: true en las opciones de ts-loader se redujo el tiempo de compilación a unos 4-5 segundos.
Esto, por supuesto, ignorará los errores de mecanografiado, por lo que solo es útil para iteraciones rápidas de compilación, probar en el navegador y confiar en el IDE para detectar posibles errores, pero creo que es muy útil durante el desarrollo.

Para obtener los errores de TS y la compilación rápida, sigo pensando que la única forma sería ejecutar módulos en el navegador, pero la falta de soporte para mapas de importación y extensiones js lo dificultó.
@justinfagnani @MicahZoltu gracias, probaré esas opciones. En general, prefiero evitar usar un módulo npm más, pero parece inevitable.

Traté de hacer que funcionara usando systemjs también, pero me quedé atascado con los mapas de importación.

@andrewvarga Puede probar SystemJs con mi ejemplo ligero con importmap.
También puede probar mi ejemplo pesado : systemjs & esm alternativa, pero los mapas de importación de esm no son compatibles con los nativos, y debemos resolver los módulos manualmente (gulp-replace), o puede probar es-module-shims .

Entonces, si estoy usando tsc como mi único compilador, apuntando a esnext o es2015 como mi tipo de módulo. ¿Hay alguna manera de que pueda usar la salida directamente en mi navegador?

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

Si entiendo el resto de este hilo correctamente, Typescript debería estar perfectamente feliz de compilar su código si cambia esta línea para decir from "./module.js" . Luego, el index.js compilado tendrá una declaración de importación ES6 válida y todo debería funcionar.

Eso es a menos que importe alguna biblioteca que no sepa cómo importar ES o no le importe: P.

Creé un complemento para Gulp que agrega .js para importar rutas de archivos. (también una resolución de ruta de ts de bonificación).

Usé Gulp porque no conozco ningún otro ejecutor de tareas que me permita esencialmente adjuntar un paso simple de procesamiento posterior al compilador tsc (tanto en modo reloj como normal). Webpack y rollup se agrupan exclusivamente, y quiero emitir módulos es.

Funciona, pero es lento de ver, ya que parece reconstruir todo.

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

Esto se está volviendo más importante ya que el equipo del nodo decidió no importar sin extensión
https://github.com/nodejs/modules/issues/444

Agregar mapas de importación también se decidió en contra de las importaciones sin extensión
https://github.com/WICG/import-maps/issues/194

Si queremos usar el módulo es compilado de mecanografiado en el navegador o nodo, ¿necesitamos tener extensiones agregadas por mecanografiado? (para módulos internos) y manualmente para módulos externos? @weswigham

@chyzwar de nuevo, si simplemente escribe las extensiones .js en su código fuente de TypeScript, la salida compilada tendrá las extensiones correctas y los módulos funcionarán en navegadores y Node. No necesita herramientas de transformación adicionales ni tsc para hacer nada por usted.

Es más sencillo para el desarrollador hacer lo siguiente: si es un archivo fuente de TypeScript, escriba una extensión .ts. Si es un archivo fuente de JavaScript, escriba una extensión .js. Eso también se compilará y ejecutará correctamente en el navegador (.ts necesitará un tipo MIME de aplicación/javascript). La extensión debe coincidir con el tipo de archivo de origen. Los módulos tsc y ES pueden manejar eso (al menos los módulos ES en el navegador, con suerte Node.js sigue lo mismo)

@justinfagnani tsc está bastante contento con esto, y es justo decir "no es nuestro problema" aquí, pero parece que no hay consenso sobre lo que es correcto.

Entre tsc, vscode, webpack y ts-node, ninguno puede estar realmente de acuerdo con un estándar que ahora está disponible de forma nativa (navegador y nodo ahora disponibles).

Ejemplo 1

Quiero escribir un paquete javascript moderno, crearlo en mecanografiado y eliminar los tipos para distribuirlos como un módulo ecmascript (reteniendo declaraciones de importación y exportación).

Ejemplo 2

Estoy construyendo un sitio web estático usando módulos en vscode, de manera predeterminada, se importará automáticamente sin una extensión para cada primera importación y debe ajustar esto manualmente.

En estos casos, tsc puede manejar esto, e incluso exportar archivos descriptores aparte que admiten luego consumir la distribución del módulo es desde TypeScript con escritura completa (increíble).

Pero si quiero ejecutar el código de prueba contra la fuente, podría usar ts-node pero aquí ts-node no está contento.

Del mismo modo, el hecho de que tsc, vscode y webpack hayan evolucionado para hacer lo siguiente:

  1. importaciones automáticas de vscode sin una extensión
  2. tsc felizmente reescribirá las importaciones a un archivo js en el sentido del archivo ts
  3. webpack hace varias magias aquí para que las extensiones predeterminadas busquen

Son todas las cosas que deben cuestionarse ahora que cuatro implementaciones (chrome, firefox, safari, node) esperan que la ruta de importación apunte a algo que pueda resolverse directamente en un archivo.

Agregar .js a una importación debería ser una solución temporal, no una solución definitiva. En todo caso, se siente como un truco. Una forma de engañar al compilador. Y tratar de burlar a un compilador es una ideología horrible para seguir en mi humilde opinión. Solo puedo imaginar lo confuso que debe ser esto para las personas nuevas en TypeScript. Un lenguaje que debería ayudar a los desarrolladores de Javascript a escribir _mejor_ código.

Como ya se mencionó, si agrega .js a la importación, TypeScript los generará y todo funcionará (al menos dentro de su código). Razonar que tsc debería agregar extensiones porque no funcionan en el navegador es como pedirle a TypeScript que corrija los errores de tiempo de ejecución causados ​​por el desarrollador. Está bien, pero ¿por qué el desarrollador no puede corregirlos por sí mismo?
No me malinterpreten, me encantaría que tsc fuera mi única dependencia de desarrollo, pero algunas cosas simplemente no sucederán y permanecerán como un sueño.

Me encantaría que tsc fuera mi única dependencia de desarrollo, pero algunas cosas simplemente no sucederán y permanecerán como un sueño.

Debo haber visto docenas de comentarios casi idénticos durante varios años en el n.º 3469, incluidos algunos del equipo de Typescript. "Es un verificador de tipos, se supone que debe hacer una cosa bien, no espere que reemplace toda su cadena de herramientas..." Les tomó 3 años, pero aun así agregaron el modo de compilación, porque se argumentó que era la dirección correcta a seguir.

Webpack y rollup se agrupan exclusivamente, y quiero emitir módulos es.

@alshdavid Rollup puede funcionar para usted si configura el formato de salida en esm y establece preserveModules en true : https://rollupjs.org/guide/en/#preservemodules

tal vez las importaciones "sin extensión" fueron un pecado original, no compatibles con la forma en que funcionarían los navegadores

ahora es el momento de corregir nuestro código fuente e incluir las extensiones .js : encontramos que cuando agrega extensiones .js a su código fuente hoy, todo funciona: el navegador está satisfecho, el mecanografiado es agnóstico y a los empaquetadores no les importa

así que tal vez sin extensión era una falla en nuestro código fuente que nuestra herramienta anterior estaba compensando

Escribir la extensión .js en las importaciones en el código fuente mecanografiado es una completa tontería. Está funcionando, conserva la extensión en la salida, pero probablemente fallará con errores de "no se pudo resolver el archivo" en las reglas de ESLint (o TypeScript) en VSCode o cualquier editor que esté usando. Sin mencionar cuando está probando contra ese código fuente mecanografiado. Entonces la herramienta de prueba también debería saber sobre ese comportamiento de mierda. Estoy casi seguro de que arrojará errores que no puede resolver archivos.

Ejemplo básico

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

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

prueba/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);
});

Perdón por el uso de "mierda", pero esa es la verdad.

No creo que sea tan difícil implementar la opción básica que cuando el compilador ve la extensión ( .ts ) en las importaciones para convertirla a .js (o incluso permitir opcionalmente especificar a qué se extiende la salida ser). Cuando no hay extensión, no conserve las extensiones (¿comportamiento semi-actual?).

Escribir la extensión .js en las importaciones en el código fuente mecanografiado es una completa tontería. Está funcionando, conserva la extensión en la salida, pero probablemente fallará con errores de "no se pudo resolver el archivo" en las reglas de ESLint (o TypeScript) en VSCode o cualquier editor que esté usando.

Esto simplemente no es cierto. ESLint, TypeScript, VS Code y todas las demás herramientas relacionadas con TypeScript que he usado _simplemente funcionan_ con este método. No es un truco, y tiene una lógica muy razonable a su alrededor: que el archivo que está importando en realidad _es_ el archivo .js , y que sus extensiones no deberían cambiar solo porque un archivo importado es parte del archivo local proyecto, o precompilado como parte de un paquete de terceros.

Nuevamente, escribo todo mi código TypeScript de esta manera y resuelve todos los problemas que se plantean en este hilo. La salida funciona muy bien en navegadores y Node. No es una tontería, simplemente funciona, _hoy_.

No, no es. Al menos en el caso más común donde el directorio de salida es dist o build o lib y etc. Sus archivos compilados no están en el mismo directorio, simplemente nunca existen allí (en src/ ) - ni durante la prueba, ni durante la codificación en el editor.

Tener/ver e importar ./foo.js en los src/index.ts anteriores no tiene NINGÚN sentido para mí, a menos, por supuesto, si realmente quiere importar el archivo js/json, lo cual está completamente bien. Pero escribir ./foo.js cuando realmente te refieres a otro archivo fuente mecanografiado ( ./foo.ts ) es... brutal. Es engañoso y confuso, y definitivamente incorrecto.

Estoy casi seguro de que si ejecuto el test/index.ts anterior con Jest, fallará con el error de que no puede encontrar/resolver ./foo.js porque solo hay ./foo.ts .

Si dejamos todo a un lado, ¿por qué se permite tener una extensión .js pero no .ts (ts report error en el editor)? Es una inconsistencia básica, simple y estúpida. Como muchos otros problemas "solo porque sí" en TypeScript.

De hecho, perdí la lógica de por qué este problema se llama así cuando en realidad es posible terminar con la extensión .js . Creo que el problema es todo lo contrario: que no puede terminar con .ts (a partir de 3.7+)

¿Por qué la extensión de .ts en las importaciones está totalmente prohibida?

Y aclaremos. Estoy hablando de tiempo de desarrollo y experiencia. Entiendo por qué podemos conservar la extensión .js en la salida compilada, y por qué podemos agregar .js ext a las importaciones en un archivo .ts sin informar errores, y yo Estoy bien con eso.

TypeScript es un superconjunto de JavaScript pero no es JavaScript. JavaScript es un objetivo de compilación para TypeScript.

Con eso en mente, a pesar de saber que TS compilará a JS, esperaría que el código TypeScript se comporte de manera completamente autónoma.

Escribir un .js al intentar importar un archivo .ts asume el conocimiento del tipo de compilación objetivo y asume que el objetivo de la compilación siempre es JavaScript.

¿Qué pasa si compilamos TypeScript en un binario de ensamblado web o ejecutamos código TypeScript usando un tiempo de ejecución alternativo como Deno o ts-node.

Las declaraciones de importación que terminan en .js no tienen sentido en tales contextos.

Preferiría verme obligado a escribir .ts en mis rutas de importación o no tener una extensión especificada que asuma un archivo fuente de TypeScript.

Es triste que TypeScript haya inventado su propia extensión en lugar de ser solo un flujo de azúcar de sintaxis.

@phaux Nunca me gustaría trabajar con un proyecto que mezcle archivos fuente y dist bajo la misma extensión, incluso si viven en carpetas diferentes. Es como nombrar todos los archivos index.js solo porque viven en carpetas diferentes...

Este problema (que es más grande que TypeScript) parece impedir que IntelliSense de Visual Studio Code funcione en navegadores web y Node, lo que requiere rutas de archivo completas (relativas) en los especificadores de importación. Sin esto, las declaraciones import generadas que crea solo funcionan con transpiladores y empaquetadores, como WebPack y TypeScript.

La respuesta del equipo de VSCode fue que el código que proporciona sugerencias de importación automática debe agregar extensiones. Sospecho que es el servidor de lenguaje TypeScript (no tsc , de lo que se ha tratado aquí).

¿Puede alguien que realmente sepa cosas confirmar (o corregir) que VSCode recibe sugerencias de importación automática del servidor de lenguaje TypeScript?

la situación es un poco complicada y matizada, por lo que si bien las extensiones ".js" inicialmente van en contra de las elegantes intuiciones e ideales de muchas personas, puede ser imprudente y confuso que el mecanografiado se desvíe mucho de los estándares de navegador ratificados y las implementaciones enviadas.

entonces quizás consideremos el paradigma actual de la siguiente manera:
Las importaciones mecanografiadas describen lo que se importa en tiempo de ejecución , es decir, sus importaciones se ejecutan en su directorio "dist", no en "src", como fetch llamadas y el resto, si podemos tolerar esta idea, el resto se convierte en simple y consistente

ciertamente parece una mala idea tener mecanografiado adjuntando ciegamente ".js" a importaciones sin extensión como lo hace el nodo para commonjs (vale la pena señalar que la compatibilidad con node esm requiere ".js" de la misma manera que mecanografiado hoy) - adjuntando ciegamente ".js" crearía nuevos problemas, como importar archivos javascript verdaderamente sin extensión, o incluso otros tipos de archivos como css o json; haría que las extensiones fueran significativas y requeriría una lógica de análisis especial, creando una gran diferencia entre la semántica del navegador y la mecanografiada, y obviamente no vamos a hacerlo. para reescribir las llamadas fetch la misma manera, ¿así que tal vez import debería seguir siendo similar?

sin embargo, me pregunto: ¿es relativamente inofensivo que TypeScript convierta las extensiones ".ts" a ".js"?

por supuesto, eso haría imposible importar un archivo javascript que tuviera una extensión ".ts", pero tal vez eso sea un poco de magia funky que podamos tolerar. por otro lado, es una diferencia idiosincrásica mágica funky entre la semántica del navegador y la mecanografiada que los desarrolladores tendrían que aprender y comprender (seguramente creando extraños gotchyas), por lo que mi instinto es dejar las cosas donde están hoy.

por otro lado, si mantenemos las cosas como están, la magia simplemente se reubica en mecanografiado, que tiene que relacionar las importaciones ".js" con los archivos de origen ".ts" correspondientes; me parece una ubicación más razonable para albergar la magia, ser interno a mecanografiado en lugar de pisotear la semántica del navegador

🥃 persecución

@rconnamacher , @TomasHubelbauer

Este problema (que es más grande que TypeScript) parece impedir que IntelliSense de Visual Studio Code funcione en navegadores web y Node, lo que requiere rutas de archivo completas (relativas) en los especificadores de importación. Sin esto, las declaraciones de importación generadas que crea solo funcionan con transpiladores y empaquetadores, como WebPack y TypeScript.

Creo que aquí hay algo de confusión: hoy en día es muy posible crear una biblioteca o aplicación de mecanografiado que funcione muy bien con vscode e intellisense, que funcione en navegadores y nodos, y funcione en esm o commonjs: hoy en día es posible una solución verdaderamente universal

He estado trabajando en un puñado de bibliotecas abiertas que exhiben esto: renraku , cynic , redcrypto , autoritarian

envíeme un correo electrónico y estaré encantado de explicarle más

:ola: persecución

Otro punto es que genera confusión sobre a qué archivo está accediendo. Ya existe la ambigüedad de lo que tsc ve después de la resolución del módulo cuando tiene un archivo .js y .ts uno al lado del otro.

/folder
  a.ts
  a.js
  index.ts

Si en index.ts , al usar 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` 

Ya existe ambigüedad de lo que tsc mira después de la resolución del módulo cuando tiene un archivo .js y .ts uno al lado del otro.

De acuerdo, claro, más o menos, pero si a.js es cualquier cosa menos la versión transpilada de a.ts entonces algo salió catastróficamente mal y no es culpa de TypeScript.

@thw0rted si está compilando en un solo archivo de paquete JS, TypeScript no generará una contraparte de JS para los archivos TypeScript de entrada, solo el archivo de paquete único. En ese caso, es completamente legal tener un archivo JS para y un archivo TS del mismo nombre que no se corresponden de ninguna manera.

No es "ilegal", pero eso no significa que sea una buena idea. ¿Tienes un ejemplo concreto de dónde realmente querrías esto?

Simplemente sería bueno usar TypeScript sin paquetes, cargadores y de una manera que emita JavaScript que los navegadores modernos puedan usar directamente.

Como ejemplo:
https://github.com/alshdavid/tsc-website

Pero siento el dolor del problema. El equipo de TypeScript no quiere implementar la resolución del módulo. Es la misma razón por la que el compilador de TypeScript no puede convertir paths en sus rutas relativas reales en el momento de la compilación.

Convertir una importación de .ts a .js , o agregar .js a una importación sin una extensión significa que el equipo de TypeScript estaría implementando la resolución del módulo y eso está fuera del alcance.

Una solución para esto es que el equipo de TypeScript proporcione una forma de introducir extensiones para que podamos implementar estas cosas.

Una solución para esto es que el equipo de TypeScript proporcione una forma de introducir extensiones para que podamos implementar estas cosas.

Lo hacen, simplemente no se expone a través tsc (solo a través de la invocación programática del compilador). Afortunadamente, alguien construyó un contenedor alrededor del compilador central que funciona _exactamente_ como tsc excepto que admite extensiones a través de la configuración. Con este contenedor tsc, puede usar una extensión como https://github.com/Zoltu/typescript-transformer-append-js-extension/ para agregar automáticamente la extensión .js .

@alshdavid, su ejemplo en GitHub funciona en navegadores sin un paquete si solo incluye la extensión .js en las importaciones. Presenté un PR para arreglarlo.

@alshdavid Puede ser interesante en mi proyecto de muestra (esm para moderno e IE11 con SystemJS).
Pero me veo obligado a resolver los módulos esm manualmente =(

No tengo ningún problema en principio con poner .js en todos mis import s, pero desafortunadamente expone una mala interacción con algunas herramientas. Por ejemplo, ts-node chokes: https://github.com/TypeStrong/ts-node/issues/783. No parece haber un acuerdo claro sobre de quién es esta responsabilidad: TypeScript para emitir la extensión .js (en algunas circunstancias) o cada herramienta que consume fuentes de TypeScript para hacer la traducción. Y mientras todos estén pasando la pelota, los usuarios están sufriendo con complementos mal documentados o trabajadores de servicio incómodos para solucionar las incompatibilidades de interoperabilidad.

¿Hay alguna actualización sobre esto? Honestamente, no puedo creer que no parezca posible usar TypeScript normalmente hoy en día sin un cargador de módulos externo o un paquete como Webpack. Esto me parece tan extraño y también frustrante. Si tengo que usar algún módulo externo para hacer que TypeScript funcione completamente, entonces debería comenzar.

Estoy tratando de usar esto en mi aplicación Electron, por lo que no veo una razón para usar un paquete web y también me gustaría no instalar un cargador de módulos externo si no es necesario. Pero esto me está volviendo loco. Ni siquiera ser capaz de poner en marcha una configuración básica de TypeScript + Electron, aunque ambos son elogiados en todas partes como la mejor solución que existe. Eso es una locura, para ser honesto. No sé si me estoy perdiendo algo, pero no poder encontrar una solución adecuada es más que frustrante.

Y si realmente no soy yo, no entiendo por qué este problema no se ha solucionado en 3 años ...

Recientemente completé el tutorial de mecanografiado y luego, cuando traté de crear algunos archivos ts, encontré este problema. Soy completamente nuevo en este mundo js-ts, así que disculpe si algo está mal o es engañoso/mal informado.

lo que hice fue, mientras importaba

Simplemente puse la extensión .js en el archivo ts y luego, cuando revisé el intellisense, funcionó también cuando lo transpilé usando tsc, también agregó la extensión .js al archivo de salida generado.

Lo siguiente es lo que hice.
tsc -p tsconfig.json

{
"Opciones del compilador": {
//"módulo": "amd",
"módulo": "es6",
"objetivo":"es6",
"noImplicitAny": falso,
"eliminar comentarios": verdadero,
"preservarConstEnums": falso,
//"archivo de salida": "js",
"outDir":"js",
"mapafuente": falso
},
"incluir": [
"testscript.ts"
]
}

Aunque funcionó para mí.

Mi duda es que dado que no hay svgwrapper.js para importar desde
¿por qué / cómo funcionó? (Supongo que no considera la extensión)

Adjunto la captura de pantalla como referencia.

ts-js-ext-issue

@yogeshjog así es exactamente como es tsc y se supone que funciona. Importa el módulo con el nombre de archivo que se generará. Si el módulo importado se escribió originalmente como un archivo $# .ts o como un par .d.ts / .js , no debería ser observable desde el módulo de importación.

@yogeshjog así es exactamente como es tsc y se supone que funciona. Importa el módulo con el nombre de archivo que se generará. Si el módulo importado se escribió originalmente como un archivo $# .ts o como un par .d.ts / .js , no debería ser observable desde el módulo de importación.

¡Gracias! @justinfagnani para aclaraciones 👍

Importa el módulo con el nombre de archivo que se generará.

Pero TypeScript también permite omitir la extensión, lo que no está permitido según ECMAScript. Incluso omite la extensión cuando usa la función de importación automática en VSCode, que es lo más molesto. Escribe algo de JS y TS dice que está bien y luego falla en el tiempo de ejecución.

Pero TypeScript también permite omitir la extensión.

Cuando se utiliza la resolución de nodos. tsconfig está configurado al menos para permitir otros modos de resolución que advertirían sobre esto, pero entiendo que el equipo ha estado permitiendo que el soporte del módulo nativo se asiente antes de agregar más modos.

que no está permitido según ECMAScript.

ECMAScript no dice nada sobre los especificadores de importación. Eso se deja a los entornos de alojamiento como HTML y Node. TypeScript admite la resolución de nodos al cargar módulos e interpreta la resolución contra la _salida_ del compilador, no la _entrada_ del compilador. De esta manera, los especificadores funcionan después de la compilación y funcionan independientemente de si intenta importar un módulo compilado o no.

Debido a que TypeScript usa la resolución de nodo que realizará una búsqueda de ruta para convertir la información de './foo' './foo.js' , './foo' es válido. Pero la resolución del nodo no convertirá './foo.ts' en './foo.js' , por lo que './foo.ts' no es válido.

Pero eso está dentro de la resolución del nodo. Si está tratando de usar otro entorno como HTML o la compatibilidad con módulos nativos de Node, TypeScript y el host no estarán de acuerdo sobre lo que es válido.

Esperemos que la compatibilidad con módulos nativos esté lo suficientemente establecida ahora para que TypeScript agregue otra configuración de resolución.

@leontepe No necesitas un empaquetador/cargador. Puede usar https://github.com/Zoltu/typescript-transformer-append-js-extension/ (mi solución preferida) o puede agregar .js a todas sus declaraciones de importación (cuidado: esto haga que su código falle en ts-node ).

@leontepe No necesitas un empaquetador/cargador. Puede usar https://github.com/Zoltu/typescript-transformer-append-js-extension/ (mi solución preferida) o puede agregar .js a todas sus declaraciones de importación (cuidado: esto haga que su código falle en ts-node ).

@MicahZoltu Bueno, gracias, pero aún así es un poco frustrante que no funcione solo 'fuera de la caja'. Como dijo @phaux , VSCode sugiere a sus usuarios que realicen declaraciones de importación sin la extensión y eso simplemente no funciona en tiempo de ejecución. Cuestiono seriamente la competencia del equipo de TypeScript aquí o me equivoqué en algo todo este tiempo y soy simplemente estúpido. Pero quién sabe...

Editar: considerando seriamente dejar caer TypeScript para JavaScript + Babel en este punto.

No he escrito una aplicación Electron, pero ¿existe alguna posibilidad de hacer que tenga una resolución de estilo Node, donde hay un algoritmo para tratar de resolver las importaciones que intenta varias cosas en un orden fijo? Parece que debería estar bien dado que todas las fuentes se cargan desde recursos locales...

¿Tal vez es hora de agregar una nueva resolución de módulo a TS? Node.js tiene soporte ESM nativo ahora, pero sin extensiones explícitas en las rutas relativas, obliga a usar el indicador --experimental-specifier-resolution=node , lo que es un poco molesto. También hay Deno y navegadores. Idealmente debería haber algo así:
tsconfig.json:

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

luego mecanografiado:

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

compila a Javascript:

import foo from './foo.js';

"estricto": ¡verdadero significa mucho trabajo!
2020, todavía no arreglado, ridículo.

Solo intervino para decir que este problema también está bloqueando a nuestro equipo 😢

Realmente nos gustaría poder tener una única fuente que se compile en módulos nativos y que también sea consumible en el nodo y con el paquete web. Webpack parece tener un problema si coloca manualmente .js en sus importaciones en su código TS. Sin embargo, puede hacer que el paquete web funcione si coloca la extensión de archivo .ts en sus importaciones, pero, por supuesto, mecanografiado se queja. No tener una extensión de archivo resulta en no tener módulos nativos. Por lo tanto, ninguna combinación parece satisfacer al navegador y a los empaquetadores. Si pudiéramos escribir .ts en nuestras importaciones y hacer que se convierta en .js en la salida, creo que el problema se resolvería (y también obtendría deno compat). Algo como @ evg656e sugiere que parece que debería funcionar.

@EisenbergEffect ¿hay un error presentado contra WebPack por esto? Realmente suena como un problema de WebPack que se desvía del tsc normal.

@justinfagnani No estoy seguro de si el problema radica en webpak, ts-loader o en otro lugar. Pasé mucho tiempo tratando de establecer mi configuración de compilación óptima y no encontré ninguna solución que marcara todas las casillas. Probablemente haya formas de hacerlo con transformadores personalizados o pasos posteriores a la compilación, pero soy reacio a adoptar configuraciones no estándar, ya que puede afectar negativamente a los desarrolladores posteriores.

@EisenbergEffect si el cargador TypeScript de WebPack no le permite importar archivos TypeScript a través de una extensión .js como lo hace tsc , entonces es un error. Como dijiste, el comportamiento impide tener la misma fuente compilada con WebPack y tsc .

¿Tal vez es hora de agregar una nueva resolución de módulo a TS? Node.js tiene soporte ESM nativo ahora, pero sin extensiones explícitas en las rutas relativas, obliga a usar el indicador --experimental-specifier-resolution=node , lo que es un poco molesto. También hay Deno y navegadores. Idealmente debería haber algo así:
tsconfig.json:

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

luego mecanografiado:

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

compila a Javascript:

import foo from './foo.js';

A la gente (por ejemplo, a mí) le encantaría dejar que una pieza de código funcione entre Node.js, Deno y la Web al mismo tiempo. Creo que este sería un gran hito para la programación de TypeScript/JavaScript.

Si está utilizando vscode y necesita una solución provisional, agregar esto a settings.json parece solucionar los problemas:

"typescript.preferences.importModuleSpecifierEnding": "js"

Agregará .js a sus rutas de importación (lo que resolverá los archivos *.ts en src sin errores, pero conservará los .js al transpilar). Es útil cuando se usa tsc sin un paquete.

Mientras esperamos una solución tsc, una solución de baja tecnología para esto es

  1. Copie todos los archivos de origen en una carpeta temporal
  2. Eliminar la extensión para importaciones y exportaciones antes de compilar

Quería compartir este one-liner en caso de que otros puedan usarlo. Copia la carpeta src/ en tmp/ y cambia los archivos allí.

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

Como parte de un script de compilación en package.json (después de hacer yarn add --dev shx rexreplace ) podría verse así

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

Actualmente mantengo .js fuera de las rutas de importación en las fuentes de TypeScript, para mantener feliz a Jest.
Luego, tengo un paso de procesamiento posterior para agregar .js .
Los mapas de origen no son compatibles con este método.

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

El script de posprocesamiento build-post.js hace lo siguiente.

Agregue .js a import y export de rutas relativas

Por ejemplo,

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

se convierte

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

Tenga en cuenta que no uso index.ts ninguna parte, sino que uso mod.ts siguiendo la convención de Deno. Por lo tanto, no necesito considerar el caso de agregar /index.js .

Cambie import a require para paquetes de CommonJS

Mi código se ejecuta en el Nodo ^12.17 y ^14.1, en modo módulos. Solo publico módulos ES.
Sin embargo, muchas dependencias todavía tienen CommonJS en su campo "main" .
Por lo tanto, debería cambiarlos a CommonJS, excepto los módulos integrados de NodeJS.

Por ejemplo,

import { Server as WsServer } from "ws";

se convierte

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

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

Pero luego, webpack no está contento con estos require s, así que tengo que usar:

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

En webpack, cualquier paquete que importe mi proyecto debe usar ifdef-loader , y luego webpack vería la línea original import .

También nos está afectando esto y no puedo entender cómo esto no se soluciona 3 años después de haber sido informado.
Estamos usando WebStorm, por lo que la configuración específica de VSCode no funcionará.
Usar un script separado para arreglar la salida es ridículo.
Esto debería funcionar sin tener que usar herramientas de terceros.

+1

Esta es mi solución utilizando un sitio web asp.net core 3.1 (probablemente funcione en versiones inferiores)
En el inicio.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!");
                });
            });
        }

El middleware de reescritura agregará la extensión ".js" a cualquier solicitud dirigida a la carpeta /js.
Advertencia: el orden del middleware importa aquí, UseStaticFiles debe colocarse después de UseRewriter o no funcionará.

Como todos aquí, preferiría una solución lista para usar, pero hasta entonces...

¿Tal vez es hora de agregar una nueva resolución de módulo a TS? Node.js tiene soporte ESM nativo ahora, pero sin extensiones explícitas en las rutas relativas, obliga a usar el indicador --experimental-specifier-resolution=node , lo que es un poco molesto. También hay Deno y navegadores. Idealmente debería haber algo así:
tsconfig.json:

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

luego mecanografiado:

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

compila a Javascript:

import foo from './foo.js';

Configuré la regla node/file-extension-in-import en eslint-plugin-node para linting config con la idea de agregar manualmente la extensión para importar declaraciones (ya que es mejor así) y "moduleResolution": "node" en TypeScript config y todo lo que puedo ver es ts(2691) .

Con suerte, lo que dijo @ evg656e podría valer la pena implementarlo.

No puedo creer que esto siga siendo un problema.

cuando usas
"baseUrl": ".", "paths": { "/*": ["./*"] },

puedes hacer una importación de módulo absoulte así:
`importar ws desde "/hey/conexión";

pero al agregar la extensión ".js", de repente el compilador ya no encuentra la declaración de conexión.ts y dice:

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.

usando una ruta relativa todo funciona bien.

por favor arregla esto

También quiero una solución para esto.

Gracias.

¡Es ridículo que esto siga siendo un problema! :00

Finalmente decidí hacer el cambio a TypeScript y este fue uno de los primeros problemas con los que me encontré. Rompe la resolución del módulo en la implementación nativa de Node, y solo he podido evitarlo usando el paquete esm que parece ser más flexible para aceptar nombres sin extensiones, o (extrañamente) usando extensiones .js en las rutas de importación dentro de mis archivos .ts incluso cuando la importación se refiere a un archivo .ts o .tsx. No estoy seguro de por qué el compilador de TypeScript acepta eso, pero al menos el resultado de la compilación incluye la extensión .js. Sin embargo, una solución terriblemente hacky.

Ni siquiera estoy usando mecanografiado mucho en el lado del cliente en estos días, no afecté demasiado la calidad de mi código y simplifiqué las cosas. Probablemente JavaScript tendrá tipos opcionales de un punto y este problema ya no importará.

Dejo la extensión en las líneas de importación, para hacer felices a Jest y Webpack.
Cuando compilo, invoco tsc --listEmittedFiles y canalizo la salida a un script de posprocesamiento. Ese script agrega las extensiones .js , para hacer feliz a Node (en modo módulo).
https://github.com/yoursunny/NDNTs/blob/fa6b2eb68a9f32a6a2e24e5475275f803236b8f8/mk/build-post.js

@kj

(extrañamente) usando extensiones .js en las rutas de importación dentro de mis archivos .ts incluso cuando la importación se refiere a un archivo .ts o .tsx. No estoy seguro de por qué el compilador de TypeScript acepta eso, pero al menos el resultado de la compilación incluye la extensión .js. Sin embargo, una solución terriblemente hacky.

No es raro y definitivamente no hacky, y funciona perfectamente con el navegador y la resolución del módulo nativo de Node.

El recurso que está importando _es_ el archivo .js. El tipo podría estar en un archivo .ts o en un archivo .d.ts. Ni siquiera es necesario que un archivo .d.ts sea hermano del módulo .js, y no es necesario que exista una relación de 1 a 1 entre los archivos .d.ts y los archivos .js.

Importar el módulo .js es la opción más confiable y estable que tsc podría haber elegido. De lo contrario, habrá casos en los que importe los tipos y tsc no sepa la forma correcta de reescribirlos en una ruta de módulo real.

@justinfagnani Ah, creo que tiene sentido. No quise dar a entender que nada de lo que TypeScript estaba haciendo aquí fuera raro (no estoy en posición de hacer una afirmación como esa), solo que sentí que lo que estaba haciendo podría no ser típico. Supongo que lo estaba pensando de la manera equivocada. No es TypeScript el que importa el módulo, ¿es lo que sea que evalúe el resultado de la compilación (o estoy malinterpretando)? En ese caso, puedo ver por qué funcionaría de esta manera.

El recurso que está importando _es_ el archivo .js

Te refieres al módulo construido aquí, ¿verdad? ¿No es un archivo .js en el directorio de origen, sino la versión compilada del módulo .ts?

¿No podría ser que si especifica explícitamente la extensión .ts o .tsx en una ruta de módulo, entonces la salida sustituirá a .js?

Creo que puede haber un malentendido de lo que está pasando @kj. Cuando especifica una extensión .ts sin haber compilado su código, hace referencia al archivo ts. Pero cuando compila usando tsc, convierte el contenido del archivo ts en un archivo js que es ejecutable en el entorno en el que se encuentra (nodo o navegador).

Entiendo que @mkay581 , pero digamos que tengo esta línea en un archivo foo.ts:

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

El 'Component.js' al que me refiero es, de hecho, 'Component.tsx' en el sistema de archivos (no hay ningún archivo .js, a menos que TypeScript entienda que esto se refiere a la eventual versión transpilada del archivo), pero TypeScript acepta esto muy bien y la misma línea de importación está presente en la salida (con la extensión .js que luego funciona con Node o el navegador).

La forma tradicional de TypeScript (AFAIK) sería especificar esa línea de importación sin la extensión, como:

import { Component } from './Component';

Obviamente, eso también se compila bien, excepto que la línea de importación en el archivo .js transpilado no incluye la extensión .js en './Component', que es requerida por ciertos entornos (y posiblemente suene como la especificación, aunque no lo he hecho). No lo leo para estar seguro).

Por otro lado, si especifico la línea con el nombre de archivo real del archivo fuente:

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

Luego, TypeScript no reconoce la ruta y sugiere que debería probar la línea de importación sin la extensión del archivo (si mal no recuerdo, no estoy en mi computadora en este momento).

Entonces, el primer ejemplo me parece un poco extraño, ya que estoy escribiendo TypeScript, espero poder importar con la extensión .ts o .tsx, pero solo acepta la ruta sin extensión (que parece ser en desacuerdo con otras implementaciones del sistema de módulos ES) o con la extensión .js que solo podría referirse al archivo de salida ya que no tengo dicho archivo fuente.

@justinfagnani

El recurso que está importando _es_ el archivo .js.

No sé cómo funciona tsc, pero eso no me suena bien. Cuando escribe su código, todavía no hay un archivo .js. Es trabajo del compilador crearlo.

TS actúa como una capa de abstracción sobre JS y los archivos .js son el resultado del paso de compilación. Contar con que estén allí con esa extensión específica parece romper la abstracción, en mi opinión.

Para decirlo de otra manera, cuando usa C o C ++, no #include los archivos .o en su código, incluye el .h o como máximo el .c o .cpp .

Estoy dispuesto a aceptar una explicación razonable para este comportamiento en Typescript, pero a menos que me esté perdiendo algo, este no parece ser el caso.

@kj

No es raro y definitivamente no es hacky.

Difícilmente en desacuerdo. Para mí es la definición misma de raro y hacky. 😛 Lo que estás haciendo aquí es referenciar un archivo hipotético. Un archivo cuya existencia no está garantizada. (Por ejemplo, al agrupar código, usar AssemblyScript o deno) Está asumiendo el formato de salida. Pero cuando se escribe código agnóstico (por ejemplo, módulos de terceros), eso es algo _peligroso_ de asumir.

@borfast @frzi Sí, básicamente así es como me siento al respecto, y me alegra ver que no soy el único que no se siente cómodo con esto. ¡Solo estoy tratando de no hacer demasiadas suposiciones siendo tan nuevo en TypeScript!

@frzi

Lo que estás haciendo aquí es hacer referencia a un archivo hipotético. Un archivo cuya existencia no está garantizada

No es hipotético, tsc sabe que lo generará. Se garantiza que existe, cuando se usa tsc.

Otra forma de verlo es que si importa el archivo .ts, está importando un archivo que no estará allí después de la compilación.

al empaquetar código

Los empaquetadores se ejecutan después de tsc

@kj mencionó los archivos .tsx, y me llevan a casa aún más. .tsx solo existe para señalar al compilador de ese módulo, _localmente_, que el módulo contiene JSX. Los importadores del módulo no necesitan saber que había JSX en el archivo y no pueden saberlo después de la compilación. Los archivos se pueden portar sin problemas entre pares .tsx, .ts y .js/.d.ts.

Digamos que estás importando un archivo .ts:

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

Y luego desea usar JSX para el componente, por lo que le cambia el nombre a componente.tsx. ¿Deberían fracasar todas las importaciones? Digamos que migra de .ts a .js/.d.ts, ¿deberían fallar las importaciones nuevamente?

@borfast

TS actúa como una capa de abstracción sobre JS y los archivos .js son el resultado del paso de compilación. Contar con que estén allí con esa extensión específica parece romper la abstracción, en mi opinión.

La abstracción no es tan completa como insinúas aquí. Puede importar archivos .js desde dentro o fuera de su proyecto TS. Puede agregar tipos a un archivo .js con un archivo .d.ts que se encuentra en cualquier parte de su proyecto. Los archivos .js son lo que es real después de la compilación. Todo lo demás solo ayuda al compilador.

@justinfagnani Me estoy perdiendo un poco con lo que dice, pero ¿por qué TypeScript no puede simplemente asumir que si le da una ruta de importación con .ts o .tsx, generará un archivo .js para ese módulo y por lo tanto, ¿debería sustituir esta última extensión en la salida?

@justinfagnani

No es hipotético, tsc _sabe_ que lo generará. Se garantiza que existe, cuando se usa tsc.

Pero hay una simetría implícita aquí que no estás admitiendo.

Esta "garantía" que mencionas es válida en ambos sentidos. Si, como usted dice, "tsc _sabe_ que generará [archivos js]", entonces es una pregunta igualmente válida: "Bueno, entonces, ¿por qué tsc NO actúa sobre esta garantía y aplica las extensiones .js que _sabe_ es falta en el js compilado?

Interpretar el hecho de que "tsc garantiza archivos js" va en ambos sentidos.

Así que estoy de acuerdo, @justinfagnani , tu interpretación _es_ válida, desde cierto punto de vista. Pero la interpretación opuesta es que "tsc debería, por lo tanto, _actuar sobre su conocimiento_ y realizar este proceso para el desarrollador". Y lo que me molesta de todo este debate desde el principio es lo _negativamente_ que se recibe esta interpretación, casi hasta el punto de ser ridiculizada. No es razonable.

Al final, este debate se trata de _una decisión estética, no lógica_. Y mi esperanza es que un tono de voz ampliativo y complaciente —como es propio de la _opinión_ estética (no de la deducción lógica)— se involucre en este tema por parte de sus detractores.

En resumen, admita que la pregunta del OP es una interpretación perfectamente válida, tal vez junto con la suya. No hay necesidad de un debate duro.

Gracias

@justinfagnani

Otra forma de verlo es que si importa el archivo .ts, está importando un archivo que no estará allí después de la compilación.

Por supuesto que no, al igual que un archivo .h no se distribuye con el ejecutable de un programa C. Ese es exactamente el punto: le dices a un compilador que incluya archivos fuente , no archivos compilados .

Ok, recibo demasiado spam con esta conversación como para ignorarla más.
La declaración import NO es parte de TypeScript, es parte del entorno de JavaScript que la ejecutó. Ahora, la palabra clave aquí es entorno de JavaScript , ya que ESTO es lo que resuelve las rutas. Muéstrenme una sola aplicación que en el tiempo de ejecución importe y ejecute archivos .ts (claro, puede haber algunos, pero son lo que yo llamaría hacky).
TypeScript permite agregar extensiones .js porque permite JavaScript nativo dentro de sus archivos fuente. ninguno de los navegadores de node.js ejecutará el archivo .ts, incluso ts-node transpila los archivos .ts sobre la marcha, simplemente mantiene el resultado en la memoria en lugar de escribirlos en el disco duro (no es nada complicado). ?).

Ahora, la solución tsc adecuada sería:

  • tenemos .ts archivo
  • lo referenciamos en otro archivo
  • tsc transpila ese archivo .ts en un archivo .js
  • tsc luego reescribe todas las referencias directas al archivo .ts con el archivo .js (sabe exactamente cómo se transpiló, por lo que puede actualizarlo correctamente)

Problema: el "desarrollador web moderno" no es un desarrollador web real y utiliza la forma de importación de node.js, omitiendo la extensión (y la ruta completa del archivo). tsc ahora ya no sabe cuál será la salida, porque importar my-awesome-module/test puede ser cualquier cosa, desde un archivo test.js en node-modules/my-awesome-module , hasta el archivo index.js dentro de la carpeta test en node-modules/my-awesome-module , terminando en algunas reescrituras locales con archivos que no son js como ./local-mocks/my-awesome-module/mock.json .

Aquí es donde surge el problema: ¿cómo puede un tsc saber cuál es la configuración funky webpack/rollup/super-awesome-new-and-shiny-bundler para su proyecto en particular?

Nuevamente: estoy a favor de que tsc reescriba las rutas de importación, pero solo funcionaría para proyectos simples, y hacer que funcione solo para proyectos simples (que hoy en día es una minoría, ya que incluso las páginas de presentación simples reaccionan con una configuración de paquete web sobrediseñada) no vale la pena dedicar tiempo, si se puede hacer con un simple guión escrito personalizado.

Nuevamente: estoy a favor de que tsc reescriba las rutas de importación, pero solo funcionaría para proyectos simples, y hacer que funcione solo para proyectos simples (que hoy en día es una minoría, ya que incluso las páginas de presentación simples reaccionan con una configuración de paquete web sobrediseñada) no vale la pena dedicar tiempo, si se puede hacer con un simple guión escrito personalizado.

¿Cómo lo haría en un proyecto simple sin paquete web, solo con tsc, quiero decir?

Estoy leyendo los comentarios de todos y parece ser un desacuerdo fundamental de las expectativas del uso de mecanografiado aquí.

Cuando los archivos fuente .ts hacen referencia a archivos .js, el problema ya ha comenzado.

Typescript se creó para ~ejecutar~ compilar archivos .ts de origen, no archivos .js. Si un desarrollador quiere usar TypeScript en su proyecto, debe convertir su proyecto _entero_ a mecanografiado y no dejar archivos .js huérfanos e intentar hacer referencia a ellos. Y si no tiene tiempo para cambiar el contenido de los archivos js a la sintaxis de TypeScript, simplemente cambie el nombre de los archivos js a archivos ts (o use la asignación de rutas de TS para asignar importaciones a archivos .js). Problema resuelto. :hombre_encogiéndose de hombros:

EDITAR: se corrigió "ejecutar" a "compilar", que es lo que quise decir, pero puedo ver cómo eso puede haberse interpretado de manera diferente.

@ mkay581 TypeScript nunca tuvo la intención de ejecutar nada, solo para generar archivos JS.

El proyecto simple de @valeriob probablemente tendría pocos archivos como máximo, que no es necesario agrupar. Los navegadores de hoy en día tienen importaciones integradas, no hay necesidad de evitar eso. Entonces sería tan simple como escuchar los eventos de navegación en el navegador, luego mapear cada evento a la ruta correspondiente, cada ruta podría importar datos con fetch y una vez devueltos podrían renderizarse con motores de plantillas no compilados (lit- html, HyperHTML o más antiguos como Moustache, Handlebars, Pug, etc.). Listo, no hay necesidad de fantasear con el paquete web, el marco o cualquier biblioteca de utilidades, solo escuchas, expresiones regulares, búsqueda, promesas y un motor de plantillas js simple.

Gracias @Draccoz , ¿puede decirme cómo hacer que funcione este escenario simple? https://github.com/valeriob/Typescript_Non_SPA
Es un archivo .ts simple que hace referencia a una biblioteca JS (rxjs como ejemplo) y quiero consumirlo como módulo en una página html.

@valeriob Esto no es tan trivial como debería ser. La mayoría de las bibliotecas de terceros, incluso cuando declaran que son compatibles con los módulos ES, no están en el mundo de los navegadores.
RxJS es algo que me interesó principalmente cuando lo llevé al flujo nativo, pero esperan a que se resuelva este ticket antes de decidir implementarlo ellos mismos (gracioso...).
En la arquitectura que estaba diseñando, inicialmente usé sed para corregir todas las importaciones, pero luego cambié de opinión para usar un servidor de desarrollo simple con reescritura de rutas. Mi concepto es no tener dependencias externas en mis aplicaciones aparte de rxjs, mecanografiado y lit-html (node_modules con 4 carpetas y pruebas/compilaciones de CI ULTRA rápidas). Si TS reescribiera las rutas, eliminaría la necesidad de mi servidor, aunque de todos modos son alrededor de 90 líneas de código. Es de código abierto, si alguien quiere un enlace, solo pregunte o verifique las organizaciones en mi perfil.

En cuanto a las páginas simples, me refería a aquellas que realmente no necesitan ninguna biblioteca, como presionar una URL -> obtener datos -> mostrarlos -> repetir.

No necesitar usar ninguna biblioteca en Js es pura fantasía ya que Js no tiene una biblioteca base.

El escenario simple es el que vinculé, y no funciona. También es el escenario más común para las personas que no quieren sumergirse en el loco mundo de compilación/paquete web que complica las cosas sin ningún beneficio real, limita mucho sus opciones, hace que los desarrolladores luchen contra las herramientas más que escribir su aplicación y ralentizan su desarrollo. lazo.

Se está haciendo mucha gimnasia mental aquí para negar que este problema exista y que sea una preocupación importante para la productividad de muchos desarrolladores.

Explicar que _no debería ser un problema_ no _resuelve el problema_. El software debe ajustarse a los modelos mentales de los usuarios, no imponer su propio modelo de implementación a los usuarios. (cosas de UX)

Si los usuarios están conceptualizando tsc como un compilador similar a C, según @borfast , entonces ese es el modo mental privilegiado que debe acomodarse, a pesar de los detalles de implementación de tsc.

La pregunta del OP tiene más de 200 pulgares arriba, más que todos los demás problemas en el repositorio.

Este tema merece un voto de la comunidad. Por favor considere iniciar una encuesta.

Si la mayoría de los usuarios quieren que tsc reescriba sus importaciones, entonces esa es la respuesta correcta. Al menos esa es la forma UX de ver las cosas.

Es incluso más simple que eso, si mecanografiado como lenguaje es un superconjunto de JavaScript, la salida de tsc (incluso el cambio de archivo de salida no único) debería ser digerible por JavaScript mismo.

@weoreference si define de manera clara (no escribe código, solo diseña) cómo EXACTAMENTE debería reescribir rutas, considerando múltiples entornos (node.js, navegador), múltiples posibilidades de configuración de paquetes (investigando todas las características actuales, planificadas y posibles futuras de paquete web, resumen y paquetería y cualquier otro paquete) entonces seguro, entonces creo que el equipo de TypeScript estaría completamente de su lado.

Si no estás dispuesto a hacerlo o crees que es demasiado difícil, deja de pedirles que creen una función que nadie pueda describir, es como "No me importa cómo, pero haz que esta vaca vuele"...

@Draccoz , desea que su automóvil cambie de marcha para poder conducirlo a más de 10 km / h, pero estoy seguro de que el fabricante nunca le pidió que aprendiera cómo funciona un tren de engranajes, y mucho menos diseñar uno.

En cuanto al tema de los paquetes y todo eso, ¿por qué es un bloqueador para esto?

Mire, solo quiero usar módulos ES, no quiero lidiar con toda la locura de Babel y Webpack. ¿Por qué no puede ser una opción opcional del compilador que simplemente cambia la extensión del archivo a .js? Si este comportamiento entra en conflicto con otras opciones de configuración establecidas por el usuario, debe deshabilitarse automáticamente, o debe mostrarse una advertencia/error y la compilación debe detenerse cuando se ejecuta tsc, para que el usuario sepa que necesita cambiar la configuración.

Realmente no veo por qué esto es imposible.

@Draccoz Hola :) Bueno, tal como lo veo, estás preguntando dos cosas:

  1. Cómo se puede implementar

  2. Cómo yo, el desarrollador, puedo indicarle a tsc que quiero cambiar el nombre de las importaciones de cierta manera, para mi entorno particular

Aquí están mis pensamientos.

  1. Consulte la respuesta de @borfast ; es una respuesta de "orden superior", pero sucinta :)

  2. Tal vez pueda pasar un indicador a tsc/tsconfig, como "renameImports":true, o alguna otra señal que tsc detecte. Si se necesita más precisión, entonces tal vez la bandera no debería ser booleana sino tomar una cadena, tal vez algo como esto:

extensión de importación estándar: 'js'

por lo que todas las importaciones sin extensiones de archivo tienen como valor predeterminado .js

Conclusión:
Esta funcionalidad solo parece difícil de implementar porque asume que Q2 (esquema de cambio de nombre de importación) debe ser conocido de antemano por Q1 (es decir, por tsc). Pero en realidad, no. Yo, el desarrollador humano, puedo proporcionar fácilmente este "conocimiento mundial" a tsc sin necesidad de saber cómo funcionan los paquetes web/navegadores/etc. Todo esto con una simple bandera.

Un usuario no preguntó @borfast Transmission, se lo proporcionó un automóvil con un fabricante, el usuario simplemente aceptó que es una función nueva y comenzó a usarla; lo siento, este no es un argumento adecuado. En comparación con el ejemplo suyo del fabricante de automóviles del usuario, es más como "Quiero que mi automóvil sea un automóvil completamente eléctrico con un alcance de 100,000 millas y una velocidad máxima que alcance la velocidad de un avión. No me importa cómo lograrlo, lo quiero y eso es todo - punto.
@weoreference un poco malentendido en mis preguntas. Estaba preguntando sobre: ​​¿cómo hacer que tsc entienda a qué apunta el camino? ¿Es un archivo js directamente? ¿O es una carpeta con index.ts adentro? ¿O es un módulo con package.json que contiene el campo main ? ¿O es el siguiente campo? ¿O cualquier otro que no sea estándar? ¿O es una ruta reescrita por webpack? O enrollable? Si es así, ¿dónde está la configuración? ¿Es otro paquete tal vez? ¿Algunos menos conocidos? ¿Y cuáles son los otros casos de uso en los que no pensé en la oración anterior?

Tal vez pueda pasar un indicador a tsc/tsconfig, como "renameImports":true, o alguna otra señal que tsc detecte.

@weoreference , ¿no puedes hacer esto con el mapeo de rutas ? La opción paths en el archivo TSconfig nos da el control para asignar las rutas de importación a los archivos JS. Lo siento si estoy interpretando mal.

@Draccoz Gracias por su respuesta, déjeme aclarar

¿Y cuáles son los otros casos de uso en los que no pensé en la oración anterior?

Oh, sí, sería muy difícil para tsc tener conocimiento sobre todas estas combinaciones de herramientas de entorno/construcción.

Pero tsc podría tener una utilidad simple que ayude a los desarrolladores a cubrir la mayoría de los casos de uso, y este es el valor de configuración de "extensión de importación estándar" que expliqué.

Por supuesto, aquí viene el problema de la “garantía”. Anteriormente en este hilo, se argumentó que tsc debería "garantizar" que el js compilado se ejecutará de hecho [en algún entorno].

Bueno... tal vez este era un compromiso demasiado difícil. De hecho, es muy difícil para tsc garantizar que js se ejecutará [en algún entorno] porque, como acaba de describir, ese entorno es muy difícil de definir en el panorama actual de js.

Pero la utilidad de indicador simple propuesta por @borfast resuelve la mayoría de los errores de importación js que encuentran los nuevos usuarios que prueban tsc.

Uso avanzado, que como mencionas consiste en todas estas consideraciones —-

¿Es un archivo js directamente? ¿O es una carpeta con index.ts adentro? ¿O es un módulo con package.json que contiene el campo principal? ¿O es el siguiente campo? ¿O cualquier otro que no sea estándar? ¿O es una ruta reescrita por webpack? O enrollable? Si es así, ¿dónde está la configuración? ¿Es otro paquete tal vez?

— bueno, ese uso, de hecho, puede dejarse en manos de scripts de usuario personalizados, paquetes y otras herramientas.

Pero solo porque el uso avanzado es difícil de resolver no significa que debamos evitar resolver los casos fáciles.

Y el caso más sencillo es agregar una extensión .js a las importaciones; que podemos resolver y debemos resolver.

@weoreference , así que me votaste negativo por hacer una pregunta y tratar de ser útil y luego ignoras la pregunta. Parece que solo desea discutir y debatir en lugar de avanzar hacia una solución productiva. Has rechazado el intento de todos de hacerlo. Último mensaje para mí en este hilo. Disculpas por todo el spam, todos.

@weoreference mira el comienzo de esta conversación, en los comentarios de @DanielRosenwasser . Él explica por qué no lo implementarían ("¿en este momento"? dando esperanzas inútiles). Después de su declaración, nadie de TypeScript comentó más sobre el tema. Para mí, esta discusión debería cerrarse y Microsoft debería declarar oficialmente su postura. Período.
Solo como nota al margen: personalmente estoy a favor de esa función, simplificaría MUCHO. Perdí la esperanza, pensé, ya que también entiendo los argumentos del equipo mecanografiado.

@weoreference

No es hipotético, tsc sabe que lo generará. Se garantiza que existe, cuando se usa tsc.

Pero hay una simetría implícita aquí que no estás admitiendo.

Esta "garantía" que mencionas es válida en ambos sentidos. Si, como usted dice, "tsc sabe que generará [archivos js]", entonces es una pregunta igualmente válida: "Bueno, entonces, ¿por qué tsc NO actúa sobre esta garantía y aplica las extensiones .js que sabe que es falta en el js compilado?

La simetría no se sostiene en realidad. No es tan simple como simplemente "aplicar una extensión .js": tsc tendría que resolver y reescribir el especificador, y la resolución puede depender de las declaraciones de tipo. TypeScript y Babel admiten modos de compilación de un solo módulo (aisladosModules para tsc) y, en este caso, si importa tipos en lugar de JavaScript, tsc tendría que cargar las declaraciones de tipo para determinar dónde estaría el archivo .js correspondiente, a fin de reescribir el especificador Para mantener la coherencia y no tener casos extremos, lo más sencillo es admitir solo la importación de los archivos .js que existen antes de la compilación o que son un resultado conocido del proyecto actual.

@justinfagnani @Draccoz Gracias; bien, si entiendo.

Mi comentario final: "solo porque los casos difíciles no se pueden resolver no significa que no podamos resolver los casos fáciles".

Gracias

He asumido que TypeScript va en contra de las especificaciones aquí (y produce JavaScript no válido), pero no puedo encontrar ninguna parte de las especificaciones que realmente requiera que la ruta de importación coincida exactamente con los nombres de los archivos (con extensión). Es muy difícil de digerir, por lo que no estoy completamente seguro, pero todo lo que puedo encontrar es que la especificación requiere que el 'ModuleSpecifier' en 'FromClause' sea un 'StringLiteral'. Parece una definición muy vaga, pero supongo que puede ser para permitir flexibilidad en la resolución del módulo en los diferentes entornos en los que existe ECMAScript. ¿Alguien puede confirmar si estoy leyendo esto correctamente? Si este es realmente el caso, tendría que suavizar mi postura hacia la forma en que TypeScript maneja esto. Aunque aún prefiero que haya más interoperabilidad entre TypeScript, Node y la web. La situación actual no es la ideal.

Llegué a este problema después de leer esto . Ese problema me dio la impresión de que el sistema de Node funciona de la forma en que lo hace (coincidencia estricta de los nombres de archivo) debido a la especificación ES, pero ahora puedo ver que lo entendí mal (no se referían a la especificación ES), y quizás tampoco Node, ni TypeScript están haciendo nada 'mal'. Entonces, este problema se trata realmente de incompatibilidades entre enfoques igualmente válidos para la resolución de módulos entre diferentes entornos. Aún así, claramente los principales entornos de destino de TypeScript son Node y la web, y aunque Node teóricamente podría cambiar su enfoque, no creo que sea muy probable que los navegadores lo hagan, por lo que sigo pensando que este problema es válido.

Editar: creo que podría ser esta sección de la especificación que parece especificar que la resolución del módulo está 'definida por el host'.

@kj el texto de especificación relevante está en la especificación HTML: https://html.spec.whatwg.org/multipage/webappapis.html#resolve -a-module-specifier

Dice que los especificadores de importación deben ser direcciones URL completas o rutas absolutas o relativas. Si el especificador no se analiza como una URL (generalmente comienza en http:// o https:// ) o comienza con / , ./ o ../ , se arroja un error. Los especificadores de ruta se resuelven con la URL base de los importadores.

No se realiza ninguna otra búsqueda o resolución de ruta. Esto significa que el especificador debe resolver la URL completa del módulo y debe incluir la extensión si el servidor lo requiere. Los servidores tienen la opción de devolver respuestas para direcciones URL sin extensión.

La razón por la que Node optó por un algoritmo de resolución más restrictivo para los módulos es para ser más compatible con la web, por lo que es más común que los módulos publicados en npm no necesiten herramientas adicionales para ejecutarse de forma nativa en los navegadores. Importar por nombre de paquete sigue siendo una característica muy importante, por lo que Node lo admite, pero con el objetivo de ser compatible con la propuesta Import Maps (que Deno y SystemJS ya admiten).

En total, el soporte de tsc para importar con extensiones .js funciona perfectamente tanto en Node como en navegadores web. En realidad, son las importaciones sin extensión las que causan problemas sin herramientas adicionales. Sin embargo, por lo general, las herramientas que admiten la resolución de nodos para los nombres de los paquetes también usarán la resolución de estilo class require() y resolverán las rutas relativas y agregarán sus extensiones también. Esto es lo que hace es-dev-server .

Gracias @justinfagnani. Entonces, al menos en el navegador, depende de cómo lo implemente el servidor. Es bueno saberlo. Esto todavía es bastante poco intuitivo y confuso y creo que debe haber más convergencia entre los proyectos por el bien de la comunidad, pero ya no estoy seguro de cómo sería eso.

Editar: por ahora, esto será suficiente para mí (especialmente dadas las explicaciones anteriores, me siento más cómodo):

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

No estoy seguro de si se hace referencia a esta opción en la documentación de TypeScript, pero si no es así, tal vez debería ser para evitar confusiones. No parece serlo, buscando ' sitio: typescriptlang.org specifier-solution' o ' site: staging-typescript.org specifier-resolution'. Aunque, como esto todavía es bastante nuevo en Node, no es demasiado sorprendente.

@justinfagnani Estoy de acuerdo en que la extensión .js solo funciona en la mayoría de los casos, excepto en los casos en que alguien toma una postura ideológica _en contra_ (por ejemplo, https://github.com/TypeStrong/ts-node/issues/783, con el que está familiarizado).

Hice una versión libre de dependencias del script de @quantuminformation aquí . Esa versión también contiene una expresión regular que solo reemplazará los módulos que ya no terminan con .js .

misma necesidad

Lograr extensiones de .js para la compatibilidad con ESM mediante el uso de .js en las declaraciones de importación no funciona para mí. Cuando importo un archivo TS y omito cualquier extensión, se compila bien. Cuando agrego una extensión .js a la importación, recibo muchos errores (que no deberían existir) del compilador de TS.

Parece que la razón principal por la que esta función no se está desarrollando se debe a la dificultad/imposibilidad de compatibilidad con varios paquetes, pero Node.js y los paquetes desarrollaron sus propios esquemas de módulos en ausencia de soporte para módulos en ECMAScript. Ahora que tenemos ESM, por inadecuado que algunas personas puedan considerarlo, es el camino a seguir. A medida que se desarrolle más código en ESM y componentes web, el uso de paquetes disminuirá y este punto crítico entre TS y ESM desarrollará más fricción. Sería bueno, incluso si el soporte inicial tiene errores y no considera todos los casos de uso, si pudiera comenzar a ser compatible.

Hasta que haya una solución mejor, este es un script de nodo sin dependencias para usar como tarea de compilación

configure en su paquete.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)

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

¿Alguien puede recordar lo que estaban haciendo hace 3 años cuando se abrió este problema?

La solución sin paquete es escribir proyectos distribuidos en la web con .js como extensión.

Eso funciona al 100%. El mayor problema es tratar de escribir módulos destinados a la web y Node.js, pero eso es un problema para JS en general.

Si hubiera algo que hacer, sería agregar --moduleResolution=web , pero ese no es el alcance de este problema aquí.

Tuve que escribir este script posterior a la compilación para agregar la extensión .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

Tengo un script similar, en JavaScript:
https://github.com/yoursunny/NDNTs/blob/743644226fe18d48e599181e87ad571a2708a773/mk/build-post.js

Se invoca como:

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

El principal inconveniente de este tipo de scripts es que rompen los mapas de origen, por lo que la depuración se vuelve menos efectiva.

utilizando herramientas modernas y extensiones .js en código fuente, todo funciona de manera excelente en nodos y navegadores

  • mecanografiado
  • es módulos
  • enrollar

Solo puedo suponer que las personas que tienen problemas aquí en realidad están atrapadas en algún híbrido roto de módulos es y resolución de nodo, ya que los desarrolladores se aferran a puntos de referencia familiares de sus antiguos flujos de trabajo; probablemente el webpack sea el culpable...

- probablemente webpack es el culpable...

Y así, el gato está fuera de la bolsa.

utilizando herramientas modernas y extensiones .js en código fuente, todo funciona de manera excelente en nodos y navegadores

_La mayoría_ de las cosas funcionan excelentemente, y estoy de acuerdo en que todos los archivos fuente deben tener extensiones .js en sus exportaciones. En mi experiencia, lo único que no funciona bien con esto es ts-node, debido a su obstinada negativa a admitir extensiones .js . Sí, puede agregar un paso previo a la transpilación antes de ejecutar el nodo, y las importaciones .js funcionarán, pero si desea ejecutar el código o las pruebas .ts directamente con el nodo y también en el navegador, actualmente estás mayormente sin suerte. (Para aclarar, creo que este es un error de ts-node, no un error de TypeScript).

Gracias @chase-moskal.

Refactoricé el repositorio y el archivo tsconfig, y ahora
import {something} from './something.js'
no tira
typescript force overwrite error TS5055: Cannot write file because it would overwrite input file
más, y ya no necesito el hack fix-ts-imports .

En más de 250 comentarios, ha habido muy poca claridad. Para resumir:

Antecedentes

Módulos de navegador

Los navegadores resuelven los módulos de EcmaScript según la URL, incluidas las URL relativas. ( QUÉ WG )

Módulos de Node.js

Node.js resuelve los módulos (tanto EcmaScript como CommonJS específico de Node.js) a través de un algoritmo mucho más complejo que involucra múltiples respaldos y analiza archivos package.json. ( Node.js ) Eso se puede personalizar, por ejemplo, con --experimental-specifier-resolution=explicit que requiere la ruta completa.

Módulos de mecanografiado

TypeScript tiene varios algoritmos de resolución de módulos disponibles y una variedad de opciones para personalizarlos aún más. ( TypeScript ) La intención es que los usuarios escriban los mismos especificadores de módulo que se usan en la salida producida, ajustando la resolución de tsc con opciones como baseUrl y pathMappings.

En la práctica, la mayoría de los usuarios usan el nodo moduleResolution, apuntando a un entorno Node.js o un paquete compatible. Esta solicitud se centra en los usuarios que se dirigen a navegadores sin un paquete.

resolución del módulo ts-node

Aparentemente, ts-node no admite identificadores de módulos con extensiones. Aunque no está claro por qué, ya que tanto Node.js como TypeScript lo hacen, y ts-node es aparentemente la fusión de esos.

Hechos

Dato 1: puedes usar extensiones .js

Para una compatibilidad más amplia (es decir, navegadores), puede usar extensiones .js hoy. Con la extraña excepción de ts-node (error IMO), todo funciona ahora especificando la ruta completa (es decir, incluida la extensión).

Hecho 2: no es tan simple como "agregar extensión"

Esta solicitud se resume mejor como "transformar el identificador del módulo en la ruta del archivo". Por ejemplo ./example se convierte en ./example/index.js y 'lodash' se convierte en '.node_modules/lodash/index.js' .

Tenga en cuenta que a veces ni siquiera hay una ruta de archivo resuelta, como con las declaraciones de módulos ambientales.

declare module "lodash" {
}

Quizás la reescritura del módulo se limite a los módulos TS en el proyecto/compilación actual.

En cualquier caso, ahora estamos violando uno de los parámetros de diseño de TS, que otros módulos afectan la salida del actual.

Conclusión

Es posible usar la ruta para los identificadores de módulos que funcionan para web. (Por ejemplo ./foo/index.js en lugar de ./foo .)

(Aunque en términos prácticos, es probable que desee un paquete de todos modos para los navegadores de destino. Es decir, si se utilizan paquetes npm).

@pauldraper hay un problema importante con el "Hecho 2":

Esta solicitud se resume mejor como "transformar el identificador del módulo en la ruta del archivo". Por ejemplo, ./example se convierte en ./example/index.js y 'lodash' se convierte en 'node_modules/lodash/index.js'.

Realmente no desea resolver los especificadores fuera de su paquete en el momento de la compilación, porque es posible que estas no sean las rutas disponibles cuando el paquete se instala en otro lugar. Debe ejecutar la resolución del módulo Node en cada instalación de paquete única. De lo contrario, podríamos escribir y publicar import {} from './node_modules/lodash/index.js' y terminar con eso.

@justinfagnani , estoy de acuerdo, pero eso demuestra que los identificadores de módulos son abstractos y está manipulando ubicaciones de módulos fuera de tsc. Y que tsc no puede/no necesita preocuparse por tales manipulaciones.

Esta solicitud se resume mejor como "transformar el identificador del módulo en la ruta del archivo". Por ejemplo, ./example se convierte en ./example/index.js y 'lodash' se convierte en '.node_modules/lodash/index.js'.
Tenga en cuenta que a veces ni siquiera hay una ruta de archivo resuelta, como con las declaraciones de módulos ambientales.

De eso no se trata esta solicitud. Se trata de agregar extensión al emitir código. Queremos escribir módulos compatibles con el tipo: "módulo" sin un paso de compilación hacky adicional. Los módulos externos como lodash continuarían funcionando incluso sin .js, ya que estos son CommonJs.

Ejemplo:

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

Además del mecanografiado anterior, no es compatible con las "exportaciones" y el "tipo" de package.json. No hay camino hacia un verdadero ESM en los proyectos que gestiono.

Esta solicitud se centra en los usuarios que se dirigen a navegadores sin un paquete.

Eso es incorrecto. Rara vez escribo TS/JS para navegadores, principalmente trabajo en el código del lado del servidor y también lo necesito porque quiero usar la carga de ESM en el nodo y no depender de los paquetes y el código adicional para la carga del módulo.

Los módulos externos como lodash continuarían funcionando incluso sin .js, ya que estos son CommonJs.

A menos que no lo sean.

Cuando se emite.

Podría ser ./moduleA.js . O podría ser ./moduleA/index.js , ¿verdad? La resolución del módulo Node.js permite varias rutas.

A menos que no lo sean.

¿Puede proporcionar un ejemplo cuando estos no funcionarían? Node.js acaba de obtener soporte para importar exportaciones con nombre de CommonJS.
https://nodejs.org/api/esm.html#esm_import_statements

Podría ser ./moduleA.js. O podría ser ./moduleA/index.js, ¿verdad? La resolución del módulo Node.js permite varias rutas.

No en modo ESM. index.js ya no sería compatible como lo es ahora. El cargador ESM leería los metadatos de package.json "exportaciones" y "tipo".
https://nodejs.org/api/esm.html#esm_mandatory_file_extensions

Para proyectos basados ​​en mecanografiado + node.js, necesitamos una mejor historia ESM nativa. Esto puede suceder a través de herramientas (mecanografiado) o en node.js. El problema es que no hay consenso sobre lo que se debe hacer.

Edite el enlace eliminado al nodo PR ya que era engañoso.

¿Fue útil esta página
0 / 5 - 0 calificaciones