Javascript 如何使TypeScript输出有效的ES6模块导入语句?
已经支持ES6模块一段时间了 这些方法与许多服务器端方法的不同之处在于,它们需要指定要从中导入的确切文件—它们不能使用文件发现 这是有意义的——在节点应用程序或像WebPack这样的捆绑程序中,它们只需要模块的名称,然后就可以花费一些额外的时间来发现包含代码的特定文件。在web上,这可能会浪费很多往返时间(是Javascript 如何使TypeScript输出有效的ES6模块导入语句?,javascript,typescript,es6-modules,Javascript,Typescript,Es6 Modules,已经支持ES6模块一段时间了 这些方法与许多服务器端方法的不同之处在于,它们需要指定要从中导入的确切文件—它们不能使用文件发现 这是有意义的——在节点应用程序或像WebPack这样的捆绑程序中,它们只需要模块的名称,然后就可以花费一些额外的时间来发现包含代码的特定文件。在web上,这可能会浪费很多往返时间(是library/index.js中的'library',还是library/library.js,或者library.js?require()不在乎,但在web上我们必须这样做) TypeS
library/index.js中的'library'
,还是library/library.js
,或者library.js
?require()
不在乎,但在web上我们必须这样做)
TypeScript支持ES6模块(在tsconfig.json
中设置“模块”:“ES6”
),但它似乎使用了文件发现方法
假设我有library.ts
:
export function myFunction(...) { ... }
import {myFunction} from './library';
var x = myFunction(...);
import {myFunction} from './library.js';
var x = myFunction(...);
然后在app.ts
中:
export function myFunction(...) { ... }
import {myFunction} from './library';
var x = myFunction(...);
import {myFunction} from './library.js';
var x = myFunction(...);
但是,当传输文件时,这是不变的-TS输出仍然具有文件发现的'library'
名称,这不起作用。这会引发错误,因为找不到'library'
:
<script type="module" src="app.js"></script>
如何使TS输出有效的ES6模块import
语句?
注意:我不是问如何使绑定器将TS输出连接到单个文件中。我特别想使用
单独加载这些文件。编译器采用模块种类标志:
--module ES2015
您还需要针对ECMAScript 6/2015
--target ES2015
您需要将模块种类和编译目标都设置为ECMAScript 2015最小值,以实现“零转换导入”
您的导入语句应该介于两个示例之间:
import {myFunction} from './library';
附加说明
显然,关于模块分辨率还有很多讨论。。。存在,并且-plus节点当前仍然没有文件扩展名。。。看来RequireJS的寿命可能比我们想象的要长。。。请参阅:
(即是否会添加文件扩展名?)
推荐
坚持使用模块加载器,例如RequireJS或SystemJS。这也意味着,通过分别使用UMD或系统模块,您的模块可以在浏览器和服务器之间共享
显然,一旦ECMAScript讨论得出结论,这将需要重新讨论。这是一个问题,尽管关于是否应该修复它还有一些争论
有一个解决方法:虽然TS不允许您指定.TS
文件作为模块的源,但它允许您指定.js
扩展名(然后忽略它)
因此在app.ts
中:
export function myFunction(...) { ... }
import {myFunction} from './library';
var x = myFunction(...);
import {myFunction} from './library.js';
var x = myFunction(...);
然后在app.js
中正确输出,TS已正确找到import
定义和绑定
这有一个优点/gotcha需要注意/小心:TS只是忽略了.js
扩展名,并用通常的文件发现加载路径的其余部分。这意味着它将导入library.ts
,但也会找到定义文件,如library.d.ts
或导入library/
文件夹中的文件
如果您要将这些文件合并到
library.js
输出中,最后一种情况可能是可取的,但要做到这一点,您需要查看大量嵌套的tsconfig.json
文件(凌乱),或者可能是另一个库的预传输输出和…来自“/library.js”代码>是两个不同的东西,第一个是命名包,第二个是到module@MaximKoretskyi是-命名包有一个入口点,该入口点必须是模块导入的显式相对或绝对路径。web无法使用包名。如果使用命名包导入,TS无法输出相对路径,因为库与导入模块不在同一目录中,对吗?@MaximKoretskyi没关系,路径在任何情况下都不起作用/library
失败,。/src/utils/library
失败,https://example.com/cdn/library
失败。何时失败?在浏览器中?这稍微好一点,但不起作用。在一个支持的浏览器(比如说金丝雀)中尝试一下,你会得到一个404作为不存在的文件“library”。TS输出需要指定符合ES6模块规范的文件,因此从“/library.js”导入{myFunction}
“不需要.js
扩展名”-这取决于具体情况。@Bergi这正是我的观点。在ES6模块规范中,几乎所有需要.js
的主流浏览器都将实现该规范。如果启用ES6模块(通过命令行上的--module ES2015
,或通过配置中的“module”:“ES6”
),则TS会将library.TS
传输到library.js
,这样编译工具就可以准确地知道特定的文件,而浏览器则不会,我不认为transpiler知道弄乱模块名称。不-我不认为我们同意这一点。我在许多库/框架上工作,这些库/框架不是专门针对节点或浏览器的,因此我编写ES风格的导入,并让TypeScript使用UMD标志对它们进行传输。这允许我将库打包为.js
+'.d.ts`包,可以在浏览器中使用,也可以在节点上使用,而不仅仅是从其他TypeScript程序使用。我们希望能够独立于模块的运行位置编写模块。如果使用Visual Studio代码,则可以将其配置为在自动导入模块时自动添加.js结尾。转到设置,然后在搜索字段中键入“模块说明符”。您可以找到选项“typescript>Preferences:Import Module Specifier Ending”,您可以将其设置为“.js”。