Skip to main content

性能故障排除


正如 类型感知的 linting 文档 中提到的,如果你使用类型感知 linting,你的 lint 时间应该与构建时间大致相同。

英:As mentioned in the type-aware linting doc, if you're using type-aware linting, your lint times should be roughly the same as your build times.

如果你遇到的时间比这慢得多,那么有一些常见的罪魁祸首。

英:If you're experiencing times much slower than that, then there are a few common culprits.

广泛包含在你的 tsconfig

使用类型感知 linting 时,你需要向我们提供一个或多个 tsconfig。 然后,我们将预解析所有文件,以便提供完整且完整的类型信息。

英:When using type-aware linting, you provide us with one or more tsconfigs. We then will pre-parse all files so that full and complete type information is available.

如果你在 include 中提供非常宽的 glob(例如 **/*),则可能会导致此预解析中包含的文件数量超出你的预期。 此外,如果你在 tsconfig 中未提供 include,则与提供最宽的 glob 相同。

英:If you provide very wide globs in your include (such as **/*), it can cause many more files than you expect to be included in this pre-parse. Additionally, if you provide no include in your tsconfig, then it is the same as providing the widest glob.

宽范围可能会导致 TypeScript 解析诸如构建工件之类的内容,这会严重影响性能。 始终确保提供针对你特别想要检查的文件夹的 glob。

英:Wide globs can cause TypeScript to parse things like build artifacts, which can heavily impact performance. Always ensure you provide globs targeted at the folders you are specifically wanting to lint.

广泛包含在你的 ESLint 选项中

在 ESLint 命令中指定 tsconfig.json 路径也可能会导致比预期多得多的磁盘 IO。 与使用 ** 递归检查所有文件夹的 glob 不同,更喜欢一次使用单个 * 的路径。

英:Specifying tsconfig.json paths in your ESLint commands is also likely to cause much more disk IO than expected. Instead of globs that use ** to recursively check all folders, prefer paths that use a single * at a time.

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

详细信息请参见 解析器选项 "project" 中的 Glob 模式会减慢 linting

英:See Glob pattern in parser's option "project" slows down linting for more details.

indent / @typescript-eslint/indent 规则

此规则有助于确保你的代码库遵循一致的缩进模式。 然而,这涉及文件中每个标记的大量计算。 在大型代码库中,这些问题可能会累积起来,并严重影响性能。

英:This rule helps ensure your codebase follows a consistent indentation pattern. However this involves a lot of computations across every single token in a file. Across a large codebase, these can add up, and severely impact performance.

我们建议不要使用此规则,而是使用 prettier 等工具来强制执行标准化格式。

英:We recommend not using this rule, and instead using a tool like prettier to enforce a standardized formatting.

请参阅我们的 格式化文档 了解更多信息。

英:See our documentation on formatting for more information.

eslint-plugin-prettier

该插件在 lint 时显示 Prettier 格式化问题,有助于确保你的代码始终格式化。 然而,这需要付出相当大的成本 - 为了弄清楚是否存在差异,它必须对每个被检查的文件进行 Prettier 格式。 这意味着每个文件将被解析两次 - 一次由 ESLint 解析,一次由 Prettier 解析。 这可能会增加大型代码库的规模。

英:This plugin surfaces Prettier formatting problems at lint time, helping to ensure your code is always formatted. However this comes at a quite a large cost - in order to figure out if there is a difference, it has to do a Prettier format on every file being linted. This means that each file will be parsed twice - once by ESLint, and once by Prettier. This can add up for large codebases.

我们建议使用 Prettier 的 --check 标志来检测文件是否格式不正确,而不是使用此插件。 例如,我们的 CI 设置为自动运行以下命令,这会阻止尚未格式化的 PR:

英:Instead of using this plugin, we recommend using Prettier's --check flag to detect if a file has not been correctly formatted. For example, our CI is setup to run the following command automatically, which blocks PRs that have not been formatted:

npm run prettier --check .

详细信息请参见 Prettier 的 --check 文档

英:See Prettier's --check docs for more details.

eslint-plugin-import

这是我们在这个项目中使用的另一个很棒的插件。 然而,有一些规则可能会导致 lint 非常慢,因为它们会导致插件进行自己的解析和文件跟踪。 这种双重解析加起来会产生很大的代码库。

