在 Typescript 编译(ES6 模块)期间在相对导入语句上附加 .js 扩展名 [英] Appending .js extension on relative import statements during Typescript compilation (ES6 modules)

查看:57
本文介绍了在 Typescript 编译(ES6 模块)期间在相对导入语句上附加 .js 扩展名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这似乎是一个微不足道的问题,但需要使用什么设置/配置来解决这个问题并不是很明显.

This seems to be a trivial problem, but it is not very obvious what settings/configurations need to be used to solve this issue.

这里是Hello World程序目录结构和源代码:

Here are the Hello World program directory structure and the source code:

目录结构:

| -- HelloWorldProgram
     | -- HelloWorld.ts
     | -- index.ts
     | -- package.json
     | -- tsconfig.json

index.ts:

import {HelloWorld} from "./HelloWorld";

let world = new HelloWorld();

HelloWorld.ts:

HelloWorld.ts:

export class HelloWorld {
    constructor(){
        console.log("Hello World!");
    }
}

package.json:

package.json:

{
  "type": "module",
  "scripts": {
    "start": "tsc && node index.js"
  }
}

现在,执行命令 tsc &&节点 index.js 导致以下错误:

Now, execution of the command tsc && node index.js results in the following error:

internal/modules/run_main.js:54
    internalBinding('errors').triggerUncaughtException(
                              ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'HelloWorld' imported from HelloWorldindex.js
Did you mean to import ../HelloWorld.js?
    at finalizeResolution (internal/modules/esm/resolve.js:284:11)
    at moduleResolve (internal/modules/esm/resolve.js:662:10)
    at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:752:11)
    at Loader.resolve (internal/modules/esm/loader.js:97:40)
    at Loader.getModuleJob (internal/modules/esm/loader.js:242:28)
    at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:50:40)
    at link (internal/modules/esm/module_job.js:49:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

很明显,问题似乎源于在 index.ts Typescript 文件中,import 语句中没有 .js 扩展名(<代码>从./HelloWorld"导入{HelloWorld};).Typescript 在编译期间没有抛出任何错误.但是,在运行时 Node (v14.4.0) 需要 .js 扩展名.

It is obvious that the problem seems to have been originated from the fact that in index.ts Typescript file there is no .js extension in the import statement (import {HelloWorld} from "./HelloWorld";). Typescript didn't throw any error during compilation. However, during runtime Node (v14.4.0) wants the .js extension.

希望上下文清楚.

现在,如何更改编译器输出设置(tsconfig.json 或任何标志),以便本地相对路径导入,例如 import {HelloWorld} from ./Helloworld; 将被替换为 import {HelloWorld} from ./Helloworld.js; 在 Typescript 到 index.js 文件中的 Javascript 编译期间?

Now, how to change the compiler output setting (tsconfig.json or any flags) so that local relative path imports such as import {HelloWorld} from ./Helloworld; will get replaced by import {HelloWorld} from ./Helloworld.js; during Typescript to Javascript compilation in the index.js file?

注意:在 typescript 文件中导入时可以直接使用 .js 扩展名.然而,它在处理数百个旧的 typescript 模块时并没有多大帮助,因为我们必须返回并手动添加 .js 扩展名.对我们来说,更好的解决方案是批量重命名并最终从所有生成的 .js 文件名中删除所有 .js 扩展名.

推荐答案

对于正在寻找此问题解决方案的开发人员,我们遇到的可能解决方法如下:

To fellow developers who are looking for a solution to this issue, the possible work-arounds we have come across are as follows:

  1. 对于新文件,可以在编辑时简单地在 Typescript 文件的导入语句中添加 .js" 扩展名.示例:import {HelloWorld} from "./HelloWorld.js";

如果处理旧项目,而不是检查每个文件并更新导入语句,我们发现简单地批量重命名和删除 .js" 扩展更容易通过一个简单的自动化脚本从生成的 Javascript 中提取.但是请注意,这可能需要在服务器端代码中稍作更改,以便为客户端提供具有正确 MIME 类型的这些无扩展名的 .js" 文件.如果您想避免这种情况,您可能需要使用正则表达式批量查找并递归替换导入语句以添加 .js 扩展名.

If working with old projects, rather than going through each and every file and updating the import statements, we found it easier to simply batch rename and remove the ".js" extension from the generated Javascript via a simple automated script. Please note however that this might require a minor change in the server side code to serve these extension-less ".js" files with the proper MIME type to the clients. If you want to avoid this, you may instead want to use regular expression to batch find and replace the import statements recursively to add the .js extension.

旁注:

关于 TS 团队在解决这个问题上的失败,似乎有一种倾向,试图断章取意地把这个问题与实际情况分开,并将其附加到一些设计原则上进行辩护.

Regarding the TS team's failure on resolving this issue, it appears that there is a tendency to try to blow up this issue out of context than what it really is and attach that to some design principles to defend.

然而,实际上这只不过是编译器如何不对称地处理扩展的问题.Typescript 编译器允许没有扩展名的 import 语句.然后继续添加.js"文件被翻译时相应输出文件名的扩展名,但对于引用此文件的相应导入语句,它忽略了它已添加.js"的事实.翻译过程中的扩展.脱离上下文的 URI 重写原则如何保护这种不对称性?

However, factually this is nothing more than an issue with how the compiler deals asymmetrically with the extension. The Typescript compiler allows import statement without an extension. It then goes on to add ".js" extension to the corresponding output filename while the file is being translated, but for the corresponding import statements where this file is referenced it ignores the fact that it has added ".js" extension during translation. How can this asymmetricity be defended by the out of context URI rewriting principles?

Typescript 文件和编译时生成的 Javascript 输出文件有固定的一一对应关系.如果引用的导入不存在,编译器会抛出错误.这些文件甚至不会编译!因此,断章取义或不可编译的示例提到其他冲突 URI 的可能性会使此类声明无效.

There is a fixed one to one correspondence between the Typescript file and the generated Javascript output file during compilation. If the referenced import does not exists, the compiler would throw an error. The files wouldn't even compile! So, out of context or non-compilable examples mentioning the possibility of other conflicting URIs invalidate such claims.

如果编译器只是生成无扩展名的输出文件,它也可以解决问题.但是,这是否也会以某种方式违反有关 URI 重写的设计原则?当然,在这种情况下,可能存在其他设计原则来捍卫这一立场!但这样的顽固岂不是进一步验证了TS团队在这个问题上的顽固或无知?

If the compiler simply generated extension-less output files it would also solve the issue. But, would that also somehow violate the design principle regarding URI rewrites? Certainly, in that case there could exist other design principles to defend the position! But wouldn't such stubbornness only help to further validate the adamancy or ignorance of the TS team on this issue?

这篇关于在 Typescript 编译(ES6 模块)期间在相对导入语句上附加 .js 扩展名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