浅谈 Monorepo 带来的效益:以 Turborepo 为例

944次阅读  |  发布于2年以前

前言

随着技术发展越来越进步,除了编程语言的框架越来越多以外,连项目的架构也越来越复杂了,今天这篇文章就来探讨一个算是近年越来越多开发者在讨论的项目架构:Monorepo。

什么是 Monorepo?

在一般的开发模式中,通常都是一个项目用一个仓库进行管理,假如今天要设计一个内容管理系统的产品,一般来说会提供以下两种服务。

  1. 后台管理系统。
  2. 前台页面(H5)。

这时候按照以往的开发方式,我们会创立两个仓库分别去管理这两个网站,这种项目架构的设计方式称之为:Multi-repo

反之,当我们把这两个网站都用一个 仓库 进行管理,这种做法就是 Monorepo

为什么我们需要 Monorepo?

看完上述 Monorepo 的介绍,可能读者还是会觉得有点懵,觉得集中管理跟分开管理并没有相差多少,其实除了项目上的集中管理外,Monorepo 能做到的事情还有很多。

其实 Monorepo 除了管理专案之外,也可以管理一些共用的组件,甚至是共用的 utils,这样就不用很麻烦的在两个项目上进行 ctr c + v,通常在 Monorepo 上会用以下的项目架构进行设计。

apps
  |- 后台网站
  |- 前台网站
node_modules
packages
  |- components
  |- utils

在 apps 的文件中,我们会放置真正会被执行的项目,假如日后这个项目是有机会要被 builddocker image 的话,这时候就可以根据 apps 文件中的项目产出相对应的 docker image,以上述的例子来看就是会产生出 后台网站 以及 前台网站 这两个 image。

packages 的文件中,我们就可以放置各种需要被共用的组件或者是 utils,在这边开发的共用内容就可以同时被 apps 文件内的项目使用,这样的架构设计也可以让代码写起来相当干净。

Package Manager

Monorepo 的世界中一个 仓库 底下会有很多个项目,每个项目都会有自己的 package,假如没有一个好的** package manager** 来管理这些 package 的话,最后就会让整个 仓库 很难被控制,因此接下来要花一点篇幅来稍微阐述一下 package manager 的用法。

以前端来说比较著名的 package manager 有以下几个:

通常** package manager** 只负责用来处理依赖的安装,然而在 Monorepo 的架构中,我们通常都会有好几个项目在同一个文件中,这时候就必须要使用 package manager 的一个重要观念:workspaces。

workspaces 简单来说就是可以方便让你一键安装所有的依赖至 workspaces 所管理的目录内,或者是方便你安装依赖在 workspaces 所管理的目录。

想要设定 workspaces 管理的目录也很简单,只要在 package.json 中填上想要被管理目录路径就好,像下图这样:

在上图中让 workspaces 所管理的目录就包括 apps 文件以及 packages 文件内的所有第一层的文件。

想要将依赖利用 workspaces 安装到指定的目录也很简单,只要打上yarn workspace folderName add packageName 即可。

这时候打开 web 目录中的 package.json 就会发现 styled-components 真的被安装进去了非常方便。

想要移除依赖也很简单,只要把刚刚指令中的 add 改成 remove 就好。

这时候的 package.json 也就会删除掉依赖的相关资源。

Turborepo

接下来就正式进入本篇文章的重头戏:Turborepo 。

Turborepo 支持的 package manager 有 Yarn、npm、pnpm,这边以 Yarn 当作范例。

为了快速产生一个完整可用的项目架构,这边可以运行 npx create-turbo@latest 这样就可以快速产生一个基于 Turborepo 架构而生的 Monorepo 项目。

接下来进入 repo 内可以看到有一个蛮特别的文件叫 turbo.json ,这个文件主要可以用来设定一些执行指令的 pipeline,而 pipeline 主要的功能就是当你在执行 yarn run xxx时,这个指令在执行时应该要有哪些规范,想要了解更多 pipeline 设定的读者也可以参考这个网站。

例如这边的 dev 有一个 cachefalse 的设定,就代表著每次执行 dev 这个指令时都不要使用先前的 cache 以确保每次的开发环境都会是最新的环境。

可以看到在 turbo.json 配置项的 pipeline 基本上跟 package.jsonscripts 指令互相对应。

可以看到在 turbo.json 这隻档案设定的 pipeline 基本上跟 package.json 的 scripts 指令都有互相对应。

其实在 apps 目录内的项目都有各自的package.json ,只要在这些项目的package.json 内都有 dev 这个 script,Turborepo 就会自动执行这些内容。

最后再补充一点,读者在观察项目架构时可以看到有一个叫 packages 的目录,这个目录内内容基本上就是要提供一些共用的内容给 apps 中的项目。

假如要让 packages 内的某个文件容给 apps 内的某个项目用,这时候就可以在该项目 package.json 中填上对应包名,并且把版本号设定为 * ,这样就可以顺利在该项目内引用 packages 中的内容啦!

Turborepo 开发

由于这次的范例是利用 Yarn 做为 package manager,因此这边可以下 yarn dev 来启动开发环境,这边可以看到有一个参数是 --parallel ,这个参数是可以让我们依序启动项目的参数,如此一来在开发环境下就不会忘记有哪个项目没被启动了。

之后就可以在localhost:3000 以及localhost:3001 看到两个项目的画面啦!

总结

今天介绍了 Monorepo 的项目架构,虽然 Monorepo 的架构看似非常好用,但其实这种项目架构设计并不适合所有的产品,假如今天大家有想要试玩看看 Monorepo 但又不知道可以怎麽下手的话,也可以利用 Monorepo 的架构设计一些 UI 库。

而且现在很多主流的 UI 库 都有使用 Monorepo 作为架构,例如:Material UI 使用 lerna 、 NextUI 使用文章介绍的 turborepo 等等,假如之后读者有遇到类似的使用情境不妨可以尝试看看 Monorepo 架构喔。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8