在typescript编译器选项#module中,我们有一系列选项,包括nodenextesnext,其中nodenext是实验性的(截至目前).

为什么我们需要这个额外的nodenext选项,而esnext选项似乎已经在使用node.js?

或者换言之,nodenextesnext之间有什么区别?

推荐答案

module and moduleResolution

首先需要澄清的是modulemoduleResolution编译器选项的区别.前者是一个emit设置:tsc愿意向JS发送哪些与模块相关的代码?查看此选项效果的最简单方法是在设置commonjsesnext之间切换:

Input code Output --module commonjs Output --module esnext
import { createSourceFile } from "typescript" "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const typescript_1 = require("typescript"); import { createSourceFile } from "typescript"

虽然此设置基本上控制emits ,但它可以对允许的模块相关输入代码施加限制.例如,您不能以--module es2015以下import fs = require("fs")(或更高ES目标)的样式写入导入,因为ES模块系统中没有require.此外,仅在--module es2022(或更高)或system中允许使用顶级await,因为它需要模块加载系统中的相应支持.

另一方面,--moduleResolution是用来回答以下问题的算法:"给定一个文件系统和一些包含"lodash"导入的输入文件,我应该寻找哪些文件来找到该模块?"显然,查找具有神奇名称node_modules的文件夹的决定与Node有关(尽管为了方便起见,大量非Node工具已经复制了该文件夹),并且不会对每个可能的运行时都是正确的.

Differences in moduleResolution

在这样的背景下,我们准备开始直接回答您的问题.--module nodenext--module esnext之间最大、最明显的区别是前者意味着--moduleResolution nodenext,这是一种新的解析模式,专为 node 具体实现共存的ESM和CJ而设计,而后者does not imply a 104 setting because there is no such corresponding setting in TypeScript right now.换句话说,当你说你使用--module esnext时,你可以写,我们将发出,最新和最好的ES模块代码构造,但我们在决定导入如何解析时不会做任何不同的事情.您可能会继续使用--moduleResolution node,它是为Node实现CJS而设计的.这对你意味着什么?如果你正在为Node编写ESM,你可能会让一些东西在--module esnext--moduleResolution node上工作,但是像package.json exports这样更新的特定于Node的功能将不起作用,而且在编写导入路径时,你很容易就被击中了脚.tsc将根据 node 的CJS规则判断路径,但在运行时, node 将根据其ESM规则判断路径,因为您正在emits ESM.这些算法之间有显著的差异,尤其是后者需要相对导入来使用文件扩展名,而不是删除.js,而index文件没有特殊意义,因此不能仅通过命名目录路径来导入索引文件.

Differences in module

--module设置中观察到的差异本身就有点微妙.正如我之前提到的,在esnext中,你不能写import Foo = require("bar"),因为我们假设没有require.在nodenext中,我们知道给定模块可能是ES模块or,也可能是CJS模块,基于其文件扩展名(.mts)→ .mjs意味着ESM和.cts.cjs表示CJS)和/或最近包装中的type字段.json文件.--module nodenext支持查看这些内容,从而决定给定文件的模块类型,控制我们发出的模块输出类型.如果上述条件导致模块被解释为CJS,则该文件的输出几乎相同(可能相同?)你能从--module commonjs得到什么.如果模块被解释为ESM,那么输出与您从--module esnext获得的结果非常相似,但有一个例外,我可以从头回忆起:您仍然可以写入import Foo = require("bar"),并且编译为:

import { createRequire as _createRequire } from "module";
const __require = _createRequire(import.meta.url);
const Foo = __require("bar");

总结

我认为你问题的答案可以总结如下:

  • node 12+支持CJS和ESM并排运行,如软件包所示.json type和特殊的文件扩展名,所以我们需要一个理解这些内容的模块emits 模式.该模式大致可以被认为是现有commonjsesnext模式之间的基于 node 的 Select 器,并根据 node 定制了一些额外的小差异.
  • Node 12+还为包中的模块说明符如何解析带来了主要的新功能,并针对ESM导入实施了一种不同且更严格的解析算法.如果没有匹配的TypeScript解析模式,面对这些新功能,我们都无法解析,并且允许您编写won’t个ESM解析的路径.

Node.js相关问答推荐

使用OpenAI API时遇到问题

聚合操作不返回任何具有mongoose模式的内容

MongoDB的方面查询的Postgres类似功能

下一个API路由如何处理多个并发请求?

Webpack:如何避免导出函数的重命名?

Nestjs重写子类dto nodejs中的属性

使用 playwright 获取页面中同一 url 的所有响应

如何在 JavaScript 中显示多维数组中使用的一维数组的变量名?

连接到在线 redis 数据库时出错

无法截取页面截图

express cors request.body formData显示undefined

如何解决未调用 Express 错误处理程序的问题

使用 fs.createWriteStream 将数据写入 bigquery (node.js) 时出现模式错误

在 gatsby 中安装软件包时不推荐使用的错误

如何为一个网站实现这 2 个网址.即 www.administrator.sitename.com 和 www.sitename.com?

使用 node.js 执行一个 exe 文件

如何在 Mongoose 模式中设置数组大小限制

如何运行用 TypeScript 编写的 Mocha 测试?

使用 NodeJS 将新对象附加到 DynamoDB 中的 JSON 数组

node.js(ES6 / Babel)中 import X 和 import * as X 的区别?