Nodejs、TypeScript、ts-node-dev 和顶级 await

Hei*_*itx 17 node.js async-await typescript top-level-await

在需要顶级等待之后,我现在花了一个小时寻找新错误的解决方案。到目前为止我尝试过的所有其他方法都没有解决错误,例如添加"type": "module"到 package.json 文件中。

错误消息是Cannot use import statement outside a module在启动服务时。如果我将更改恢复"module": "ESNext","module": "commonjs",,它工作正常(除了必须删除 await 关键字并以某种方式重构以在没有等待的情况下工作)。

另外,我使用 ts-node-dev 来运行服务,可以在 package.json 文件中看到。

  • 我需要的新包是 kafkajs。
  • 节点版本:v14.9.0
  • 打字稿版本:4.0

包.json

{
  "name": "",
  "version": "1.0.0",
  "description": "microservice",
  "main": "src/index.ts",
  "author": "",
  "type": "module",
  "license": "MIT",
  "scripts": {
    "dev": "NODE_ENV=development tsnd --respawn --files src/index.ts",
    "prod": "NODE_ENV=production tsnd --respawn --transpile-only --files src/index.ts",
    "test": "mocha --exit -r ts-node/register tests/**/*.spec.ts",
    "eslint": "eslint src/**/*.ts"
  },
Run Code Online (Sandbox Code Playgroud)

配置文件

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "node",
    "outDir": "dist",
    "sourceMap": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "ts-node": {
    "files": true,
    "transpileOnly": true
  },
  "include": ["src/**/*.ts", "declariations/**.d.ts"],
  "exclude": ["node_modules", ".vscode"]
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 37

TL;DR:不要将 ECMAScript 模块与 ts-node 或 ts-node-dev 一起使用(目前);只需重构顶级等待

今天我跌倒了同样的兔子洞,从无害的错误开始:

Top-level 'await' expressions are only allowed when the 'module' option is set to 'esnext' or 'system', and the 'target' option is set to 'es2017' or higher.
Run Code Online (Sandbox Code Playgroud)

结果,我倾向于编辑 mytsconfig.json并设置moduleesnext,这反过来又迫使我设置moduleResolutionnode并最终添加type: module到我的package.json. 我没有意识到(IMO 他们不应该在错误消息中提出这一点——你可以简单地重构顶级等待),这将 NodeJS 的模块解析策略从 CommonJS 切换到 ESM。这实际上是一个大问题,原因有很多:

我觉得此时(2020 年 12 月)NodeJS 生态系统仍在从经典的 CommonJS 模块过渡到新的 ECMAScript 模块。因此,其他技术,如 ts-node 或 ts-node-dev 也在过渡,支持可能不稳定。我的建议是坚持使用 CommonJS,直到尘埃落定并且这些东西“开箱即用”。

  • 我的回答基本上是“你不能”并解释为什么不可以。仅仅因为答案不是您所期望的,并不意味着它是一个糟糕的答案。 (25认同)
  • @zwol 确实如此。这是否可以接受取决于您的用例的具体情况。请注意,除非您实现强烈建议不要实现的繁忙等待,否则无法实际等待来自同步代码的异步代码。这就是为什么在 JavaScript 中你找不到类似“Promise.wait()”的东西,而在其他语言(如 Java)中可能会找到类似的东西。重点是“永远”不要阻塞主线程。 (2认同)

Ric*_*Dev 14

更新节点 v18.12.0

--watch您现在还可以使用Node.js 中的内置标志。

假设您的条目文件是src/index.ts

node --watch --loader ts-node/esm --experimental-specifier-resolution node src
Run Code Online (Sandbox Code Playgroud)

原答案

我知道,这个问题已经很老了,但是对于像我今天早些时候那样经过这个问题的人来说:

我刚刚设法让它发挥作用。不是直接用,而是用和ts-node-dev组合。nodemonts-node

你需要安装nodemon然后ts-node,假设你的入口文件是src/index.ts,你可以使用这个命令:

nodemon --ext ts --loader ts-node/esm --experimental-specifier-resolution node src
Run Code Online (Sandbox Code Playgroud)

(使用 Node v16.13.0 测试)

这是我弄清楚的关键帖子:https ://github.com/TypeStrong/ts-node/issues/1007

  • 我在没有nodemon的情况下使用它:“ts-node --esm --experimental-specifier-resolution node src/app.ts” (2认同)

小智 5

应该可以使用 ts-node 并具有顶级等待。

你能ts-node --esm {file}按照你的命令尝试一下吗?

我目前在此处的代码中使用顶级等待和 ts-node 。

我还将 tsconfig 目标设置为 ,es2022将 package.json 类型设置为module