TypeScript [5.6-beta] #57196 在祖先及其引用中搜索默认项目导致孤立文件的TSServer性能退化

1cklez4t  于 4个月前  发布在  TypeScript
关注(0)|答案(2)|浏览(44)

搜索祖先及其引用的默认项目孤立解决方案
版本与回归信息

Playground链接

  • 无响应*

代码

  • 无响应*

实际行为
上下文:我们有一个包含数千个项目的monorepo。大致上,代码库的结构遵循以下结构:

  • tsconfig.json - "solution style" tsconfig,引用所有其他 tsconfig.json 文件
  • folderA
  • *.tsx 文件
  • tsconfig.json - "solution style" tsconfig,指向兄弟 tsconfig.non_test.jsontsconfig.test.json 文件
  • tsconfig.non_test.json - 包括当前目录中的所有非测试源文件,排除位于子目录中的项目中的文件,例如在 subSubFolderA 中。
  • tsconfig.test.json - 包括当前目录中的所有测试源文件,排除位于子目录中的项目中的文件,例如在 subSubFolderA 中。
  • subFolderA
  • *.tsx 文件
  • subSubFolderA
  • *.tsx 文件
  • tsconfig.json
  • tsconfig.non_test.json
  • tsconfig.test.json
  • folderB
  • tsconfig.json
  • tsconfig.non_test.json
  • tsconfig.test.json

我们曾经不得不手动维护这些tsconfig文件,但现在它们都是使用围绕Bazel构建的我们的工具生成的,可以进行智能操作,例如通过查看其源文件中的导入来推断一个项目需要引用哪个项目。无论如何,我描述所有这些的原因是为了使我们更容易看到在我们创建新项目时创建新文件并在事后生成tsconfig的过程。在生成tsconfig文件之前,所有新文件都被视为孤儿。当打开这些文件中的任何一个时,VSCode会在整个项目树中搜索,沿途查看所有解决方案tsconfig,并加载所有被引用的项目。这最终到达根目录中的 tsconfig.json ,导致所有项目被加载到项目图中。此时TSServer最终会爬过我们慷慨地给予它的48 GB内存限制,直到它崩溃。
上周我花了很多时间调试发生了什么(实际上是将调试器附加到tsserver.js并逐步执行代码)。直到看到5.6版的beta announcement 我才意识到这是最近的更改(我们一直在使用nightly版本访问isolatedDeclarations和noCheck)。直到最近,我们的根目录实际上有不同的名称,因此它不属于祖先搜索。我们将其改回为减少开发者混淆的名称,所以我只把我们最近的问题归因于这个变化。
😊预期行为
在我调试过程中不清楚的是 为什么 TSServer需要实际将项目加载到图中才能确定它是否包含给定的源文件。也许这里有一个好理由,但也许这是一个优化的机会,以便只有在打开的文件属于它或一个间接引用它的项目时才加载一个项目。如果能有一种方法可以让我们回到没有 xe2f1x 之前的行为就好了。这似乎很简单,只需在tsconfig中添加一个选项来指示如果有一个源文件的所有者存在,那么它就不会出现在祖先中。示例:
xm25n1x - 表示当前项目传递性地包含或引用此目录中的所有源文件,并防止搜索祖先。
我最终采用的解决方案是修补TSServer,使其在递归遍历项目引用时跳过那些不可能包含触发源文件的项目,只需查看tsconfig的路径是否是另一个源文件路径的前缀(我们的 xm26n1x 一直默认)。我在下面提供了修补程序(因为我修改了已经打包的JS文件,而不是从原始源代码开始并构建它)。也可以向tsconfig添加一个选项来模拟这种行为。示例:
xm27n1x - 如果其 xm28n1x 不包含源文件,则不要递归加载项目引用。

neskvpey

neskvpey1#

当前禁用解决方案搜索控制,用于打开文件的解决方案搜索以及查找所有引用..我们正在寻求关于为什么我们需要两个标志的反馈。
我们必须加载项目,因为程序中的并非所有文件都是由给定的项目组成的,一些d ts文件可以打开并属于项目,因此如果我们在找到项目之前就加载了它,就不能保证一定能找到项目。

y1aodyip

y1aodyip2#

关于类似disableProjectReferenceSearchingForSourceOutsideRoot的内容,似乎与disableSolutionSearching的情况不同。
我们必须加载项目,因为程序中的并非所有文件都是由项目提供的,一些d ts文件可以打开并属于项目,所以如果我们在找到项目之前就加载了它,就没有保证。
我不认为我真的理解为什么需要加载项目来确定它是否包含源文件。这不就是将include + exclude + files模式与源路径进行匹配的功能吗?即使需要加载项目,如果我们确定它不包含源文件且该项目中没有打开的文件,我们是否还需要将其保留在内存中?

相关问题