转发:TypeScript Monorepo 最佳实践
当我们跨多个代码仓库管理多个项目之间的依赖关系时,既耗时又容易出错。
monorepo 是一种处理上述问题的代码管理架构概念,它将多个项目的所有隔离代码库整合到一个大型存储库中,而不是单独管理它们。当与合适的工具一起使用时,Monorepos 很有优势。因此许多组织采用了在单个存储库中维护多个项目的策略。
Google、Meta 和 Microsoft 等大公司通常在单个 monorepo 中管理组织内多个项目的代码库。这种方法使他们能够在项目之间共享依赖项、库、组件、实用程序、文档等。在项目之间共享代码可确保代码库的一致性和可预测性。然而,依赖管理才是 monorepo 真正的优势所在。如果有人对共享库进行重大的更新,所有受影响的库将会立刻收到这个更新。
尽管 monorepo 有自己的一系列挑战,但它也通过正确的工具解决了这些挑战。其中一个工具是 Typescript,在这篇文章中,我们将研究管理 Typescript monorepo 的最佳实践。
使用 TypeScript Project References
TypeScript Project References 的主要目标始终是帮助解决大型 TypeScript 项目(如 monorepo)中编译时间长的问题。它们可以将一个巨大的项目划分为几个较小的模块,这些模块都可以独立构建。此外,它还可以创建更模块化的代码。使用这种方法,可以大大缩短构建时间,可以在逻辑上分离组件,并且可以以更有条理和逻辑的方式重新组织你的代码。
这是 TypeScript Project References 的文档。
管理依赖于其他包的包
在处理依赖于 Typescript monorepo 中另一个包的多个包时,你必须明确让 Typescript 知道这种依赖关系。例如, @projectName /package-A 依赖于 @projectName /package-B。我们需要添加以下配置,让 Typescrip 知道这个依赖。
首先,你必须在 package-b 的 tsconfig 中添加它。
// packages/package-b/tsconfig.json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"composite": true
},
"include": ["./src"]
}
}
复制代码
下一步是在 package-a 中引用包。
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "dist",
}
},
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["dist/*"],
"references": [{ "path": "../package-b/tsconfig.json" }]
}
复制代码
设置工作区
工作空间是在 yarn、NPM 和其他工具中发明的一个概念,可用于以有组织且一致的文件夹结构的形式为 monorepo 存储库中的包和应用程序提供自己的工作空间。monorepos 等大型项目可以从用于管理包和依赖项的工作区中受益。
在 Yarn 工作区中,可以创建项目,例如:
packages/
localPackageA/
package.json
...
localPackageB/
package.json
...
复制代码
使用 Yarn Workspaces,跨工作区安装包变得更快、更轻。此外,它可以防止跨工作区的包重复,还可以在相互依赖的目录之间创建链接,确保所有目录在 monorepo 中都是一致的。
你可以在 yarn 工作区、npm 工作区或 pnpm 工作区之间进行选择。
使用绝对路径导入模块
导入模块时最好使用绝对路径而不是长的相对路径。这对于代码的清晰很重要,因为随着代码库变得越来越大,会有更深的嵌套文件夹和文件,使用它们的相对路径导入它们是在代码库中弄乱的最快方法之一,因为这会使代码混乱且难以阅读。
我们看一下下面的例子。
import { FormType } from '../../../../types/form';
import { DateType } from '../../../../types/date';
复制代码
在这种导入的写法中,任何一个开发人员都会发现很难确切知道这些模块是从哪个文件夹中被导入的。
所以最好使用绝对路径。
我们再看一下比上面更好的一个例子:
import { FormType } from 'utils/types/form';
import { DateType } from 'utils/types/date';
复制代码
从上面的代码中,导入现在是清晰、可读和可预测的,因为开发人员知道要导入的模块来自哪个文件夹。
使用绝对导入方法在某些会比较冗余,因为它必须写全路径,而不是使用点和斜线。
但是从长远来看,随着代码库创建更多文件夹和文件而变得更大时,它会很好地发挥作用。
有一些工具可以帮助你实现这个功能。只需要在编译代码时将为你的模块添加解析器的工具就可以了。其中一个工具是 Babel Plugin Module Resolver,您可以阅读它的文档:Babel Plugin Module Resolver。
Prettier 和 ESLint
具有多个项目的大型代码库,每天有多个人在很长的时间内工作,因此编码风格往往不一致。
在开发过程中捕获常见错误被认为是开发人员的核心工作,而开发人员比较容易犯下愚蠢的错误有:错误的文件导入、未使用的变量、错误的变量命名、访问为定义的变量、重复的定义函数......
如果使用 Eslint,这些问题都可以避免。
在 monorepo 中使用 Prettier 和 ESLint 配合效果很好。
使用 Prettier,你可以在所有项目中保持代码风格的一致性。只需在 monorepo 的根目录中创建一个 .prettierrc 配置文件,它会自动应用在 monorepo 中的所有包上。
使用 ESLint,可以帮助我们分析 JavaScript 和 TypeScript 代码。和 Prettier 一样,它可以为 monorepos 轻松配置。你只需在 monorepo 的根目录中定义一个 .eslintrc.json 配置文件,它会应用于所有项目。
但是,如果 monorepo 中有很多文件,Prettier 或 ESLint 可能需要很长时间才能运行。这可以通过将脚本定义添加到本地包的 package.json 来解决,这个文件引用项目根目录中的 Prettier 和 ESLint 配置,这样可以让 Prettier 和 ESLint 只针对特定的包运行。
使用 Turborepo
有几个很棒的工具可以帮助 monorepos 提供流畅的开发体验。
其中一个工具是 Turborepo,它是一个强大的工具,有助于在 JavaScript 和 Typescript monorepos 中开发高质量和高性能的构建系统。它具有很多高级功能,其中之一是并行执行任务。
当我们从根文件夹执行 npm run dev 或 yarn dev 时,它会启动 monorepo 中所有可用的项目,只要这些项目的 package.json 文件中有一个 dev 脚本。同样的事情也适用于其他命令,例如 npm run build, npm run lint, npm run start......
在 Turborepo 中,你可以通过配置项目根文件夹下的 package.json 文件来实现:
"scripts": {
"dev": "turbo run dev",
"lint": "turbo run lint",
"build": "turbo run build",
"clean": "turbo run clean",
...
},
"devDependencies": {
...
"turbo": "latest"
}
复制代码
Turborepo 还附带了各种工具和许多其他配置,默认情况下允许你在深度嵌套的工作空间中并行执行脚本,或者你也可以选择按顺序执行它们或过滤它们。
"scripts": {
"dev": "turbo run dev --filter=\"docs\"",
...
},
复制代码
Turborepo 带有高级远程缓存功能,本地文件的高性能构建是默认功能,也适用于远程文件。你可以随时选择退出本地缓存。
此外,你还可以使用 Turborepo 创建用于执行脚本的 monorepo 管道。
你可以查看 Turborepo 的文档以了解更多信息。
除了 turborepo 外,还有其他类似的工具,比如 Lerna 和 Nx,你可以使用它们来实现相同的功能。
正确的构建工具
为你的 monorepo 项目的部署选择正确的构建工具是一个非常重要的事情。
你应该谨慎选择,因为如果没有做好构建工作,我们可能会遇到必须在仓库中部署所有代码的问题,即使部署的内容只包含必要的源文件。
就像我们使用 Jest 一样,我们也可以使用 Webpack 在一个可以配置为使用 Typescript 引用的 monorepo 中。这可以通过简单地使用 ts-loader 来实现,并且一切都可以设置成自动工作的模式。
我们还有更多工具可以使用,例如 esbuild。Esbuild 默认提供 TypeScript 支持,因此它会自动解析所有的本地引用,因为我们已经配置了 TypeScript project references。你还可以使用 @yarnpkg 插件添加其他配置,这有助于 Esbuild 从本地 Yarn 缓存中解析外部依赖项。
Changesets 也是一种流行的版本控制工具,用于管理存储库中的多个包,例如 monorepo,它为维护人员提供了一个工作流,有助于自动更新包版本和发布新包。
总结
在 monorepo 中使用 Typescript 可能需要一些繁琐的配置和使用一些最佳实践。
但这样做你将能够提高代码库的可维护性,并在你的公司整个代码库中实现了统一性和可见性,不再需要去跟踪不同的代码仓库。
转发:TypeScript Monorepo 最佳实践的更多相关文章
- 基于 Lerna 管理 packages 的 Monorepo 项目最佳实践
本文首发于 vivo互联网技术 微信公众号 https://mp.weixin.qq.com/s/NlOn7er0ixY1HO40dq5Gag作者:孔垂亮 目录 一.背景二.Monorepo vs M ...
- Typescript 开发环境的最佳实践
Typescript 开发环境的最佳实践 0️⃣ git init(略) 1️⃣️️ 初始化:$ yarn add -D ts-node typescript 2️⃣ 生成 tsconfig.json ...
- Typescript 最佳实践
文章列表: <一>大话 TypeScript 基本类型 <二>大话 Typescript 枚举 <三>大话 Typescript 接口 <四>大话 Ty ...
- 《开源安全运维平台OSSIM最佳实践》
<开源安全运维平台OSSIM最佳实践> 经多年潜心研究开源技术,历时三年创作的<开源安全运维平台OSSIM最佳实践>一书即将出版.该书用80多万字记录了,作者10多年的IT行业 ...
- RocketMQ最佳实践
1.RocketMQ中的专业术语 Topic topic表示消息的第一级类型,比如一个电商系统的消息可以分为:交易消息.物流消息...... 一条消息必须有一个Topic. Tag Tag表示消息的第 ...
- ODCA最佳实践翻译:Architecting Cloud-Aware Applications (一)
Architecting Cloud-Aware Applications ** ODCA(Open Data Center Alliance)最佳实践 ** MagicBowen(e.bowen.w ...
- 从Uber微服务看最佳实践如何炼成?
导读:Uber成长非常迅速,工程师团队快速扩充,据说Uber有2000名工程师,8000个代码仓库,部署了1000多个微服务.微服务架构是Uber应对技术团队快速增长,功能快速上线很出色的解决方案.本 ...
- Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(二)
Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(一) 接上一篇 3. Nginx配置反向代理 3.1 cnetos 安装nginx 首先,我们需要在服务器上安装N ...
- 【机器学习】Google机器学习工程的43条最佳实践
https://blog.csdn.net/ChenVast/article/details/81449509 本文档旨在帮助那些掌握机器学习基础知识的人从Google机器学习的最佳实践中获益.它提供 ...
- Kubernetes集群的监控报警策略最佳实践
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/M2l0ZgSsVc7r69eFdTj/article/details/79652064 本文为Kub ...
随机推荐
- .net基础—多线程(二)
Thread 在.NET中最早提供的控制线程类型的类型:System.Threading.Thread类.使用该类型可以直观地创建.控制和结束线程.下面是一个简单的多线程程序: static void ...
- P1982 [NOIP2013 普及组] 小朋友的数字 题解
目录 简单版 题目 code 本题 code 简单版 先要会做这道题 题目 P1115 最大子段和https://www.luogu.com.cn/problem/P1115 这道题其实是动态规划,d ...
- CF1067E 题解
题意 传送门 给定一棵 \(n\) 个节点的树,每条边有 \(\frac{1}{2}\) 的概率出现,可以得到一个森林,求这个森林邻接矩阵的秩的期望. \(1\le n\le5\times10^5\) ...
- VEU开发之element-ui中关闭dialog时并销毁
el-dialog正常使用过程中,经常会发现一些问题,就是dialog加载的组件,每次打开都会有上次的内容,其实是加载到节点未被删除,只是反复隐藏/显示. <el-button type=&qu ...
- 在vue js中for循环使用
在线免费图片压缩工具 前端技术站 1.for(let item of response.data.result) { 用item操作每一条数据. } item:定义的每一条的变量 response.d ...
- 解决windows的mysql无法启动 服务没有报告任何错误的经验。
解决windows的mysql无法启动 服务没有报告任何错误的经验. 相信很多人都遇到过安装Mysql的时候出现各种各样的问题,教大家解决window下mysql服务没有报告任何错误的情况下无法启动 ...
- 【北邮人论坛帖子备份】【FAQ】给今年国企求职学弟学妹的一点建议
目录 主要内容 补充--[心得][校招]面向国企秋招的一些体会 补充--[心得]回馈论坛,某toca的小弟金融类央企秋招过程中的一点点 主要内容 时间:Fri Feb 19 23:00:33 2021 ...
- ES操作
总结一些ES的操作方式及语法 查看健康状态 curl -XGET http://localhost:9200/_cluster/health?pretty 查看索引 curl -XGET ht ...
- 【2020NOI.AC省选模拟#7】A. t1
题目链接 原题解: 由于$+$满足幂等性,我们可以设$f_{i,j}$为从$i$号点向根$2^j$个点的权值之和,并且倍增计算出$f$.在查询是,可以像ST表一样用至多四个$f$中的路径拼出询问路径. ...
- pandas的数据结构--Series创建使用
# 1. 使用Series创建一个空的系列:import pandas as pds=pd.Series()print(s)输出结果为:Series([], dtype: float64) # 2. ...