未指定.js后缀触发ERR_MODULE_NOT_FOUND问题求助(ESM环境)
问题:ESM项目导入子模块需手动添加.js后缀否则运行报错
已配置"type: module"的ESM项目中,导入子文件夹内的模块时,若不指定.js后缀会触发ERR_MODULE_NOT_FOUND错误。该问题仅在运行时出现,编译阶段无异常;添加.js后缀后即可正常运行,且此情况在我的库项目中不存在。
错误信息
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/me/code/means-of-production/server-new/dist/resolvers/libraries' imported from /home/me/code/means-of-production/server-new/dist/index.js at new NodeError (node:internal/errors:399:5) at finalizeResolution (node:internal/modules/esm/resolve:231:11) at moduleResolve (node:internal/modules/esm/resolve:850:10) at defaultResolve (node:internal/modules/esm/resolve:1058:11) at nextResolve (node:internal/modules/esm/loader:164:28) at ESMLoader.resolve (node:internal/modules/esm/loader:838:30) at ESMLoader.getModuleJob (node:internal/modules/esm/loader:419:18) at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:77:40) at link (node:internal/modules/esm/module_job:76:36) { code: 'ERR_MODULE_NOT_FOUND' } Node.js v19.4.0 Process finished with exit code 1
package.json配置
{ "name": "server-new", "type": "module", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "compile": "tsc", "start": "npm run compile && node ./dist/index.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "@apollo/server": "^4.3.0", "@meansofproduction/domain": "^4.0.0", "graphql": "^16.6.0" }, "devDependencies": { "@types/node": "^18.11.18", "typescript": "^4.9.4" } }
tsconfig.json配置
{ "compilerOptions": { "rootDirs": ["src"], "outDir": "dist", "lib": ["es2020"], "target": "esnext", "module": "esnext", "moduleResolution": "node", "esModuleInterop": true, "types": ["node"], "sourceMap": true, "sourceRoot": "src" } }
失败的导入代码
import { ApolloServer } from '@apollo/server'; import { startStandaloneServer } from '@apollo/server/standalone'; import {allLibraries} from "./resolvers/libraries"; import * as fs from "fs"; const typeDefs = fs.readFileSync('schema.graphql').toString()
可正常运行的导入代码
import { ApolloServer } from '@apollo/server'; import { startStandaloneServer } from '@apollo/server/standalone'; import {allLibraries} from "./resolvers/libraries.js"; import * as fs from "fs"; const typeDefs = fs.readFileSync('schema.graphql').toString()
解决方法
1. 理解核心原因
Node.js的ESM模块解析必须指定完整文件后缀(如.js、.mjs),它不会像CommonJS那样自动补全后缀。你当前的TypeScript配置未让编译后的代码自动补充后缀,导致运行时Node.js找不到对应文件——dist目录下实际是libraries.js,但编译后的导入路径是./resolvers/libraries,缺少后缀。
2. 修改TypeScript配置
更新tsconfig.json的compilerOptions,让TypeScript编译时自动添加正确后缀:
{ "compilerOptions": { "rootDirs": ["src"], "outDir": "dist", "lib": ["es2020"], "target": "es2020", "module": "nodenext", "moduleResolution": "nodenext", // 关键:启用Node.js ESM的解析逻辑 "esModuleInterop": true, "types": ["node"], "sourceMap": true, "sourceRoot": "src", "resolveJsonModule": true // 可选,若需导入JSON文件 } }
修改后重新编译,TypeScript会自动给导入路径添加.js后缀,无需手动在TS代码中添加。
3. 其他临时方案
- 开发阶段可改用
tsx或ts-node-esm运行TS代码,它们能处理无后缀的ESM导入,但生产环境仍需依赖编译后的正确文件。 - 检查库项目配置差异:确认库项目是否启用了
nodenext解析规则,或使用了Rollup、Webpack等打包工具自动处理后缀。
内容的提问来源于stack exchange,提问作者Mathieson
相关产品推荐
相关产品推荐

