我已经尝试了几天来运行一个纯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
检查您的转译器发出的代码。它不会是 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 来解析模块,可以在 这里
找到