-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make type checking lint rules faster #1238
Comments
In #1114 (comment) @samreid said
"eslintConfig": {
"extends": "../chipper/eslint/sim_eslintrc.js",
"parserOptions": {
"project": [
"./tsconfig.json"
]
}
}
I just confirmed that works great for me too. Without that patch, running This works in sim repos but doesn't work in common code repos like scenery utterance-queue and sun, I am seeing lots of
|
Changing For example in utterance-queue I am seeing
Adding |
According to typescript-eslint/typescript-eslint#2094, typescript-eslint does not support project references, but they are experimenting with adding that as a feature. The workaround described in typescript-eslint/typescript-eslint#2094 (comment) indicates to list all projects explicitly, which I tried to do like so: parserOptions: {
sourceType: 'module',
// Provide a tsconfig so that we can use rules that require type information. tsconfig.eslint.json
// gives eslint project information without needing to modify our actual tsconfig setup.
// NOTE: Providing this slows down eslint substantially, see https://github.com/phetsims/chipper/issues/1114#issuecomment-1065927717
project: [ '../*/tsconfig.json' ]
}, Linting sims seemed to work OK and I was more confident it could read all source files for type checking. If I recall correctly, it took 20-30 seconds in checking a new repo, and was much faster for re-runs. When I tried to apply this to
It is still running to this day. |
A temporary flag to tap into this in added in typescript-eslint/typescript-eslint#2094 (comment) and reports suggest is it working well. It was added to the "canary" build, but if I understand correctly the canary build is just the one right before main so this flag could be in the main build by now.
|
Adding this to sun/package.json does seem to be working well: "overrides": [
{
"files": [
"**/*.ts"
],
"parserOptions": {
"project": [
"./tsconfig.json",
"./tsconfig-module.json"
],
"EXPERIMENTAL_useSourceOfProjectReferenceRedirect": true
}
}
] |
Some notes after playing with this for a while:
// Copyright 2022, University of Colorado Boulder
/**
* Modifies package.json for ALL repos under the project directory that have a package.json with overrides
* for eslintConfig. It adds a reference to the tsconfig.json files so that the repo can run typescript-eslint
* rules that leverage type information.
*/
const _ = require( 'lodash' ); // eslint-disable-line
const grunt = require( 'grunt' );
const fs = require( 'fs' );
/**
* Checks out master for all repositories in the git root directory.
* @public
*/
module.exports = function() {
const gitRoots = grunt.file.expand( { cwd: '..' }, '*' );
for ( let i = 0; i < gitRoots.length; i++ ) {
const filename = gitRoots[ i ]; // Don't change to const without rewrapping usages in the closure
if ( filename !== 'babel' && grunt.file.isDir( `../${filename}` ) && grunt.file.exists( `../${filename}/package.json` ) ) {
const rawData = fs.readFileSync( `../${filename}/package.json` );
const jsonData = JSON.parse( rawData );
if ( jsonData.eslintConfig ) {
if ( jsonData.eslintConfig.overrides ) {
console.log( 'found package.json with eslintconfig.overrides in ' + filename );
}
else {
const eslintConfigOverrides = [
{
files: [
'**/*.ts'
],
parserOptions: {
project: [
`../${filename}/tsconfig.json`,
`../${filename}/tsconfig-module.json`
]
}
}
];
// modify object in memory
jsonData.eslintConfig.overrides = eslintConfigOverrides;
// stringify in human readable format
const stringified = JSON.stringify( jsonData, null, 2 );
fs.writeFileSync( `../${filename}/package.json`, stringified );
}
}
}
}
};
EDIT: Oh and here is my chipper patch as well as my change to center-and-variability to test in a single repo. CHipper patch: Index: eslint/.eslintrc.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/eslint/.eslintrc.js b/eslint/.eslintrc.js
--- a/eslint/.eslintrc.js (revision 61879822b0e749dce4849d2ee6324b1144b73166)
+++ b/eslint/.eslintrc.js (date 1652131330699)
@@ -25,12 +25,16 @@
],
parser: '@typescript-eslint/parser',
parserOptions: {
- sourceType: 'module'
+ sourceType: 'module',
// Provide a tsconfig so that we can use rules that require type information. tsconfig.eslint.json
// gives eslint project information without needing to modify our actual tsconfig setup.
// NOTE: Providing this slows down eslint substantially, see https://github.com/phetsims/chipper/issues/1114#issuecomment-1065927717
- // ,project: [ '../chipper/eslint/tsconfig.eslint.json' ]
+ // project: [ '../chipper/eslint/tsconfig.eslint.json' ],
+ project: [ '../chipper/tsconfig.json' ],
+
+ // Enable experimental project references feature of typescript-eslint.
+ EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true
},
plugins: [
'@typescript-eslint'
@@ -78,13 +82,13 @@
// '@typescript-eslint/no-empty-function': 'error', // 41 errors
'@typescript-eslint/no-extra-semi': 'error',
// '@typescript-eslint/no-unused-vars': 'error', //TODO https://github.com/phetsims/chipper/issues/1230
- '@typescript-eslint/no-loss-of-precision': 'error'
+ '@typescript-eslint/no-loss-of-precision': 'error',
///////////////////////////////////////////////////////////////////////
//
// Typescript rules that require type information (may be slow)
// These require parserOptions.project.
- // '@typescript-eslint/no-unnecessary-type-assertion':'error',
+ // '@typescript-eslint/no-unnecessary-type-assertion': 'error'
// '@typescript-eslint/no-unsafe-member-access':'error',
// '@typescript-eslint/restrict-plus-operands':'error',
// '@typescript-eslint/prefer-readonly': 'error' // readonly when possible
@@ -100,7 +104,7 @@
// '@typescript-eslint/no-unsafe-call': 'error',
// '@typescript-eslint/no-unsafe-member-access': 'error',
// '@typescript-eslint/no-unsafe-return': 'error',
- // '@typescript-eslint/restrict-plus-operands': 'error',
+ '@typescript-eslint/restrict-plus-operands': 'error',
// '@typescript-eslint/restrict-template-expressions': 'error',
// '@typescript-eslint/unbound-method': 'error',
Center and variability patch: Index: package.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/package.json b/package.json
--- a/package.json (revision f9176187ad52720c03ddc06c2e656979b7cb56f3)
+++ b/package.json (date 1652131124861)
@@ -29,6 +29,19 @@
}
},
"eslintConfig": {
- "extends": "../chipper/eslint/sim_eslintrc.js"
+ "extends": "../chipper/eslint/sim_eslintrc.js",
+ "overrides": [
+ {
+ "files": [
+ "**/*.ts"
+ ],
+ "parserOptions": {
+ "project": [
+ "../center-and-variability/tsconfig.json"
+ ]
+ }
+ }
+ ]
}
}
\ No newline at end of file
|
Now that we don't use project references we should try this again and see if this is faster. #1238 (comment) probably isn't relevant anymore because of this. |
|
Increasing priority, since I hope to look into this during this week. |
It is much faster! Well done @samreid. Timing results below. However, there is still a problem with I changed
IF memory isn't a problem at 10-30 seconds per repo maybe UPDATE: However, I see many errors like
EDIT: It is resolved if |
I added "parserOptions": {
"project": [
"../ohms-law/tsconfig.json"
]
} to all package.jsons and ran lint-everything again. After 1min 48 seconds I got an out of memory error. It seems to me that #1238 (comment) still applies. We may be able to use a different implementation of the grunt But the best case scenario would be a ~30 minute run time for the command when there is no cache. That doesn't seem worth pursuing. |
@samreid and I met to try more things:
Alternatively could we add this to each repo's package.json so that tsc doesn't get slower? "eslintConfig": {
"extends": "../chipper/eslint/sim_eslintrc.js",
"overrides": [
{
"files": [
"**/*.ts"
],
"parserOptions": {
"project": [
"../acid-base-solutions/tsconfig.json"
]
}
}
]
} That wont make lint-everything any faster. |
I did this with just the a-b sims in active-repos and ran out of memory before 2 minutes. Otherwise that works, there were no other problems running lint. EDIT: I tried this change to lint-everything task and still ran out of memory around build-a-molecule Index: js/grunt/Gruntfile.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/grunt/Gruntfile.js b/js/grunt/Gruntfile.js
--- a/js/grunt/Gruntfile.js (revision 01b78de7541b9622ce7e2fbeb9544f78a46c14a3)
+++ b/js/grunt/Gruntfile.js (date 1653003330654)
@@ -516,10 +516,14 @@
// Don't always require this, as we may have an older chipper checked out. Also make sure it is the promise-based lint.
const lint = require( '../../../chipper/js/grunt/lint' );
if ( lint.chipperAPIVersion === 'promises1' ) {
- await lint( activeRepos.map( repo => `../${repo}` ), {
- cache: cache,
- fix: fix,
- format: format
+ const lintables = activeRepos.map( repo => `../${repo}` );
+ lintables.forEach( async lintable => {
+ console.log( 'linting ', lintable );
+ await lint( [ lintable ], {
+ cache: cache,
+ fix: fix,
+ format: format
+ } );
} );
}
} ) ); |
I tried https://typescript-eslint.io/docs/linting/monorepo/
But it failed after about 4 minutes with an out of memory error. |
I tried
Running |
Good experiments! I also ran a few tests. I wanted to see the performance characteristic of running the idiomatic way described on https://eslint.org/docs/user-guide/command-line-interface which is to run:
Which I think only works because I have a node_modules as a sibling of my checkout repos. I also tried with and without For these tests, I enabled Using tsconfig/all and no cache: 11.6s Using "eslintConfig": {
"extends": "../chipper/eslint/sim_eslintrc.js",
"overrides": [
{
"files": [
"**/*.ts"
],
"parserOptions": {
"project": [
"../gravity-and-orbits/tsconfig.json"
]
}
}
]
} without cache: 3.1s The latter result seems fast enough that we could use it for linting in the IDE and for precommit hooks, etc. We could split up chipper/js/grunt/lint.js so it is more repo-oriented if we like this approach. @jessegreenberg based on the results in your experiment and this one, how do you think we should proceed? |
Or can we just dynamically set the "project" flag based on the "patterns" parameter? |
…require project information, see #1238
That is quite fast! Good to know.
Yes, that is what I was thinking too. I went ahead and added an option for the lint task called It seems to work well. It would be simple to use these for git hooks. But I couldn't figure out a way to get this strategy to work with the IDE. @samreid can you please review this change? Do you see a way to make this work with the IDE without breaking |
I tested looping over each repo like so and it seemed to have good characteristics (including running lint-everything faster), we may want to base our strategy on this. Stashing a copy to clean my working copy. Index: js/grunt/Gruntfile.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/grunt/Gruntfile.js b/js/grunt/Gruntfile.js
--- a/js/grunt/Gruntfile.js (revision a886e4d2ddae82503a9acb30753079987edfb687)
+++ b/js/grunt/Gruntfile.js (date 1653972435290)
@@ -516,11 +516,13 @@
// Don't always require this, as we may have an older chipper checked out. Also make sure it is the promise-based lint.
const lint = require( '../../../chipper/js/grunt/lint' );
if ( lint.chipperAPIVersion === 'promises1' ) {
- await lint( activeRepos.map( repo => `../${repo}` ), {
- cache: cache,
- fix: fix,
- format: format
- } );
+ for ( let i = 0; i < activeRepos.length; i++ ) {
+ await lint( [ activeRepos[ i ] ], {
+ cache: cache,
+ fix: fix,
+ format: format
+ } );
+ }
}
} ) );
</details. |
That is promising but I don't think that patch is linting anything. The lint command should be await lint( [ `../${activeRepos[ i ]}` ], { I tried this with type checking lint rules in #1238 (comment) but ran out of memory. |
In the commit, I enabled |
Today I'm noticing that my git hooks are slower by a factor of 3-5. I suspect it is from this change. I would recommend reverting it until we know for sure that a lint rule in this list is worth the great productivity hit I've experienced. That said, during the typescript sprint I am making many more cross-repo commits than usual. |
Understood. Lets check in tomorrow or at dev meeting with the team. We have options for how to proceed:
|
@jessegreenberg, @samreid and I discussed this in depth this afternoon. RE: 1. We want these lint rules to work in the IDE, so this won't work. RE: 2. Not ideal, we as a team most often error on the side of overly cautious, even at the cost of time. RE: 3. We spent a fair bit of time on this today, investigating the "individual repo" linting strategy with the patch in #1238 (comment). We also found that most of the time has to do with the tsc command in the pre-commit hook, and not lint. RE: 4. This seems like the best path forward for maximum productivity. We want to investigate further. At the very least it can be something that members opt into, disabling their pre-commit hooks in exchange for using a script to push-all + a hook script. |
Next steps:
@jessegreenberg perhaps we are ready to close this issue when you have cleaned up? |
|
We touched on this in during developer meeting today. There is nothing more to do here. Pre-commit hooks take still take longer. and we discussed #1269 as a workflow change to improve productivity. See #1269 (comment), we will continue there. |
…require project information, see phetsims/chipper#1238
…require project information, see phetsims/chipper#1238
…require project information, see phetsims/chipper#1238
From #1114. Lint rules that use type checking are too slow. They will be slower because they use the type checker but currently they are just way too slow to use.
Maybe we can make it faster by having eslint use the same tsc cache as WebStorm. The config file
tsconfig.eslint.json
is really inefficient. I think it makes eslint recompile every file in the project every time the linter is run. Maybe we can make that better.The text was updated successfully, but these errors were encountered: