上周,我一直在将一个非常大的单一存储库(npm/typescript)重构为monorepo(yarn/lerna/typescript),刚开始的时候转换非常容易,我只是将文件重构到它们各自的文件夹中,并更新导入。
真正的痛苦开始于我开始在"开发"中尝试运行monorepo的不同方式(热重新加载/观看)模式。我真的很想避免每一个变化的每一个包(遗憾的是,就目前而言,它们都是相互依赖的)我使用Lerna引导项目并安装模块,正如我所看到的,Lerna将文件夹链接到Node_Modules,这意味着每一个更改都会在所有repos中自动更新。我已经尝试了几种方法,我真的需要指导如何继续或者标准是什么。
问题:
我有一个monorepo,其中包含3个带有服务类的包/项目,以及1个使用这些包的CLI包。当我使用命令对旧的monolithic repo运行CLI命令时:
ts-node --transpiler sucrase/ts-node-plugin --project tsconfig.json --require tsconfig-paths/register bin/cli.ts
它在内部传输所有必要的(引用的)ts文件,并在500ms-1秒内执行。这是一个可以接受的传输时间,我希望保持。我的第二个问题是我使用了tsconfig路径,这意味着我每个包都有一个tsconfig文件。我希望保持它们,但在最坏的情况下,我将不得不用相对路径替换它们。
以下是我的解决方案:
1.用tsc-watch运行每个目录,将package.json主条目指向dist/index.js,然后完成它。这样做的问题是tsc的编译/传输时间。编译源文件大约需要500ms-1s。d.ts文件生成对于每个包花费至少1.5 - 2秒,且在tspath之上花费另外500ms来替换我试着用babel-watch代替tsc-watch,它对于JS编译来说甚至更快,但是没有生成类型。
1.使用相同的文件运行上面提到的相同命令。我尝试了这个命令,它似乎工作正常,但我不知道如何解析嵌套软件包的tsconfig路径。例如,软件包CLI将使用相对tsconfig解析其路径,然后CLI将找到本地软件包Transpiler(本地文件夹链接到node_modules),它有自己的路径集,我不知道如何指定。在这种情况下,我会牺牲ts路径来获得真正快速的开发迁移时间。在这种情况下,我会将package.json main指向src/index.ts,这会使构建变得困难,因为每次构建生产项目时都需要替换它(但这与步骤1相同)。
我使用AWS JS SDK monorepo作为指导和参考。
项目结构:
packages
- cli *(depends on transpiler)*
- transpiler *(depends on common and statements)*
- statements *(depends on common)*
- common *(depends on nothing)*
package.json
tsconfig.json
1条答案
按热度按时间yshpjwxd1#
在我之前对你的问题写了评论之后,我实际上做了一些进一步的挖掘,发现了这篇很棒的文章Boost your productivity with TypeScript project references,并决定给予一试。
为了给予一些关于我的monorepo项目Slickgrid-Universal的统计数据,我在monorepo中有17个包,我使用Lerna-Lite时没有使用任何工具,在每次测试运行之前,我删除了所有
dist/
文件夹,然后比较了两种方法1.执行
lerna run
命令大约花费了1 m30秒1.使用TypeScript引用执行
tsc -b
花费了18秒哇,我不能我已经错过了这个
tsc -b
(或--build
)与TypeScript引用它是5倍快,只是哇,这也包括声明文件(d.ts)。我们还可以添加监视模式(也注意到它的性质是增量的,所以没有必要添加--incremental
)我还尝试了另一个测试,我想看看当我将新属性添加到
common
包中的现有接口时,在监视模式下传播类型需要多长时间(这是我最大的包,有数百个接口),并等待着看接口花了多长时间才反映在我的前端包中,花了10秒才在我的编辑器中显示出来,还不错但我真的以为(希望)更低的值。事实上,10秒与我之前在每个包中使用lerna watch
和tsc --incremental
的实现非常相似,所以我没有看到这方面的多少增益。真实的的增益实际上是在第一个干净的构建上,18 sec vs 1 m30 sec对我的整个monorepo包括类型是惊人的快相比之前。我们能快点吗?
可能还有另一种方法,我读过但从未真正尝试过,那就是简单地进行类型检查(这是ViteJS和ESBuild正在做的),而不通过命令
tsc --noEmit
生成声明文件。我不确定,但我认为使用这种方法,至少构建一次类型,然后在监视模式下使用--noEmit
可能会更好。我不确定这在monorepo结构中是否真的能很好地工作,因为从mono的另一个包导入必须经过那个包的package.json
,我假设这将需要类型存在,以便能够在编辑器中使用TypeScript。我认为这个新的选项2.是我从现在开始使用的。注意,我还想知道这个
tsc -b
是否可以与其他工具如TurboRepo或Nx一起使用。我没有使用这些工具,但我猜它可能不起作用。我猜使用这些工具,您仍然需要在每个包中使用单独的tsc
命令。如果与缓存一起使用,使用这些工具可能仍然更快,因为您只需要构建您更改的包。但是tsc -b --incremental
也是相当快的。编辑
在重构代码并创建PR之后,我发现了一些需要记住的事情
1.我决定仍然保留我原来的
lerna watch
,它在每个包中使用tsc --incremental
,原因有两个1.我还监视SASS文件,并希望为所有文件扩展名(.ts、.scss)保留一个Lerna监视。
1.在已更改的包中使用
lerna watch
和tsc --incremental
的时间与从根目录运行tsc -b --watch
的时间大致相同,因此,如果我在开发中没有获得速度,那么我宁愿保留已设置的单个lerna手表,而不是使用多个手表(1x tsc手表,多个SASS手表,因为我有几个SASS主题)lerna watch
似乎比tsc --watch
占用更少的资源(内存/CPU使用率),至少在Windows上是这样。注意,单个tsc监视器仍然比每个包有多个tsc监视器要好一个数量级1.这最后三点可能与您的项目无关,
tsc -b
仍然是前进的方向不管这最后3点,我仍然在启动
lerna watch
之前在根目录中运行tsc -b
,因为它非常快,而且我需要在开始开发时存在类型。然而,当这完成后,我只是简单地依赖于lerna watch
来运行tsc --incremental
的软件包上的变化。它不是最快的,但它仍然比我以前有很多。也许通过这种方法,我可以只使用lerna watch
和tsc --noEmit
进行类型检查(将来有更多时间时,我可能给予一下)我还发现另外这篇文章Using TypeScript Project References with ts-loader and Webpack非常有帮助,信息量也很大