Node.js提示找不到模块但路径存在:自研npm包测试问题
问题
我正在开发一款基于TypeScript的npm包,创建了独立测试项目从npm下载该包测试。包通过主文件导入其他模块的类后统一导出,但测试项目运行时Node.js提示找不到实际存在的子模块。
代码片段
主文件(编译后的lib/index.js)
import { EventBus } from "./modules/eventbus/eventbus"; import { EventHandler } from "./modules/eventbus/eventhandler"; import { EventType } from "./modules/eventbus/eventtype"; import { Event } from "./modules/eventbus/event"; import { SemVer } from "./modules/semver"; export { SemVer, Event, EventBus, EventHandler, EventType };
错误信息
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/workspaces/epic-engine-testing/node_modules/epic-engine/lib/modules/eventbus/eventbus' imported from /workspaces/epic-engine-testing/node_modules/epic-engine/lib/index.js
测试文件
import { EventBus, EventHandler, EventType, Event } from "epic-engine"; class SomeType extends EventType { constructor() { super(); } } const eventbus = new EventBus(); const handler = new EventHandler<SomeType>(eventbus, "type", () => {}); eventbus.createHandler(handler); const event = new Event<SomeType>(eventbus, new SomeType(), "type");
包的package.json
{ "devDependencies": { "@tsconfig/esm": "^1.0.2", "@types/jest": "^29.2.3", "jest": "^29.3.1", "ts-jest": "^29.0.3", "tslint": "^6.1.3", "typescript": "^4.9.3" }, "name": "epic-engine", "description": "Pure TS engine developed by EpicPuppy613", "version": "0.1.0-dev.5", "main": "lib/index.js", "types": "lib/index.d.ts", "type": "module", "scripts": { "test": "jest --config jestconfig.json", "build": "tsc", "prepare": "npm run build", "lint": "tslint -p tsconfig.json", "prepublishOnly": "npm test && npm run lint", "preversion": "npm run lint", "version": "git add -A src", "postversion": "git push && git push --tags" }, "repository": { "type": "git", "url": "git+https://github.com/EpicPuppy613/epic-engine.git" }, "author": "EpicPuppy613", "license": "MIT", "bugs": { "url": "https://github.com/EpicPuppy613/epic-engine/issues" }, "homepage": "https://github.com/EpicPuppy613/epic-engine#readme", "files": [ "lib/**/*" ] }
已尝试添加.js后缀、使用绝对路径、修改tsconfig.json等操作仍未解决,想知道Node.js找不到子模块的原因,以及是否有更优的模块导出方式。
解决方案
核心原因
Node.js的ES模块系统要求导入路径必须包含完整文件扩展名(如.js),若TypeScript编译配置不当,不会自动为导入路径添加后缀;另外需确认编译后的子模块文件确实存在于lib/modules目录,且未被package.json的files字段排除。
具体修复步骤
配置TypeScript自动添加
.js后缀
修改tsconfig.json,确保关键配置项正确:{ "compilerOptions": { "module": "ESNext", "moduleResolution": "NodeNext", "target": "ES2020", "outDir": "./lib", "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "declaration": true }, "include": ["src/**/*"], "exclude": ["node_modules", "lib"] }其中
moduleResolution: "NodeNext"会让TypeScript遵循Node.js的ES模块规则处理导入路径,编译后自动补充.js后缀。验证编译后的文件结构
执行npm run build后,检查lib/modules目录下是否存在所有子模块的.js和.d.ts文件,比如lib/modules/eventbus/eventbus.js必须存在。手动补全导入路径后缀(配置未生效时)
在TypeScript源码的主文件中,直接为导入路径添加.js后缀(编译后会保留该后缀):// src/index.ts import { EventBus } from "./modules/eventbus/eventbus.js"; import { EventHandler } from "./modules/eventbus/eventhandler.js"; import { EventType } from "./modules/eventbus/eventtype.js"; import { Event } from "./modules/eventbus/event.js"; import { SemVer } from "./modules/semver.js"; export { SemVer, Event, EventBus, EventHandler, EventType };
更优的模块导出方式
子模块统一入口
在src/modules/eventbus目录下创建index.ts,统一导出该目录内的所有模块:// src/modules/eventbus/index.ts export { EventBus } from "./eventbus"; export { EventHandler } from "./eventhandler"; export { EventType } from "./eventtype"; export { Event } from "./event";主文件可简化导入逻辑:
// src/index.ts import * as EventBusModule from "./modules/eventbus/index.js"; import { SemVer } from "./modules/semver.js"; export { SemVer, ...EventBusModule };这种方式让模块结构更清晰,便于后续扩展维护。
使用
exports字段定义导出规则
在包的package.json中添加exports字段,明确模块导出路径,同时兼容CommonJS和ES模块:{ "exports": { ".": "./lib/index.js", "./eventbus": "./lib/modules/eventbus/index.js" } }用户不仅可以从包根导入,还能直接导入子模块:
import { EventBus } from "epic-engine/eventbus"。
内容的提问来源于stack exchange,提问作者EpicPuppy613

