无法运行纯ESM节点项目

问题描述 投票:0回答:1

我已经尝试了几天来运行一个纯ESM节点(express,graphql)项目,但尚未成功,缺乏有关纯ESM的信息,我放弃了

实际上我的下一个里程碑是让导入语句中的路径再次在项目中工作

我得到了什么:


    [nodemon] 2.0.16
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching path(s): src/**/*
    [nodemon] watching extensions: ts,html
    [nodemon] starting `./node_modules/.bin/ts-node ./src`
    /xxxxxxx/src/server.ts:1
    Error: Cannot find module '@routes/api'
    Require stack:
    - /xxxxxxx/src/server.ts
    - /xxxxxxx/src/index.ts
        at Object.<anonymous> (/xxxxxxx/src/server.ts:1) {
      code: 'MODULE_NOT_FOUND',
      requireStack: [
        '/xxxxxxx/src/server.ts',
        '/xxxxxxx/src/index.ts'
      ]
    }
    [nodemon] app crashed - waiting for file changes before starting...


我的package.json如下:


    {
      "name": "xxxxxxx",
      "version": "0.0.0",
      "scripts": {
        "build": "./node_modules/.bin/ts-node build.ts",
        "lint": "eslint . --ext .ts",
        "start": "node -r esm -r module-alias/register ./build --env=production",
        "start:dev": "nodemon",
        "test": "nodemon --config ./spec/nodemon.json",
        "test:no-reloading": "./node_modules/.bin/ts-node ./spec"
      },
      "nodemonConfig": {
        "watch": [
          "src"
        ],
        "ext": "ts, html",
        "ignore": [
          "src/public"
        ],
        "exec": "./node_modules/.bin/ts-node ./src"
      },
      "esm": {
        "await": true
      },
      "_moduleAliases": {
        "@services": "build/services",
        "@repos": "build/repos",
        "@entities": "build/entities",
        "@shared": "build/shared",
        "@server": "build/server",
        "@routes": "build/routes",
        "@graphql": "build/graphql"
      },
      "eslintConfig": {
        "parser": "@typescript-eslint/parser",
        "plugins": [
          "@typescript-eslint"
        ],
        "extends": [
          "eslint:recommended",
          "plugin:@typescript-eslint/recommended",
          "plugin:@typescript-eslint/recommended-requiring-type-checking"
        ],
        "parserOptions": {
          "project": "./tsconfig.json"
        },
        "rules": {
          "max-len": [
            "error",
            {
              "code": 100
            }
          ],
          "no-console": 1,
          "no-extra-boolean-cast": 0,
          "@typescript-eslint/restrict-plus-operands": 0,
          "@typescript-eslint/explicit-module-boundary-types": 0,
          "@typescript-eslint/no-explicit-any": 0,
          "@typescript-eslint/no-floating-promises": 0,
          "@typescript-eslint/no-unsafe-member-access": 0,
          "@typescript-eslint/no-unsafe-assignment": 0
        }
      },
      "eslintIgnore": [
        "src/public/",
        "build.ts"
      ],
      "dependencies": {
        "class-validator": "^0.13.2",
        "command-line-args": "^5.2.1",
        "cookie-parser": "^1.4.6",
        "dotenv": "^16.0.1",
        "esm": "^3.2.25",
        "express": "^4.18.1",
        "express-async-errors": "^3.1.1",
        "express-graphql": "^0.12.0",
        "graphql": "^15.3.0",
        "helmet": "^5.1.0",
        "http-status-codes": "^2.2.0",
        "jet-logger": "^1.1.5",
        "jsonfile": "^6.1.0",
        "module-alias": "^2.2.2",
        "morgan": "^1.10.0",
        "pg": "^8.7.3",
        "pg-hstore": "^2.3.4",
        "reflect-metadata": "^0.1.13",
        "sequelize": "^6.21.0",
        "type-graphql": "^1.1.1"
      },
      "devDependencies": {
        "@types/command-line-args": "^5.2.0",
        "@types/cookie-parser": "^1.4.3",
        "@types/express": "^4.17.13",
        "@types/find": "^0.2.1",
        "@types/fs-extra": "^9.0.13",
        "@types/jasmine": "^4.0.3",
        "@types/jsonfile": "^6.1.0",
        "@types/morgan": "^1.9.3",
        "@types/node": "^17.0.45",
        "@types/supertest": "^2.0.12",
        "@typescript-eslint/eslint-plugin": "^5.28.0",
        "@typescript-eslint/parser": "^5.28.0",
        "eslint": "^8.18.0",
        "find": "^0.3.0",
        "fs-extra": "^10.1.0",
        "jasmine": "^4.2.1",
        "nodemon": "^2.0.16",
        "sequelize-cli": "^6.4.1",
        "supertest": "^6.2.3",
        "ts-node": "^10.8.1",
        "tsconfig-paths": "^4.0.0",
        "typescript": "^4.7.4"
      }
    }


