简体   繁体   English

如何使TypeScript输出有效的ES6模块导入语句?

[英]How to make TypeScript output valid ES6 module import statements?

All major browsers have supported ES6 modules for some time. 一段时间以来, 所有主流浏览器都支持ES6模块。

These differ from many of the server-side approaches in that they need to specify the exact file to import from - they can't use file discovery. 这些与许多服务器端方法的不同之处在于,它们需要指定要导入的确切文件 - 它们不能使用文件发现。

This makes sense - in Node applications or bundlers like WebPack they only really need the name of the module, and then can spend a bit of extra time discovering the specific file that holds the code. 这是有道理的 - 在Node应用程序或像WebPack这样的捆绑器中,它们只需要模块的名称,然后可以花费一些额外的时间来发现保存代码的特定文件。 On the web that could be a lot of wasted round trips (is 'library' in library/index.js , or library/library.js , or library.js ? require() doesn't care but on the web we have to). 在网上可能是浪费了很多的往返(在library/index.js 'library' ,或者library/library.js ,或者library.jsrequire()并不关心,但在网络上我们必须)。

TypeScript has ES6 modules support (set "module": "es6" in tsconfig.json ) but it appears to be using a file discovery approach... TypeScript支持ES6模块(在tsconfig.json设置"module": "es6" )但似乎是使用文件发现方法...

Suppose I have library.ts : 假设我有library.ts

export function myFunction(...) {  ... }

Then in app.ts : 然后在app.ts

import {myFunction} from './library';
var x = myFunction(...);

However, this is unchanged when transpiles - the TS output still has the 'library' name for file discovery, which doesn't work. 但是,在转换时这没有改变 - TS输出仍然具有文件发现的'library'名称,但这不起作用。 This throws an error because 'library' isn't found: 这会引发错误,因为找不到'library'

<script type="module" src="app.js"></script>

In order for ES6 modules to work the TS output needs to reference the specific file: 为了使ES6模块工作,TS输出需要引用特定文件:

import {myFunction} from './library.js';
var x = myFunction(...);

How do I make TS output valid ES6 module import statements? 如何使TS输出有效的ES6模块import语句?

Note: I am not asking how to make a bundler join the TS output into a single file. 注意:我不是问如何使捆绑器将TS输出连接到单个文件中。 I specifically want to load these files individually using <script type="module"> 我特别想使用<script type="module">单独加载这些文件

This is a bug in TypeScript , though there's some debate about whether it should be fixed. 这是TypeScript中的一个错误 ,尽管有关它是否应该修复的争论。

There is a workaround: while TS won't allow you to specify a .ts file as the source of a module, it will let you specify a .js extension (and then ignore it). 有一种解决方法:虽然TS不允许您指定.ts文件作为模块的源,但它将允许您指定.js扩展名(然后忽略它)。

So in app.ts : 所以在app.ts

import {myFunction} from './library.js';
var x = myFunction(...);

This then outputs correctly in app.js , and TS has found the import definitions and bindings correctly. 然后在app.js正确输出,并且TS已正确找到import定义和绑定。

This has one advantage/gotcha to be aware/careful of: TS just ignores the .js extension and loads the rest of the path with the usual file discovery. 这有一个优点/需要注意/注意:TS只是忽略.js扩展并使用通常的文件发现加载路径的其余部分。 This means that it will import library.ts , but it would also find definition files like library.d.ts or import files in a library/ folder. 这意味着它将导入library.ts ,但它也会找到像library.d.ts这样的定义文件或导入library/文件夹中的文件。

That last case might be desirable if you're joining those files together into a library.js output, but to do that you're going to be looking at either lots of nested tsconfig.json files (messy) or possibly the pre-transpiled output of another library. 如果你将这些文件一起加入到library.js输出中,那么最后一种情况可能是可取的,但要做到这一点,你将会看到许多嵌套的tsconfig.json文件(凌乱)或者可能是预先编译的另一个库的输出。

The compiler takes a module kind flag: 编译器采用模块类标志:

--module ES2015

And you'll also need to be targeting ECMAScript 6 / 2015... 而且你还需要针对ECMAScript 6/2015 ...

--target ES2015

You need both the module kind and the compilation target to be ECMAScript 2015 minimum to have "zero transformation imports". 您需要将模块类型和编译目标都作为ECMAScript 2015最小值来进行“零转换导入”。

Your import statements should look half-way between your two examples: 您的import语句应该看起来在两个示例之间:

import {myFunction} from './library';

Additional Notes 补充笔记

There is still clearly a lot of discussion about module resolution... there is the TC39 specification , and the WHATWG specification - plus Node is currently still file-extention-less... looks like RequireJS might live longer than we all thought... please see: 关于模块解析仍然有很多讨论...有TC39规范WHATWG规范 - 加上节点目前仍然没有文件扩展...看起来像RequireJS可能比我们想象的更长寿。 。 请参见:

The TypeScript thread for supporting file extensions during import transpilation (ie will it add the file extension?). 用于在导入转换期间支持文件扩展名的TypeScript线程 (即它是否会添加文件扩展名?)。

Recommendation 建议

Stick with a module loader, for example RequireJS or SystemJS. 坚持使用模块加载器,例如RequireJS或SystemJS。 This also means your modules can be shared between browser and server by using UMD or System module kinds repectively. 这也意味着您可以分别使用UMD或系统模块类型在浏览器和服务器之间共享您的模块。

Obviously, once the ECMAScript discussion reaches a conclusion this will need a revisit. 显然,一旦ECMAScript讨论得出结论,这将需要重新审视。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM