多Node.js TypeScript项目共用外部Common目录并编译至各项目Dist目录的配置问题
嘿,我来帮你搞定这个共用TypeScript代码编译的问题!你之前用rootDirs没生效其实是因为对它的作用理解有点偏差——它主要是用来处理模块解析逻辑的,让TypeScript把多个目录当成同一个逻辑根目录来查找模块,但并不会自动把这些目录里的文件编译到你的应用dist目录里。咱们一步步来搞定这个需求:
方案一:调整TSConfig直接编译共用代码到应用dist(适合简单场景)
这个方案让TypeScript把common目录和应用自身的src目录都当成源文件,编译后按目录结构输出到dist里。假设你的项目结构是这样的:
your-project/ common/ utils.ts types.ts apps/ app1/ src/ index.ts tsconfig.json app2/ ... app3/ ...
每个应用的tsconfig.json配置
修改app1/tsconfig.json,重点调整include、rootDir和paths:
{ "compilerOptions": { "target": "ES2020", // 根据你的Node.js版本调整 "module": "commonjs", "outDir": "./dist", "rootDir": "../../", // 把项目根目录(your-project)设为所有源文件的根目录 "baseUrl": ".", "paths": { "@common/*": ["../../common/*"] // 设置别名,方便代码里导入共用模块 }, "strict": true, "esModuleInterop": true }, "include": [ "./src/**/*", // 包含应用自身代码 "../../common/**/*" // 包含共用代码 ], "exclude": [ "node_modules", "./dist", "../app2/dist", "../app3/dist" ] }
为什么这样有效?
include告诉TypeScript要编译common和src下的所有TS文件rootDir指定了所有源文件的共同根目录,这样编译后common的文件会输出到dist/common/,应用自身代码输出到dist/src/,结构和源码一致paths别名让你在代码里用import { formatDate } from '@common/utils'代替冗长的相对路径,更易维护
方案二:使用TypeScript Project References(推荐大型项目)
如果你的项目规模较大,或者希望共用代码只编译一次、多个应用复用编译产物,这个方案更合适。我们把common当成一个独立的TS项目,每个应用通过项目引用依赖它。
步骤1:配置common目录的tsconfig.json
在common/tsconfig.json里开启composite模式(允许被其他项目引用):
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "outDir": "./dist", // 共用代码编译到自己的dist目录 "rootDir": "./", "strict": true, "esModuleInterop": true, "declaration": true, // 生成类型声明文件,方便应用里的类型提示 "composite": true // 标记为可引用的复合项目 }, "include": ["**/*"], "exclude": ["node_modules", "dist"] }
步骤2:配置每个应用的tsconfig.json
修改app1/tsconfig.json,添加项目引用并指向common的编译产物:
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "outDir": "./dist", "rootDir": "./src", "baseUrl": ".", "paths": { "@common/*": ["../../common/dist/*"] // 引用common编译后的JS文件和类型声明 }, "strict": true, "esModuleInterop": true }, "include": ["./src/**/*"], "exclude": ["node_modules", "./dist"], "references": [{"path": "../../common"}] // 声明依赖common项目 }
编译方式
使用tsc --build命令编译,它会自动先编译common目录的代码,再编译应用代码:
cd apps/app1 tsc --build
这种方式的好处是共用代码只需要编译一次,应用编译时直接复用产物,节省时间,也更符合模块化的项目结构。
为什么之前的rootDirs没生效?
再补充下:rootDirs的作用是让TypeScript在模块解析阶段把多个目录视为同一个逻辑根目录,比如你在app1/src/index.ts里可以直接import { utils } from 'common/utils'(不用相对路径),但它不会改变TypeScript的编译输出路径规则——如果没把common加入include,TS根本不会去编译这些文件,自然不会出现在dist里。
内容的提问来源于stack exchange,提问作者Itay.B

