您可能不需要 TypeScript 项目引用
如果您曾在大型 TypeScript 代码库或 monorepo 中工作过,您可能熟悉项目引用。它们确实相当强大。
当您在 tsconfig.json 中引用一个项目时,会发生一些新事情
- 从引用的项目导入模块将转而加载其输出声明文件(
.d.ts) - 如果引用的项目生成一个
outFile,则输出文件.d.ts文件的声明将在此项目中可见 - 运行构建模式(
tsc -b)将自动构建引用的项目,如果它尚未构建但需要的话 - 通过分成多个项目,您可以大大提高类型检查和编译的速度,减少在使用编辑器时的内存使用,并更好地强制执行程序的逻辑分组。
听起来很棒!对吗?!嗯……也许吧。一旦您向项目添加引用,每当您添加或删除包时,您现在都需要不断更新它们。这有点糟糕。
嗯……如果您不需要呢?
“内部”TypeScript 包
事实证明,您甚至可能不需要引用,甚至不需要临时 TypeScript 构建步骤,通过我即将向您展示的一种模式,我称之为“内部包”。
“内部包”是一个没有 tsconfig.json 的 TypeScript 包,其 package.json 中的 types 和 main 字段都指向包的未转译入口点(例如 ./src/index.tsx)。
事实证明,TypeScript 语言服务器(在 VSCode 中)和类型检查器可以将原始的 .ts 或 .tsx 文件视为其自身有效的类型声明。一旦您读两遍,最后一句话就很明显了。然而,不那么明显的是,您可以将 types 字段直接指向原始源代码。
一旦您这样做,只要您遵守 2 条规则,此包就可以在没有项目引用或 TypeScript 构建步骤(无论是通过 tsc 还是 esbuild 等)的情况下使用
- 使用内部包的应用程序必须对其进行转译和类型检查。
- 您不应将内部包发布到 npm。
据我所知,这种内部包模式适用于所有 yarn/npm/pnpm workspace 实现,无论您是否使用 Turborepo 或其他工具。我个人已经使用几种不同的元框架测试了这种模式(见下文),但我确信它也适用于其他框架。
Next.js
Next.js 13 可以自动转译和打包来自本地包(如 monorepo)或外部依赖项(node_modules)的依赖项。
从 Next.js 13.1 开始,您不再需要 next-transpile-modules 包。欲了解更多信息,请访问 Next.js 内置模块转译 博客文章。
Vite
内部包可以直接工作。无需额外配置。
React Native
如果您使用 Expo 并使用 expo-yarn-workspaces 或 @turborepo/adapter-expo 包,只要您面向 iOS 或 Android,就可以使用内部包。当您为这些平台运行 Expo 时,所有 node_modules 都会自动通过 Metro 进行转译。但是,如果您面向 Expo for web,内部包将不起作用,因为 node_modules 在 web 上奇怪地没有转译。
我向 Expo 团队反映了这种不一致。他们知道这一点。有人告诉我,这是一个遗留问题。
这种模式的优点
这种模式很棒,因为它节省了您不必要的或重复的构建步骤。它还为您提供了项目引用的所有编辑器优点,但无需任何配置。
注意事项
当您使用内部包时,这有点像告诉使用该包的应用程序您有另一个源目录——这有利有弊。随着您的使用应用程序的增长,添加更多内部包与向该使用应用程序添加更多源代码相同。因此,当您添加更多源代码时,需要转译/打包/类型检查的代码就越多……这可能会导致使用应用程序的构建速度变慢(因为工作量更大),但总体构建时间可能会更快(且更简单)。当/如果总体构建时间开始受到影响时,您可能决定将较大的内部包转换回带有 .d.ts 文件和正常 TypeScript 构建步骤的“常规”包。
如前所述,这种模式实际上与 Turborepo 关系不大。它只是超级棒,我认为您应该了解它。由于我们正在积极开发 Turborepo 的预设包构建规则(即“构建器”),我们将使用内部包模式来跳过构建步骤。
说到漫长的构建时间……
在这里插播一条广告。如果您正在阅读此帖子,并且您正在为缓慢的构建和测试时间而烦恼,我很乐意向您展示 Turborepo 如何提供帮助。我保证 Turborepo 会将您的 monorepo 的构建时间缩短 50% 或更多。您可以在这里请求实时演示。