[英]Unable to import ESM module in Nestjs
I am having a problem with importing ESM modules in my project based on Nest.js.我在基于 Nest.js 的项目中导入 ESM 模块时遇到问题。 As far as I understand, this problem is relevant not just to Nest.js but typescript as well.
据我了解,这个问题不仅与 Nest.js 相关,还与 typescript 相关。
I have tried various things and combinations of Node.js & typescript versions, adding "type":"module"
to package.json
& changes in the settings of my tsconfig.json
file, so it has the following view, which is far from default values:我尝试了 Node.js 和 typescript 版本的各种组合,将
"type":"module"
添加到package.json
并更改了我的tsconfig.json
文件的设置,因此它具有以下视图,与默认值相去甚远:
{
"compilerOptions": {
"lib": ["ES2020"],
"esModuleInterop": true,
"module": "NodeNext",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"moduleResolution": "Node",
"target": "esnext",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": false,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false,
}
}
My full environment is:我的完整环境是:
But it still gives me an error when I am trying to import any ESM module in any of my services.但是当我尝试在我的任何服务中导入任何 ESM 模块时,它仍然给我一个错误。 For example:
例如:
import random from `random`;
export class AppService implements OnApplicationBootstrap {
async test() {
const r = random.int(1, 5);
console.log(r);
}
}
Does anyone have a clue how to fix it?有谁知道如何解决它?
This Problem seems to occur more frequently since more packages are switching over to be distributed as ES module.这个问题似乎更频繁地发生,因为更多的包正在切换为作为 ES 模块分发。
Summary概括
There are two approaches for this problem.这个问题有两种方法。
import()
functionimport()
异步导入 package function The instruction to use import()
for ES modules in CommonJS can be found everywhere. CommonJS 中 ES 模块使用
import()
的说明随处可见。 But when using typescript the additional hint is missing how to prevent the compiler to transform the import()
call to a require()
.但是当使用 typescript 时,附加提示丢失了如何防止编译器将
import()
调用转换为require()
。 I found two options for this:我为此找到了两个选择:
moduleResolution
to nodenext
or node16
in your tsconfig.json
(Variant 1)tsconfig.json
(变体 1)中将nodenext
moduleResolution
node16
eval
workaround - this is based on the section "Solution 2: Workaround using eval" from answer https://stackoverflow.com/a/70546326/13839825 (Variant 2 & 3)eval
解决方法 - 这基于答案https://stackoverflow.com/a/70546326/13839825 (变体 2 和 3)中的“解决方案 2:使用 eval 的解决方法”部分await import()
whenever neededawait import()
This solution is also found frequently on the official NestJS Discord这个解决方案在 NestJS 官方Discord上也经常出现
"moduleResolution": "nodenext"
or "moduleResolution": "node16"
to your tsconfig.json
"moduleResolution": "nodenext"
或"moduleResolution": "node16"
添加到您的tsconfig.json
await import()
call when neededawait import()
调用async
contextasync
上下文import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
async getHello(): Promise<string> {
const random = (await import('random')).default;
return 'Hello World! ' + random.int(1, 10);
}
}
Note : Importing a type from a ES module will not result in an require
call, since it's only used by the typescript compiler and not the runtime environment.注意:从 ES 模块导入类型不会导致
require
调用,因为它仅由 typescript 编译器而不是运行时环境使用。
async
contextasync
上下文import { Injectable } from '@nestjs/common';
import { type Random } from 'random';
async function getRandom(): Promise<Random> {
const module = await (eval(`import('random')`) as Promise<any>);
return module.default;
}
@Injectable()
export class AppService {
async getHello(): Promise<string> {
return 'Hello World! ' + (await getRandom()).int(1, 10);
}
}
import { Injectable } from '@nestjs/common';
import { type Random } from 'random';
let random: Random;
eval(`import('random')`).then((module) => {
random = module.default;
});
@Injectable()
export class AppService {
async getHello(): Promise<string> {
return 'Hello World! ' + random.int(1, 10);
}
}
Although not supported, it seems possible to setup NestJS to compile to ESM.尽管不受支持,但似乎可以将 NestJS 设置为编译为 ESM。 This Guide has good general instructions to do this in a typescript project.
本指南有很好的一般说明,可以在 typescript 项目中执行此操作。
I tested it with NestJS and found these steps sufficient:我用 NestJS 测试了它,发现这些步骤足够了:
"type": "module"
to your package.json
"type": "module"
到你的package.json
module
to NodeNext
in your compilerOptions in tsconfig.json
NodeNext
的 compilerOptions 中将module
更改为tsconfig.json
.js
extension to all of your relative imports.js
扩展名添加到所有相关导入Now the import should work as expected现在导入应该按预期工作
import { Injectable } from '@nestjs/common';
import random from 'random';
@Injectable()
export class AppService {
async getHello(): Promise<string> {
return 'Hello World! ' + random.int(1, 10);
}
}
What did not work so far were the unit tests with jest.到目前为止没有用的是开玩笑的单元测试。 I got other import errors there and I bet there are more problems down the road.
我在那里遇到了其他导入错误,我敢打赌未来还会有更多问题。 I would avoid this approach and wait until NestJS officially supports ES modules.
我会避免这种方法,等到 NestJS 正式支持 ES 模块。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.