在 monorepo 中引用依赖时直接指向源码
本文最后更新于:2022年1月13日 下午
场景
在 monorepo 项目中,我们可能有几十个 lib 模块,而 lib 模块如果需要发布到 monorepo 外,则必须打包为 js,并且将 main/module
指向打包后的 js 文件,以便所有人都能使用。
例如下面这样一个简单的 lib 模块
- lib-a
- src
- README.md
- package.json
- tsconfig.json
原先不需要发布时 package.json 中可能直接指向源码
这种 monorepo 中 lib 无构建的优化方式在 如何减少 monorepo 中 lib 的初始化时间 提到过
1 |
|
而当发布后,则需要修改为
1 |
|
这就导致我们至少需要添加一个 setup 脚本,以供第一次拉取项目的人批量执行所有模块的初始化动作。例如 pnpm 的命令可能是 pnpm --filter . run setup
1 |
|
如果模块只有一两个,那么可能不会花太多时间。但如果模块有几十个(我们的生产项目中,大约有 37 个),就算一个模块的初始化构建仅需要几秒钟,那么累积起来也需要几分钟。目前有许多做法
- 仅首次全部初始化,后续更新由使用者自行去使用的模块重新构建。例如 antv 系列的开源项目
- 使用 typescript 的 project-references,直接指向 ts 源文件。例如开源项目 Maskbook
- 缓存构建的文件,避免重新构建。例如 nx.js、yarn-plugin-change、ultra-runner
- 加快每个模块的构建速度。吾辈之前尝试使用 esbuild 重构 @liuli-util/cli
由于吾辈大部分 web 项目均基于 vite 开发,所以便考虑使用创建一个 vite/rollup 插件来重写 module resolve,将 import 的模块直接重写指向源码而非 dist/index.js,即便这样会增加每个模块开发时的时间,但平均到每个模块中依赖的其他 lib 不超过 10 个,额外增加的时间几乎是微不足道的(主要是在一个 nodejs 进程并且使用 esbuild 编译)。
实现
在自行实现之前,吾辈也检索过现有的插件,例如 @rollup/plugin-alias,但它的配置是静态的,例如吾辈需要配置 @liuli-util/*
全部指向 @liuli-util/*/src/index.ts
,这需要为每个模块单独配置。
1 |
|
而吾辈期望专注于做这件事情,所以便单独开发了一个插件 rollup-plugin-ts-alias
1 |
|
使用
该插件已发布至 npm @liuli-util/rollup-plugin-ts-alias
安装
1 |
|
配置
1 |
|
之后,在 monorepo 直接修改 lib 的源码便能热更新,不需要启动额外的 terminal,也不再需要添加 setup
命令供全部初始化。下面可以看到,依赖的 lib @liuli-util/react-router 已经被指向源码了
问题
- 大型 monorepo 应该怎么解决性能、协作问题?
- 亦或是我们不需要使用 monorepo?