TypeScript 隔离声明:提升 Monorepo 构建速度
Monorepo 的构建速度经常会因为 TypeScript 处理声明文件的方式而变慢。默认情况下,TypeScript 在创建单个 .d.ts 文件之前,会分析每一个导入链。这导致了一个漫长的等待队列,各个包必须互相等待。
你可以通过 --isolatedDeclarations 标志来解决这个问题。
该标志允许并行构建。每个包不再需要等待依赖项,而是独立生成自己的声明。团队可以实现 3 到 15 倍的构建速度提升。
问题所在: TypeScript 通常会在模块边界之间进行类型推断。如果包 A 依赖于包 B,编译器必须在开始处理 A 之前完全解析 B。在大型 monorepo 中,当编译器逐个处理时,大多数包都处于闲置状态。
解决方案:
--isolatedDeclarations 标志改变了规则。它要求你为你导出的所有内容编写显式的类型注解。
折衷方案: 你的代码量会增加。你必须手动为函数添加返回类型,并为常量添加类型。你不能再依赖编译器从代码中猜测这些类型。
结果: 由于每个导出项都有明确的类型,编译器无需查看其他包即可理解它们。它可以同时处理每一个包。
实际效果:
- 一个拥有 18 个包的 monorepo,构建时间从 47 秒降至 3.2 秒。
- 一个拥有 32 个包的 monorepo,在 CI 流水线上的速度提升了 8 倍。
- 性能随 CPU 核心数扩展。核心越多,意味着可以同时构建更多的包。
如何迁移:
- 在根目录的
tsconfig.json和每个包的配置中启用该标志。 - 使用
"composite"标志以允许项目引用(project references)。 - 为导出的函数添加显式的返回类型:
// 之前 export function add(a: number, b: number) { return a + b; }
// 之后 export function add(a: number, b: number): number { return a + b; }
- 为导出的常量添加显式类型:
// 之前 export const SETTINGS = { port: 3000 };
// 之后 export const SETTINGS: { port: number } = { port: 3000 };
如果你不添加这些类型,编译器将会报错。这确保了你的类型是确定性的且高效的。
