如何使 TypeScript 输出有效的 ES6 模块导入语句?
How to make TypeScript output valid ES6 module import statements?
All major browsers 支持 ES6 模块有一段时间了。
这些方法与许多服务器端方法不同,因为它们需要指定要从中导入的确切文件 - 它们不能使用文件发现。
这是有道理的——在 Node 应用程序或像 WebPack 这样的捆绑器中,他们只真正需要模块的名称,然后可以花一些额外的时间来发现保存代码的特定文件。在网络上,可能会浪费很多往返('library'
in library/index.js
,或 library/library.js
,或 library.js
?require()
不关心,但在网络上我们必须这样做)。
TypeScript 支持 ES6 模块(在 tsconfig.json
中设置 "module": "es6"
)但它似乎使用了文件发现方法...
假设我有 library.ts
:
export function myFunction(...) { ... }
然后在app.ts
:
import {myFunction} from './library';
var x = myFunction(...);
然而,这在转译时没有改变 - TS 输出仍然具有用于文件发现的 'library'
名称,这是行不通的。这会引发错误,因为未找到 'library'
:
<script type="module" src="app.js"></script>
为了让 ES6 模块工作,TS 输出需要引用特定文件:
import {myFunction} from './library.js';
var x = myFunction(...);
如何使 TS 输出有效的 ES6 模块 import
语句?
注意:我不是询问如何使捆绑器将 TS 输出加入单个文件。我特别想使用 <script type="module">
单独加载这些文件
编译器采用模块类型标志:
--module ES2015
并且您还需要以 ECMAScript 6 / 2015 为目标...
--target ES2015
您需要模块类型和编译目标至少为 ECMAScript 2015 才能具有 "zero transformation imports"。
您的导入语句应该看起来介于两个示例之间:
import {myFunction} from './library';
补充说明
显然还有很多关于模块解析的讨论......有 TC39 specification, and the WHATWG specification - 加上 Node 目前仍然没有文件扩展......看起来 RequireJS 可能比我们所有人都活得更久想...请看:
The TypeScript thread for supporting file extensions during import transpilation(即它会添加文件扩展名吗?)。
推荐
坚持使用模块加载器,例如 RequireJS 或 SystemJS。这也意味着您的模块可以通过分别使用 UMD 或系统模块类型在浏览器和服务器之间共享。
显然,一旦 ECMAScript 讨论得出结论,就需要重新审视。
这是一个 bug in TypeScript,尽管关于是否应该修复它存在一些争论。
有一个解决方法:虽然 TS 不允许您将 .ts
文件指定为模块的源,但它会让您指定 .js
扩展名(然后忽略它).
所以在 app.ts
:
import {myFunction} from './library.js';
var x = myFunction(...);
然后在 app.js
中正确输出,并且 TS 已正确找到 import
定义和绑定。
这有一个 advantage/gotcha 是 aware/careful 的:TS 只是忽略 .js
扩展名并使用通常的文件发现加载路径的其余部分。这意味着它将导入 library.ts
,但它也会找到 library.d.ts
之类的定义文件或在 library/
文件夹中导入文件。
如果您将这些文件连接到一个 library.js
输出中,最后一种情况可能是可取的,但要做到这一点,您将要查看大量嵌套的 tsconfig.json
文件(凌乱)或者可能是另一个库的预编译输出。
对于个人项目,我采用了另一种方式。因为我让 NPM 调用 shell 脚本将 index.html 复制到 /build 文件夹,所以我有 shell 脚本,然后批量重命名所有 .js 文件,使其完全没有扩展名。
我确实必须在“MIME 类型”部分通知 IIS,对于该特定站点,无扩展名文件应该具有 MIME 类型 application/javascript,但它确实有效。没有 webpack,没有 SystemJS,什么都没有。 Index.html 刚刚硬编码
<script type="module">
import "./app";
</script>
这很重要,因为我使用的测试框架 jest
不喜欢我将 .js 放入打字稿导入语句中。
All major browsers 支持 ES6 模块有一段时间了。
这些方法与许多服务器端方法不同,因为它们需要指定要从中导入的确切文件 - 它们不能使用文件发现。
这是有道理的——在 Node 应用程序或像 WebPack 这样的捆绑器中,他们只真正需要模块的名称,然后可以花一些额外的时间来发现保存代码的特定文件。在网络上,可能会浪费很多往返('library'
in library/index.js
,或 library/library.js
,或 library.js
?require()
不关心,但在网络上我们必须这样做)。
TypeScript 支持 ES6 模块(在 tsconfig.json
中设置 "module": "es6"
)但它似乎使用了文件发现方法...
假设我有 library.ts
:
export function myFunction(...) { ... }
然后在app.ts
:
import {myFunction} from './library';
var x = myFunction(...);
然而,这在转译时没有改变 - TS 输出仍然具有用于文件发现的 'library'
名称,这是行不通的。这会引发错误,因为未找到 'library'
:
<script type="module" src="app.js"></script>
为了让 ES6 模块工作,TS 输出需要引用特定文件:
import {myFunction} from './library.js';
var x = myFunction(...);
如何使 TS 输出有效的 ES6 模块 import
语句?
注意:我不是询问如何使捆绑器将 TS 输出加入单个文件。我特别想使用 <script type="module">
编译器采用模块类型标志:
--module ES2015
并且您还需要以 ECMAScript 6 / 2015 为目标...
--target ES2015
您需要模块类型和编译目标至少为 ECMAScript 2015 才能具有 "zero transformation imports"。
您的导入语句应该看起来介于两个示例之间:
import {myFunction} from './library';
补充说明
显然还有很多关于模块解析的讨论......有 TC39 specification, and the WHATWG specification - 加上 Node 目前仍然没有文件扩展......看起来 RequireJS 可能比我们所有人都活得更久想...请看:
The TypeScript thread for supporting file extensions during import transpilation(即它会添加文件扩展名吗?)。
推荐
坚持使用模块加载器,例如 RequireJS 或 SystemJS。这也意味着您的模块可以通过分别使用 UMD 或系统模块类型在浏览器和服务器之间共享。
显然,一旦 ECMAScript 讨论得出结论,就需要重新审视。
这是一个 bug in TypeScript,尽管关于是否应该修复它存在一些争论。
有一个解决方法:虽然 TS 不允许您将 .ts
文件指定为模块的源,但它会让您指定 .js
扩展名(然后忽略它).
所以在 app.ts
:
import {myFunction} from './library.js';
var x = myFunction(...);
然后在 app.js
中正确输出,并且 TS 已正确找到 import
定义和绑定。
这有一个 advantage/gotcha 是 aware/careful 的:TS 只是忽略 .js
扩展名并使用通常的文件发现加载路径的其余部分。这意味着它将导入 library.ts
,但它也会找到 library.d.ts
之类的定义文件或在 library/
文件夹中导入文件。
如果您将这些文件连接到一个 library.js
输出中,最后一种情况可能是可取的,但要做到这一点,您将要查看大量嵌套的 tsconfig.json
文件(凌乱)或者可能是另一个库的预编译输出。
对于个人项目,我采用了另一种方式。因为我让 NPM 调用 shell 脚本将 index.html 复制到 /build 文件夹,所以我有 shell 脚本,然后批量重命名所有 .js 文件,使其完全没有扩展名。
我确实必须在“MIME 类型”部分通知 IIS,对于该特定站点,无扩展名文件应该具有 MIME 类型 application/javascript,但它确实有效。没有 webpack,没有 SystemJS,什么都没有。 Index.html 刚刚硬编码
<script type="module">
import "./app";
</script>
这很重要,因为我使用的测试框架 jest
不喜欢我将 .js 放入打字稿导入语句中。