NestJS导入p-retry遇ERR_REQUIRE_ESM错误,求非动态导入方案
解决p-retry在NestJS v9中出现的ERR_REQUIRE_ESM错误
问题根源
p-retry从v5版本开始完全切换为ESM模块,而你的NestJS项目默认编译输出为CommonJS,静态import语句会被TypeScript转译为require(),触发Node.js的ESM/CommonJS互操作错误。动态导入仍报错大概率是因为项目未正确配置ESM支持,或者在非异步上下文使用了await。
配置修复方案(无需动态导入)
方案1:将项目切换为ESM输出
这是最彻底的解决方式,适配Node.js 20的ESM特性:
- 修改项目根目录
package.json,添加:"type": "module" - 更新
tsconfig.json核心配置:{ "compilerOptions": { "module": "ESNext", "moduleResolution": "NodeNext", "target": "ES2020", "outDir": "./dist", "esModuleInterop": true, "allowSyntheticDefaultImports": true, "types": ["node"] }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] } - 修改
nest-cli.json,确保编译器使用新的tsconfig:{ "$schema": "https://json.schemastore.org/nest-cli", "collection": "@nestjs/schematics", "sourceRoot": "src", "compilerOptions": { "deleteOutDir": true, "tsConfigPath": "./tsconfig.json" } } - 启动脚本更新:将
start:prod改为node dist/main.js(无需ts-node,因为已编译为ESM)
方案2:在CommonJS项目中兼容ESM模块
如果不想全项目转ESM,可以通过TypeScript配置强制处理ESM包:
- 确保
tsconfig.json中开启:{ "compilerOptions": { "esModuleInterop": true, "allowSyntheticDefaultImports": true, "moduleResolution": "Node16" } } - 使用命名导入替代默认导入:
(注:部分版本的p-retry可能需要调整为import { pRetry } from 'p-retry';import * as pRetry from 'p-retry',需结合类型定义验证)
动态导入报错的额外排查点
如果尝试动态导入仍报错,检查:
- 是否在非异步函数中使用了
await,需确保代码在async上下文执行 - 确认NestJS的模块提供者/守卫等生命周期钩子中,不要在同步初始化逻辑中调用异步导入的模块
替代npm包推荐
如果不想调整配置,这些重试库同时支持CommonJS和ESM:
- retry:老牌通用重试库,支持回调和Promise封装,API简洁
- async-retry:专门为Promise设计的重试工具,内置指数退避等策略
- promise-retry:轻量级Promise重试封装,无多余依赖
内容的提问来源于stack exchange,提问作者BumbleBee
相关产品推荐
相关产品推荐

