入职新公司快一个月了。再一次的东京生活也算稳定下来了。到现在为止生活还算惬意,30 岁之后心态真的会发生很大的变化(笑
每当天气好的清晨黄昏,就可以在小屋阳台看到富士山
话不多说,接手的第一个项目是类似问卷的项目,包括管理侧制作问卷,和用户侧使用问卷。分两个仓库开发过一版,但是种种原因没有上线。现在时机成熟了,重启项目。新的一版设计中管理侧有预览用户侧问卷的功能,那为什么不把两个仓库合二为一呢。
上一份工作有大规模的使用 Monorepo,采用的是微软开源的NX
作为构建 Monorepo 的方案,功能很齐全很强大,它的命令行工具类似 NG CLI,但这样带来的副作用就是刚上手可能会有一些不知所措。小型项目使用的话,有些杀鸡用牛刀。
短暂的考虑一番之后,决定采用简单轻量pnpm workspace
方案,花了一天时间把两个项目合而为一,顺便替换掉Yarn
.
由于基于原 admin 仓库进行改造的,在项目根目录创建pnpm-workspace.yaml
文件,确定 workspace 位置。我这边的初步设计很简单就是 两个 App 分别是: admin 和 user,公共部分放在 packages 文件夹里
项目结构如下
1 | . |
仅此pnpm-workspace.yaml
配置如下(暴露了两个文件夹)
1 | packages: |
三部分就是三个独立的前端项目。
- 之前 admin 代码内容统统移动到 apps/admin 里面。合并的 user 仓库代码夜一并移动到 apps/user 中。
公共部分 packages 和最外层 也pnpm init
分别创建package.json
。 - 调整
package.json
中 name(也就是包名)现在四个 workspace 区域。最好起名相互管理。这里最外层叫lacApp
,里层三个项目分别交@lacApp/admin
/@lacApp/user
以及@lacApp/packages
- 删除调整代码:之前移动过去的 admin、user 代码。删除 lock file,ignore file(之后在外层统一管理)。
.eslintrc
/tsconfig
如果用共同,推荐在外层维护一个共通的配置,里层项目通过 extend 方式继承调整配置代码 4.公共部分 npm 包移动到最外层。比如react
/eslint
/axios
/vite
/typescript
··这些两个 app 或者公共包都会用的移动到最外层,相应的里层package.json
中进行删除。
如果之后需要全局安装以来,可以通过 -w、–workspace-root 参数来安装. 给某个特定的 package 安装依赖,可以通过 –filter 参数来安装.
eg:
1 | # 全局安装开发依赖eslint |
模块之间进行相互依赖,比如我们的公共部分@lacApp/packages
,分别在 admin 和 user 中使用。它作为一个包,作为 app 的依赖
1 | pnpm add @lacApp/packages -r --filter @lacApp/admin |
4.调整好后,最外层添加 file:.npmrc
1 | auto-install-peers = true |
告诉npm
在安装一个包的同时,自动安装其在 monorepo 中的相互依赖(peer dependencies)。
5.最外层pnpm i
就可以了。(是不是很简单,在外层生成一份 lock 文件。并且里层的 npm 包也一并进行了安装
6.调整 script。其实 cd 到里层项目执行脚本完全 ok。但是这里更推荐。外层去配置相应的 script 统一管理 比如:
1 | ### dev |
1 | ###如果想要一起执行也是可以的(默认情况下,pnpm 会根据子包的依赖拓扑排序,按顺序对子包执行命令,以避免在构建某个包的时候,出现子依赖的构建产物未生成的问题,进而引发比如类型错误等问题。另外如果两个子包没有依赖关系,pnpm 会并发进行构建。 |
7.其实到这一步就算完了,是不是很简单。构建配置需要和运维进行简单的沟通。可能之前 dist 目录在根目录现在无非在 apps/admin/dist
和 apps/user/dist
多了两层
8.* 上车turborepo
.其实其实到第七步就算完了,是不是很简单。为了更好的 monorepo 构建体验(想折腾一下)可以上车Turborepo
.
turborepo 是一个适用于 JavaScript 和 Typescript monorepo 的高性能构建工具,它不是一个侵入式的工具,你可以在项目中渐进的引入和使用它,它通过足够的封装度,使用一些简单的配置来达到高性能的项目构建。
和 esbuild 一样,Turborepo 也是基于 go/rust 实现的工具,在语言层面上就具有一定的性能优势。还有更快的增量构建。turborepo 中的缓存机制 可以帮助我们记住构建内容 并且跳过已经计算过的内容,优化打包效率。(真的超级快
turborepo 正因为它可以渐进的引入和使用,改造起来很简单。
1 | pnpm install turbo -w -D |
之后在根目录配置 turbo.json
.这里有个pipeline
管道的概念,
说简单点就是基于turbo.json
约定的配置,控制脚本执行的顺序、依赖。按配置文件定义任务之间的关系,然后让 Turborepo 优化构建内容和时间
在我们执行turbo run
命令的时候turbo
会根据我们定义的 Pipelines(https://turbo.build/repo/docs/core-concepts/monorepos/running-tasks) 里对命令的各种配置去对我们的每个 package 中的 package.json
中 对应的 script 执行脚本进行有序的执行和缓存输出的文件。
当然 turbo 里的 pipeline name 也是 monorepo 中每一个子包里的script
。比如 admin app
和 user app
都有run dev
命令。这里就可以定义一个 name 为 dev 的 Pipelines.执行 script:turbo run dev
就会同时执行 两个 app 中定义的dev
命令
1 | { |
最后还要提一下 filter 过滤语法 其实和 pnpm 的类似 比如我们只想用 turbo build admin 项目 。我们就可以
1 | build:admin": "turbo run build --filter=@lacApp/admin", |
加上 Turbo,可以在已经很快的构建上,锦上添花。
就这样吧