TypeScript中baseUrl配置无效,Node运行时模块找不到报错
短路径导入模块后Node运行报错问题
为了避免冗长的相对路径导入(比如import x from '../../../../../../../lib/tool'),我想用短路径(比如import x from 'lib/tool')导入模块,于是在tsconfig.json里做了如下配置:
{ "compilerOptions": { "target": "es2016", "module": "ESNext", "rootDir": "./src", "moduleResolution": "node16", "baseUrl": "./src", "declaration": true, "declarationMap": true, "declarationDir": "./@types", "outDir": "./dist", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true }, "exclude": ["./@types", "node_modules"], "include": ["./src"] }
我的目录结构如下:
. ├── dist │ ├── index.js │ └── tools │ └── test.js ├── package.json ├── package-lock.json ├── src │ ├── index.ts │ └── tools │ └── test.ts ├── tsconfig.json └── @types ├── index.d.ts ├── index.d.ts.map └── tools ├── test.d.ts └── test.d.ts.map
执行npx tsc -w编译时,输出正常:
[11:36:32 AM] Starting compilation in watch mode... [11:36:32 AM] Found 0 errors. Watching for file changes.
但运行node ./dist/index.js时出现报错:
node:internal/modules/cjs/loader:1078 throw err; ^ Error: Cannot find module '/home/xam/Desktop/test/src/dist/index.js' at Module._resolveFilename (node:internal/modules/cjs/loader:1075:15) at Module._load (node:internal/modules/cjs/loader:920:27) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) at node:internal/main/run_main_module:23:47 { code: 'MODULE_NOT_FOUND', requireStack: [] } Node.js v18.15.0
编译后的./dist/index.js代码为:
import { testMe } from "tools/test"; testMe();
问题原因
TypeScript的baseUrl配置只服务于TS编译阶段的路径解析,编译后的JS代码不会自动转换短路径。Node运行时会把tools/test当成第三方模块,去node_modules里查找,自然找不到我们自己写的模块。
解决方法
方法一:用tsc-alias转换路径
这是最直接的方案,它能自动把编译后JS里的短路径转换成相对路径:
- 安装依赖:
npm install tsc-alias --save-dev
- 修改
package.json的脚本:
{ "scripts": { "build": "tsc && tsc-alias", "watch": "tsc -w & tsc-alias -w" } }
- 重新编译后,
dist/index.js里的代码会变成:
import { testMe } from "./tools/test"; testMe();
此时再运行node ./dist/index.js就不会报错了。
方法二:用Node的路径映射(适合Node 12+)
在package.json里添加exports字段,指定模块的解析路径:
{ "exports": { "./tools/*": "./dist/tools/*.js" } }
不过这种方式更适合发布npm包时使用,项目内部导入还是用tsc-alias更方便。
内容的提问来源于stack exchange,提问作者Islam Y-
相关产品推荐
相关产品推荐

