浅析eslint、 typescript-eslint 性能慢,如何解决?

3,187 阅读3分钟

问题:Lint的过程很慢

在使用 TypeScript 设置我们团队的 ESLint 配置时,我注意到使用 typescript-eslint 运行 ESLint 非常慢。

在GitHub挖掘了很久,我发现根本原因是使用类型信息运行 typescript-eslint 会导致意外的性能成本。

typescript-eslint 将 TypeScript AST 转换为 ESLint AST

文档:typescript-eslint: How does typescript-eslint work.

ESLint 通过使用由 ESLint JavaScript 解析器 Espree 生成的 AST 运行规则来工作。

但是,TypeScript 有额外的语法,因此 TypeScript 编译器创建的 TypeScript AST 需要转换为 ESLint 兼容的 AST。

此过程由@typescript-eslint/parser 提供的自定义解析器处理,该解析器利用@typescript-eslint/typescript-estree 包中的ESTree。

因此,@typescript-eslint/typescript-estree 需要在每个 .{ts,tsx} 文件上调用 TypeScript 编译器来生成 TypeScript AST,然后将 TypeScript AST 转换为与 ESLint 兼容的 AST。

创建此 AST 后,@typescript-eslint/eslint-plugin 使用 ESLint 可以针对其运行规则的 TypeScript 特定功能扩展规则。

.eslintrc指导typescript-eslint 的的运行过程。 个人参考以下代码可以实现从30s的lint到15s的优化

// .eslintrc.js
module.exports = {
  root: true,
  parser: "@typescript-eslint/parser",
  parserOptions: {
    tsconfigRootDir: __dirname,
    project: ["./tsconfig.json"]
  },
  plugins: ["@typescript-eslint"],
  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking"
  ]
};

总之,高级 typescript-eslint 解析过程包括:

  1. @typescript-eslint/parser
    • @typescript-eslint/parser 读取 .eslintrc 配置以确定包含和排除的文件
    • @typescript-eslint/parser 调用 @typescript-eslint/typescript-estree
  2. @typescript-eslint/typescript-estree
    • @typescript-eslint/typescript-estree 调用 TypeScript 编译器并将每个包含的 .{ts,tsx} 文件解析到 TypeScript AST
    • @typescript-eslint/typescript-estree 将 TypeScript AST 转换为与 ESLint 兼容的 AST
  3. @typescript-eslint/eslint-plugin
    • @typescript-eslint/eslint-plugin 扩展了 ESLint 规则与 TypeScript 特定的功能

TypeScript 基本上是在执行我们项目的构建,并在 ESLint 进行 linting 之前将每个 AST 节点复制并转换为 ESLint 兼容节点

ESLint 还单独运行每个文件,因此在每个文件中初始化类型检查器都会产生重复的开销工作。

不幸的是,这意味着运行时间随着项目的大小而增加。

当有更多文件时,TypeScript 编译时间和 AST 转换时间会增加。

后续步骤:较小的性能改进调整

我无法发现许多大型优化来提高运行时性能。

根本问题仍然是 TypeScript 编译器生成 AST 的开销,以及将这个 AST 转换为 ESLint 兼容 AST 的 @typescript-eslint/typescript-estree 的工作。

但是,有一些小的调整:

  • 设置 .eslintignore 以忽略不相关的目录,例如 node_modules 和非typescript文件。
  • 运行 eslint 时使用 --cache 标志:eslint --cache **/_.ts。 存储有关已处理文件的信息,以便仅对更改的文件进行操作。

还有一篇关于 TypeScript 性能的整篇文章建议:

  • 使用 include 属性设置 tsconfig.json ,指定项目中应编译的 TypeScript 文件的输入文件夹。
  • 避免添加过多的 exclude 和 include 文件夹,因为 TypeScript 文件必须通过遍历包含的目录来发现,因此运行多个文件夹实际上会减慢编译速度。
// tsconfig.json
module.exports = {
  compilerOptions: {
    // ...
  },
  include: ["src"],
  exclude: ["**/node_modules", "**/.*/"]
};

最后

文章翻译自: