turboRepo介绍

2,294 阅读9分钟

多项目解决方案介绍

  1. npm发包: 将模块代码发布成npm包,用户只需要安装即可使用。
  2. git submodule/subTree(推荐使用subtree):这种代码架构就是一个主仓库下面有一个或者多个独立仓库,子模块和主模块都有自己的仓库和分支。不同的是git subtree实现了双向修改数据,submodule只能在子模块修改数据,更新后需要提交到主项目。
  3. 模块联邦: 是一种基于webpack5的架构模式,模块联邦通过webpack的ModuleFederationPlugin插件实现,每个模块都是一个单独的构建,这些构建被编译为容器。容器可以异步公开模块,允许构建将每个公开的模块及其依赖项放在单独的文件中,从而减少请求和下载量,提高Web性能。
  4. turborepo: 是一种基于monorepo的构建系统,它能够组织多项目的构建流程,以及使用本地缓存或远程缓存来加快构建速度等。

什么是monorepo?

monorepo(单一代码库):把所有项目的代码统一维护在单一代码库中。这些项目虽然可能相关,但是在逻辑上是独立的,并由不同的团队来维护。

多代码仓库(multirepos): 每个项目存储在一个完全独立的版本库中,这是公司普遍使用的一种方式,比如每个项目的web项目是一个代码库,h5项目是另外一个。

目前,antd,umijs,vant,element ui等开源软件,都是采用monorepo的方式组织项目代码。

monorepo的优点:
1,可见性:每个人都可以看到其他人的代码,对于团队开发比较友好,每个人都可去修复bug.
2, 一致性:把所有的代码放在一起,可以执行的代码质量标准和统一风格更容易。
3,共享时间线:某一共享项目或者api变更会立刻暴露出来,团队可以快速跟进变化。
4,共享性,不同项目使用的相同部分可以抽离出一个单独项目,供其他项目复用。
5,原子提交:开发人员可以一次行提交多个项目。
6,对于微前端项目更友好。

monorepo的缺点:

1,性能差:由于所有项目都放在一起,导致ide或者命令运行比较缓慢。
2,破坏性:某一修改可能会影响全局,如果没有经过严格测试可能会造成多个项目出现bug.
3,学习曲线:增加学习成本。
4,权限控制;失去按项目控制权限。
5,codereview:多个项目同时修改,会增加代码审查难度。

monerepo的实现工具: yarn/pnpm nx turborepo lerna等等。

turborepo简介

turboRepo是一个js和ts的代码构建系统,他是为扩展单包而设计的,同时也使单包工作区的工作流更快。 turoRepo不负责各个工作区的包管理。

如下是monorepo的构建方式:

image.png

每个工作共建有它自己的测试,代码检查,构建等,每个任务的执行都是串行的,当很多任务要去执行的时候,这样的做法是非常减速的。而我们需要快速的构建检查等,这样开发人员才能快速交付高质量的代码。

image.png

turorepo通过任务并行运行,以及缓存等解决了以上的问题。

turboRepo主要有两个功能:

  • 管理工作流,能够配置工作任务的相互依赖关系,实现不同任务的前后运行顺序,且能够实现不同工作区任务流的并行运行
  • 缓存输出内容,turborepo能够缓存构建产物(本地缓存和远程缓存),实现两次相同内容的构建只会运行一次。

turborepo学习

1,构建存储库

1,新建一个turborepo项目

使用如下命令可以快速开始构建一个turborepo项目。

npx create-turbo@latest

此应用包括两个应用程序和三个共享库。

声明包的目录:

image.png

应用程序会根据包目录查找对应的json文件,每一个json文件对应一个包。

根package.json是工作空间的基础:

image.png

根turbo.json配置文件会配置turbo的行为。

使用如下命令可以查看使用turboRepo的示例。

npx create-turbo@latest --example [example-name]

案例名称可以参照如下文档:

案例名称

** 2,添加TurboRepo到已有的存储库**

可以在任何存储库(单包或者多包)中增量添加使用turboRepo。

添加命令如下:

1,在存储库中项目中安装turbo包

 npm install turbo --save-dev

2,添加turbo.json配置turbo的行为

---turbo.json file

{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "check-types": {
      "dependsOn": ["^check-types"]
    },
    "dev": {
      "persistent": true,
      "cache": false
    }
  }
}

3,编辑.gitignore文件

---.gitignore.file
.turbo

4,运行build和check-types 任务

turbo build check-types

5,在不对代码做任何改变的情况下,再次运行步骤4中的命令

image.png

可以看到任务已经被缓存,而不是重新构建。