和我的 tsconfig.json:


    {
      "compilerOptions": {
        "target": "ES2022",                       
        "module": "ES2022",                       
        "strict": false,                           
        "moduleResolution": "node",              
        "baseUrl": "./",                          
        "allowSyntheticDefaultImports": true,  
        "experimentalDecorators": true,           
        "emitDecoratorMetadata": true,            
        "paths": {
          "@config/*":   [  "config/*"       ],
          "@repos/*":    [  "src/repos/*"    ],
          "@models/*":   [  "src/models/*"   ],
          "@shared/*":   [  "src/shared/*"   ],
          "@server":     [  "src/server"     ],
          "@services/*": [  "src/services/*" ],
          "@routes/*":   [  "src/routes/*"   ],
          "@graphql/*":  [  "src/graphql/*"  ]
        },
        "useUnknownInCatchVariables": false
      },
      "include": [
        "src/**/*.ts",
        "spec/**/*.ts"
      ],
      "exclude": [
        "src/public/",
        "node_modules"
      ],
      "ts-node": {
        "esm": true,
        "require": ["tsconfig-paths/register", "esm"]
      }
    }

我需要 ES2022 中的模块,因为我使用顶级等待,正如你所看到的,我正在 ts-node 配置中注册 esm 和 tsconfig-paths,但我不知道应该做什么才能使其最终运行,在问题是

"type": "module
之前,因为我无法让它在 ts-node 上使用 ES2022
 运行 
"esm": true

node.js typescript es6-modules ts-node top-level-await
1个回答
1
投票

检查您的转译器发出的代码。它不会是 ESM,它将用称为 Common-JS 的旧节点模块规范编写 (当作为首字母缩略词键入时,又称为

CJS

这是因为您分配给

./tsconfig.json
文件字段的值:
"moduleResolution"
,即值
"node"
。该设置并不意味着您想要支持 Node.js RTE,而是意味着您想要像经典 Node.js 模块一样解析模块。

引用关于这个主题的官方文档,很容易找到:

  • 'node'
    用于 Node.js CommonJS 实现
  • 'node12'
    'nodenext'
    从“TypeScript
    v4.5
    ”开始支持 Node.js 的 ECMAScript 模块

注意:这个文档有点落后。文档应该指出,对于那些坚持使用 LTS 版本的人来说,Node16(当前的 LTS 版本)也是可用的_(包括大多数在生产模式下运行的启动后应用程序)。

{
    "module": "ES2022", // this can be set to ES2020, ES2021, etc... Its all the same after ES2020
    "moduleResolution": "Node"
}

...做了两件事,它定义了您在创作项目时也将遵循的模块类型,以及将用于解析模块的规范。

这两个设置,

module
moduleResolution
都会影响我们的
TSC
编译器(或transpiler,这是一种特定类型的编译器)发出的转译输出。最近,人们似乎将
moduleResolution
与模块规范实现的语法联系在一起,然而,这并不是对“模块解析”的准确理解。然而,很容易理解为什么有些人可能认为“模块解析”(我具体谈论的是概念,而不是配置) 与语法有关。模块解析是模块在模块化系统中(显然,如果它不在模块化系统中,它就不是模块)使用的系统(或进程),用于定位和实现其他模块。简而言之,它是用于将许多模块连接在一起以形成更大系统的逻辑。语法是为每个不同的模块化系统定制的,因为语法的目标是最好地反映语法实现的机制。

不管怎样,我已经偏离主题了。重点是,您可以使用几种不同的配置来编译 ESM,但是,您使用的配置不是其中之一(当然我指的是您的

tsconfig.json
文件)。

看来您确实遇到了另一个问题。你不仅需要告诉 TypeScript,还需要告诉 Node,你计划如何解析模块。由于您想使用 ESM 规范,因此需要这样配置您的

package.json
文件。

要让节点知道您想要使用 ESM 规范来解析模块,请将以下内容添加到您的

package.json
文件中。

{
    "type": "module"
}

...您也可以使用

.mts
/
.mjs
文件扩展名,当节点找到该扩展名时,让节点知道您使用的文件将被解析为 ES 模块。

有两个链接您应该阅读,都可以进一步启发您。

第一个是“模块解析”上的 TSConfig 链接(配置和概念)。

第二个是如何使用 ECMAScript-Module 规范正确配置 Node.js 来解析模块,可以在 这里

找到
© www.soinside.com 2019 - 2024. All rights reserved.