TypeScript Monorepo构建时出现MODULE_NOT_FOUND错误求助
问题
开发时用nodemon + ts-node运行TypeScript Monorepo(包含API和通用代码包)完全正常,但构建后启动API时出现模块找不到错误:
Error: Cannot find module '@cas/common/src/Errors' Require stack: - mono-test\@app\api\build\src\config.js - mono-test\@app\api\build\src\index.js at Module._resolveFilename (node:internal/modules/cjs/loader:1077:15) at Module._load (node:internal/modules/cjs/loader:922:27) at Module.require (node:internal/modules/cjs/loader:1143:19) at require (node:internal/modules/cjs/helpers:119:18) at Object.<anonymous> (mono-test\@app\api\build\src\config.js:7:34) at Module._compile (node:internal/modules/cjs/loader:1256:14) at Module._extensions..js (node:internal/modules/cjs/loader:1310:10) at Module.load (node:internal/modules/cjs/loader:1119:32) at Module._load (node:internal/modules/cjs/loader:960:12) at Module.require (node:internal/modules/cjs/loader:1143:19) { code: 'MODULE_NOT_FOUND', requireStack: [ 'mono-test\\@app\\api\\build\\src\\config.js', 'mono-test\\@app\\api\\build\\src\\index.js' ] }
文件夹结构
@app - api - build - src - index.ts - ... - package.json - tsconfig.json packages - common - build - src - Errors.ts // 无index.ts文件 - .gitignore - package.json - tsconfig.json
根目录tsconfig.json
{ "compilerOptions": { "composite": true, "strict": true, "module": "commonjs", "target": "es6", "moduleResolution": "Node", "esModuleInterop": true }, "references": [ { "path": "./@app/api" }, { "path": "./packages/common" } ] }
API包配置
package.json
{ "name": "@user/api", "version": "1.0.0", "main": "build/index.js", "types": "build/index.d.ts", "scripts": { "start": "node build/src/index.js", "build": "tsc", "dev": "nodemon --exec ts-node src/index.ts" }, "dependencies": { "@cas/common": "^1.0.0", "body-parser": "^1.20.2", "express": "^4.18.2" }, "devDependencies": { "@types/express": "^4.17.21", "nodemon": "^3.0.2" } }
tsconfig.json
{ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "./build", "baseUrl": "./src", "composite": true, "strict": true, "module": "commonjs", "target": "es6", "moduleResolution": "node", "esModuleInterop": true }, "references": [ { "path": "../../packages/common" } ] }
Common包配置
package.json
{ "name": "@cas/common", "version": "1.0.0", "main": "index.js", "license": "MIT", "scripts": { "build": "tsc" }, "dependencies": {}, "devDependencies": {} }
tsconfig.json
{ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "./build", "composite": true, "baseUrl": "./src" } }
已确认先构建common包再构建api包,且api包已执行npm install,但错误仍存在。
解决方法
1. 修复Common包的package.json配置
Common包的main字段指向不存在的index.js,且未配置构建后文件的导出规则,导致Node无法找到正确的模块路径。
修改packages/common/package.json:
- 方式一(仅导出Errors模块):
"main": "build/src/Errors.js", "types": "build/src/Errors.d.ts" - 方式二(支持多模块导出,更灵活):
"exports": { "./src/Errors": "./build/src/Errors.js", "./src/Errors.d.ts": "./build/src/Errors.d.ts" }, "typesVersions": { "*": { "src/Errors": ["build/src/Errors.d.ts"] } }
2. 配置Monorepo Workspaces(关键)
根目录未配置workspaces,导致npm install时可能安装了远程的@cas/common包,而非本地包。在根目录package.json中添加:
"workspaces": [ "@app/*", "packages/*" ]
然后在根目录执行npm install,确保本地包被正确链接到api的node_modules中。
3. 调整API中的导入路径(可选,更规范)
如果使用方式二的exports配置,API中的导入语句可以保持import { ... } from '@cas/common/src/Errors';如果用方式一,建议改为直接导入包:
import { ... } from '@cas/common'
同时在Common包的src目录添加index.ts,导出Errors模块:
export * from './Errors';
并同步修改Common包的package.json:
"main": "build/index.js", "types": "build/index.d.ts"
4. 清理旧构建文件并重新构建
删除旧的build目录,按顺序重新构建:
# 清理构建文件 rm -rf packages/common/build @app/api/build # 构建Common包 cd packages/common && npm run build # 构建API包 cd ../../@app/api && npm run build
5. 可选:添加TypeScript路径映射(优化开发体验)
在API的tsconfig.json中添加paths字段,确保开发时路径解析正确:
"compilerOptions": { // ...其他配置 "paths": { "@cas/common/*": ["../../packages/common/src/*"] } }
注意:构建后Node不识别paths,所以必须配合Common包的package.json导出配置使用,或使用tsconfig-paths工具在启动时解析路径(在API的start脚本中添加:tsconfig-paths/register):
"scripts": { "start": "node -r tsconfig-paths/register build/src/index.js" }
内容的提问来源于stack exchange,提问作者jp j