6,运行 在多包工作空间中,可以使用如下命令去开启所有的任务执行

turbo dev

也可以添加filter指令来只对特定的包进行处理

turbo dev --filter=packageName

2,管理依赖

当我们为对应的包安装依赖的时候,我们应该将依赖包直接安装到使用它的包中。每个包中的package.json中将包含它们所有的依赖项。

包管理器可能会选用与包不同位置的node_modules,也就是monorepo中所有的依赖都会储存在根目录下的 node_modules 中:/monorepo/node_modules

如下是給对应包安装所需依赖的命令:

yarn workspace web add jest --dev
yarn workspace @repo/ui add jest --dev

批量给对应包添加依赖:

yarn workspaces foreach -R --from '{web,@repo/ui}' add jest --dev

但某些情况下,我们可能需要同一 package 的不同版本。例如:一个 react 项目较老,使用 bootstrap 4。而另一个在开发中的新项目决定使用 bootstrap 5。我们可以在packages.json中配置nohist配置。

{
  "name": "monorepo",
  "version": "1.0.0",
  "license": "MIT",
  "private": true,
  "workspaces": {
    "packages": [
      "packages/*"
    ],
    "nohoist": [
      "**/bootstrap"
    ]
  }
}

3,创建内部包

1,创建一个空文件夹

image.png 2,在文件夹下面建立package.json配置文件,使用npm init创建即可。

image.png 3,添加tsconfig.json配置文件

image.png

  • extends可以让你从别的包中继承基础配置
  • compilerOptions outDir它制定编译后的结果放在哪里,与package.json中的exports匹配。
  • compilerOptions roodi确保outDir的目录和src所在目录一致。
  1. 创建src文件夹,并在src目录下创建两个文件
  2. 在应用程序中使用新包

image.png 6. 编辑turbo.json文件:

image.png 7,运行turo build执行构建任务,再次运行运用,可以看到由于缓存作用,应用可以在毫秒级快速构建完成。

4,配置任务

通过对turbo.json的配置,可以使我们的构建流程更快。

比如之前运行命令执行任务时,cpu的执行状态可能如下:

image.png 通过配置turbo.json之后,运行流程如下:

image.png

和明显,第二张图片所用到的时间要比第一个少很多,这就是turboRepo的魅力之处。

image.png

在turbo.json文件中,使用tasks来配置不同的任务。

image.png

dependsOn用于指定当前的任务执行之前必须运行完成的任务。这就是构建依赖,被依赖的项目会优先执行于依赖的项目。

^语法告诉turoRepo从依赖关系图的底部开始运行.比如A依赖于b的,那么b的build任务将会优先执行,然后a的build任务次才会执行。

image.png 有时候可能需要同一个包中的两个任务以特定的顺序执行,比如想执行完build之后执行test任务,那么就可以不带^

image.png

output会让turbo缓存对应的输出文件,这样两次同样的任务将会只执行一次构建任务即可。

image.png input关键字可以配置对应任务执行的扫描文件,默人情况下,turorepo将会包含所有git追踪的文件。上述配置完成之后,只有对应的markdown文件改变,才会去执行spell-check任务。

image.png

cache可以定义任务是否需要缓存,有些任务无论如何都需要执行,那么就可以将cache属性置为false.

5,运行任务

image.png 在package.json中定义可执行任务的脚本。

6,缓存

6-1本地缓存

利用缓存的时候需要注意,turboRepo假设每个任务的输出和输入是一一对应的,如果同样的输入,但是却会产生不同的输入,那么是不能够使用缓存的。

可以通过以下3个方式来尝试使用缓存:

1,创建一个turboRepo项目

npx create-turbo@latest

2,运行构建脚本

yarn run build

3.再次运行步骤2中的脚本命令,输出结果如下:

image.png

可以看到第二次并没有重新构建,因为输入标识可以在缓存中找到,turborepo可以直接从缓存中拿到构建结果,从而节约资源和时间。

6-2远程缓存

Turborepo将任务的结果存储在机器上的.turbo/cache目录中。但是,通过与您的团队成员和CI共享此缓存,您可以使整个组织更快。

使用远程缓存步骤:

1,是用身份验证

npx turbo login

2,将机器的存储库和远程存储库链接起来

npx turbo link

配置完成之后,turorepo会自动将构建输出发送到远程缓存,如果有团队成员在另外一台机器上运行相同的任务,并且该机器也对远程缓存进行了身份验证,那么第一次执行该任务的时候,就会直接从远程缓存拿到对应的构建结果,而不是重新构建。

默人情况下,turbo使用默人配置的vercel远程缓存。你也可以根据文档来配置不同的远程缓存。