英:This is another great plugin that we use ourselves in this project. However there are a few rules which can cause your lints to be really slow, because they cause the plugin to do its own parsing, and file tracking. This double parsing adds up for large codebases.

进行单文件静态分析的规则有很多,但我们提供以下建议。

英:There are many rules that do single file static analysis, but we provide the following recommendations.

我们建议你不要使用以下规则,因为 TypeScript 提供与标准类型检查相同的检查:

英:We recommend you do not use the following rules, as TypeScript provides the same checks as part of standard type checking:

  • import/named
  • import/namespace
  • import/default
  • import/no-named-as-default-member

以下规则在 TypeScript 中没有等效检查,因此我们建议你仅在 CI/推送时运行它们,以减轻本地性能负担。

英:The following rules do not have equivalent checks in TypeScript, so we recommend that you only run them at CI/push time, to lessen the local performance burden.

  • import/no-named-as-default
  • import/no-cycle
  • import/no-unused-modules
  • import/no-deprecated

import/extensions

使用强制扩展

如果你想强制始终使用文件扩展名,并且你使用 moduleResolution node16nodenext 进行 NOT 操作,那么对你来说并没有一个好的替代方案,你应该继续使用 import/extensions lint 规则。

英:If you want to enforce file extensions are always used and you're NOT using moduleResolution node16 or nodenext, then there's not really a good alternative for you, and you should continue using the import/extensions lint rule.

如果你想强制始终使用文件扩展名,并且 ARE 使用 moduleResolution node16nodenext,那么你根本不需要使用 lint 规则,因为 TypeScript 会自动强制你包含扩展名!

英:If you want to enforce file extensions are always used and you ARE using moduleResolution node16 or nodenext, then you don't need to use the lint rule at all because TypeScript will automatically enforce that you include extensions!

不使用强制扩展

从表面上看,import/extensions 对于这个用例来说应该很快,但是该规则不仅仅是纯粹的 AST 检查 - 它必须解析磁盘上的模块,以便在导入模块的情况下不会出现误报 其名称中包含扩展名(例如 foo.js 解析为 node_modules/foo.js/index.js,因此需要 .js)。 这种磁盘查找的成本很高,因此会使规则变慢。

英:On the surface import/extensions seems like it should be fast for this use case, however the rule isn't just a pure AST-check - it has to resolve modules on disk so that it doesn't false positive on cases where you are importing modules with an extension as part of their name (eg foo.js resolves to node_modules/foo.js/index.js, so the .js is required). This disk lookup is costly and thus makes the rule slow.

如果你的项目不使用任何名称中带有文件扩展名的 npm 包,也不使用两个扩展名(如 bar.js.ts)来命名文件,那么这种额外的成本可能不值得,你可以使用更简单的 使用 no-restricted-syntax lint 规则进行检查。

英:If your project doesn't use any npm packages with a file extension in their name, nor do you name your files with two extensions (like bar.js.ts), then this extra cost probably isn't worth it, and you can use a much simpler check using the no-restricted-syntax lint rule.

下面的配置比 import/extensions 快几个数量级,因为它不执行磁盘查找,但是在上述 foo.js 模块等情况下它会出现误报。

英:The below config is several orders of magnitude faster than import/extensions as it does not do disk lookups, however it will false-positive on cases like the aforementioned foo.js module.

function banImportExtension(extension) {
const message = `Unexpected use of file extension (.${extension}) in import`;
const literalAttributeMatcher = `Literal[value=/\\.${extension}$/]`;
return [
{
// import foo from 'bar.js';
selector: `ImportDeclaration > ${literalAttributeMatcher}.source`,
message,
},
{
// const foo = import('bar.js');
selector: `ImportExpression > ${literalAttributeMatcher}.source`,
message,
},
{
// type Foo = typeof import('bar.js');
selector: `TSImportType > TSLiteralType > ${literalAttributeMatcher}`,
message,
},
{
// const foo = require('foo.js');
selector: `CallExpression[callee.name = "require"] > ${literalAttributeMatcher}.arguments`,
message,
},
];
}

module.exports = {
// ... other config ...
rules: {
'no-restricted-syntax': [
'error',
...banImportExtension('js'),
...banImportExtension('jsx'),
...banImportExtension('ts'),
...banImportExtension('tsx'),
],
},
};