Waj*_*ath 68 node.js typescript
在打字稿编译器选项#module中,我们有很多选项,包括nodenext和esnext,其中nodenext是实验性的(截至目前)。
为什么我们需要这个额外的nodenext选项,而这个esnext选项似乎已经可以与 Node.js 一起使用了?
或者换句话说,nodenext和之间有什么区别esnext?
来源:https ://github.com/microsoft/TypeScript/issues/46452#issuecomment-1066771513
And*_*rew 140
module和moduleResolution首先需要澄清的是编译器选项module和moduleResolution编译器选项的区别。前者是一个emit设置:tsc愿意向JS发送哪些模块相关的代码?查看此选项效果的最简单方法是在设置commonjs和之间切换esnext:
| 输入代码 | 输出--module commonjs | 输出--module esnext |
|---|---|---|
import { createSourceFile } from "typescript" | "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const typescript_1 = require("typescript"); | import { createSourceFile } from "typescript" |
虽然此设置从根本上控制发出,但它可以对允许的模块相关输入代码施加限制。例如,您不能以import fs = require("fs")under --module es2015(或更高 ES 目标)的风格编写导入,因为 ES 模块系统中没有require可言的。await另外,只有在--module es2022(或更高级别)中才允许使用顶级,或者system因为它需要模块加载系统中的相应支持。
另一方面,--moduleResolution都是关于用于回答问题 \xe2\x80\x9c 的算法给定一个文件系统和一些包含导入的输入文件"lodash",我应该查找哪些文件来查找该模块?\xe2\x80\x9d显然,查看具有神奇名称的文件夹的决定node_modules与 Node 相关(尽管为了方便起见,已经复制了大量非 Node 工具),并且对于每个可能的运行时来说并不都是正确的。
moduleResolution在此背景下,我们\xe2\x80\x99准备好开始直接回答您的问题。--module nodenext和之间最大、最明显的区别--module esnext是,前者暗示了--moduleResolution nodenext一种新的解析模式,专为 Node\xe2\x80\x99s 共存 ESM 和 CJS 的特定实现而设计,而后者并不暗示一种moduleResolution设置,因为没有这样的设置现在在 TypeScript 中进行相应的设置。换句话说,当你说你\xe2\x80\x99正在使用 时--module esnext,你\xe2\x80\x99就被允许编写,并且我们将发出最新和最好的ES模块代码结构,但我们不会做任何不同的事情来决定进口如何解决。您\xe2\x80\x99可能会继续使用--moduleResolution node,它是为 CJS 的 Node\xe2\x80\x99s 实现而设计的。这对你来说意味着什么?如果您\xe2\x80\x99正在为Node编写ESM,您可能可以使一些东西与--module esnext和 一起使用--moduleResolution node,但是较新的Node特定功能(例如package.json导出)将\xe2\x80\x99无法工作,并且将非常容易编写导入路径时搬起石头砸自己的脚。路径将由 tsc 在 Node\xe2\x80\x99s CJS 规则下评估,但在运行时,Node 将在其 ESM 规则下评估它们,因为你\xe2\x80\x99 正在发出 ESM。这些算法之间存在显着差异\xe2\x80\x94值得注意的是,后者需要相对导入以使用文件扩展名而不是删除.js,并且index文件没有特殊含义,因此您可以\xe2\x80\x99t仅通过以下方式导入索引文件命名目录的路径。
module环境本身的差异--module更为微妙。正如我之前提到的,在esnextyou are\xe2\x80\x99t 中不允许写入,import Foo = require("bar")因为我们假设没有require. 在 中nodenext,我们知道给定的模块可能是 ES 模块,也可能是 CJS 模块,基于其文件扩展名(.mts\xe2\x86\x92.mjs意味着 ESM,.cts\xe2\x86\x92.cjs意味着 CJS)和/或type字段在最近的 package.json 文件中。--module nodenext允许查看这些内容来决定给定文件是什么类型的模块,它控制我们发出什么类型的模块输出。如果上述条件导致模块被解释为 CJS,则该文件的输出几乎与您\xe2\x80\x99d 从--module commonjs. 如果该模块被解释为 ESM,则输出与 you\xe2\x80\x99d 获得的输出非常相似--module esnext,但有一个例外我可以立即回想起: you\xe2\x80\x99re 仍然允许写入import Foo = require("bar"),并被编译为:
import { createRequire as _createRequire } from "module";\nconst __require = _createRequire(import.meta.url);\nconst Foo = __require("bar");\nRun Code Online (Sandbox Code Playgroud)\n我认为你的问题的答案可以概括如下:
\ntype和特殊文件扩展名指示,因此我们需要一个能够理解这些内容的模块发出模式。该模式可以大致被认为是现有模式commonjs和esnext模式之间基于 Node 的选择器,还有一些针对 Node 定制的额外的小差异。