Closed IlCallo closed 2 years ago
Thank you for reporting this issue. I hope this explanation will help you with debugging:
Starting from version 5, eslint has its own process, separate from typescript checker. It means that eslint configuration should not affect typescript check time (except IO as the file system is shared) and vice versa. It can slow down the time to show issues as it uses Promise.all
but not the check itself.
Currently, we don't have implemented profiling for vue extension and for eslint. I can add it - maybe it would help you to find the issue.
Also, I think there is lack of documentation on how to set up eslint for .vue files. By default, the plugin sets:
options: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
}
which doesn't include .vue
files. You can overwrite this by passing it as eslint.options.extensions
Consider that the problem isn't probably related to ESLint. As I specified, the problem comes up even when linting isn't even enabled.
That let apart, I think I tried the linter with Vue files and I seem to recall that it worked anyway (probably because it got up the eslint configuration).
After a lot of trial and errors, I noticed that removing some ts aliases solved the issues.
In particular components
, pages
and layouts
.
Gonna study a bit what's happening there and what do they have in common
EDIT: tried to add eslint
options as you said, no effect
~EDIT2: can confirm Vue linting isn't actually working, even if I add .vue
extension into the options as you proposed~
EDIT3: note that all 3 those aliases usually references Vue files, there could be some problems in that area
EDIT4: forget about EDIT3, Vue linting is working ok (even without the additional options you wrote before)
Cool, thanks for digging into this 👏 I would like to help, but it's hard without a reproduction repository.
You can clone the plugin repository and add performance.markStart
and performance.markEnd
in the vue extension to check if it's a bottleneck. The example usage is in the TypeScriptReporter
. Then you can build it (yarn build
) and link it to your project (using yarn link
).
I have to admit that we don't have end-to-end tests for .vue linting. The assumption is that eslint linter should be capable of doing everything that eslint
command is capable of. I'm not a Vue.js developer, so I'm not familiar with the eslint support for .vue
files. Is it something that eslint
command handles well, but the plugin doesn't?
I added a new edit on previous message: seems like I was doing something wrong in tsconfig, Vue linting works as expected even without the extension options you mentioned.
Right now, I managed to make my project work (and it's blazing fast!) with this configuration:
{
"extends": "@quasar/app/tsconfig-preset",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"src/*": ["src/*"],
"app/*": ["*"],
// "components/*": ["src/components/*"],
// "layouts/*": ["src/layouts/*"],
// "pages/*": ["src/pages/*"],
"assets/*": ["src/assets/*"],
"boot/*": ["src/boot/*"]
}
}
}
We're gonna release q/app v2 (which will support this package both v4 and v5) and try to gather more examples on the wild to pinpoint the issue. Also, it will be easier for us to provide some repro when v2 is officially out.
Gonna try what you suggested next week.
If this could ring some bell to you, our current investigative trail (lol) brought us to vue-router
files and it's dynamic import syntax for layouts and pages. Components could be affected indirectly because loaded by layouts an pages? Maybe it's something not working related to dynamic imports and dependencies of files retrieved in that way?
Example:
const routes: RouteConfig[] = [
{
path: '/',
redirect: () => ({ name: isAuthenticated() ? 'home' : 'login' })
},
{
path: '/',
component: () => import('layouts/guest.vue'),
beforeEnter: redirectIfAuthenticated,
children: [
{
path: 'login',
name: 'login',
component: () => import('pages/login.vue')
},
{
path: 'forgot-credentials',
name: 'forgot-credentials',
component: () => import('pages/forgot-credentials.vue')
}
]
},
{
path: '/',
component: () => import('layouts/authenticated.vue'),
beforeEnter: redirectIfGuest,
children: [
{ path: 'home', name: 'home', component: () => import('pages/home.vue') },
{
path: 'statistics',
name: 'statistics',
component: () => import('pages/statistics.vue')
},
{
path: 'registry',
name: 'registry',
component: () => import('pages/registry.vue')
},
{
path: 'administration',
name: 'administration',
component: () => import('pages/administration.vue'),
beforeEnter(to, from, next) {
if (!isAdmin()) {
next(false);
} else {
next();
}
}
}
]
}
];
Hmm... Hard to tell if dynamic imports can be an issue. We use standard TypeScript API, with a custom fileExists
and readFile
functions which interpret src/some-file.vue.ts
as src/some-file.vue
(because TypeScript doesn't support custom extensions and import 'src/some-file.vue';
can be resolved only to src/some-file.vue.ts
, src/some-file.vue.tsx
, or src/some-file.vue.js
). I've opened https://github.com/microsoft/TypeScript/issues/38736 proposal to allow compiler plugins for better Vue.js support, so you can give a 👍 there to let know TypeScript team that this is a desired feature. So we don't hack around import statements.
"app/*": ["*"],
looks suspicious for me - maybe it makes other aliases hard to resolve in the TypeScript?
Liked the proposal :+1: Will let you know next week if I discover something more.
I don't think it's about "app/*": ["*"]
, the problem was still there when I disabled everything except the 3 paths I mentioned yesterday. Also, it's a pretty popular path alias, even if you usually find it as ~/*
or @/*
instead
@piotr-oles
Also, I think there is lack of documentation on how to set up eslint for .vue files. By default, the plugin sets:
options: { extensions: ['.ts', '.tsx', '.js', '.jsx'], }
which doesn't include
.vue
files. You can overwrite this by passing it aseslint.options.extensions
I'm hijacking this issue but wanted to say: this ☝️
Just randomly noticed my vue files aren't linted and was trying to figure out why. Glad I found this.
It would be nice to add a note in the Vue section of the readme, or even better, add .vue
automatically to the default extensions when Vue support is enabled.
It would be nice to add a note in the Vue section of the readme,
Would you like to submit a PR?
Finally got little time to come back at this. I see you added some items to the time stats, here what do I get now with dev
mode
Parse Configuration: 0.10 s
Create Watch Compiler Host: 0.00 s
I/O Read: 0.15 s
Parse: 2.98 s
ResolveTypeReference: 0.07 s
ResolveModule: 1.35 s
Program: 4.77 s
Bind: 3.77 s
Check: 10.06 s
transformTime: 150.53 s
Emit: 153.74 s
Semantic Diagnostics: 164.09 s
Create Watch Program: 172.81 s
Poll And Invoke Created Or Deleted: 0.07 s
Queued Tasks: 0.00 s
and build
mode
Parse Configuration: 0.07 s
Create Watch Compiler Host: 0.00 s
I/O Read: 0.24 s
Parse: 2.68 s
ResolveTypeReference: 0.08 s
ResolveModule: 1.45 s
Program: 4.66 s
Bind: 2.84 s
Check: 7.49 s
transformTime: 139.46 s
Emit: 142.29 s
Will continue my debugging next week and let you know if I discover something new
Some comments on DX:
yarn link
give some problems (mostly about "I cannot find module X, Y and Z"), got better luck with yarn add
package.json > version
and the exported version const are placeholders. Not a major problem, but it could cause confusion during development of tools (as Quasar) which tries to detect the version of the packageI tried to add a Vue-related performance measurements, but seems like I'm missing something obvious:
performance
instance into https://github.com/TypeStrong/fork-ts-checker-webpack-plugin/blob/65ab0cc994b627648fb872a8ced33de33808efc3/src/typescript-reporter/extension/vue/TypeScriptVueExtension.ts#L20 didn't workmarkStart
and markEnd
calls didn't work (random guess, those calls are considered only when a performance.enable()
has been called before?)extension
array)Meanwhile I enabled all diagnostic options like this
typescript: {
extensions: {
vue: true
},
diagnosticOptions: {
syntactic: true,
semantic: true,
declaration: true,
global: true
},
profile: true
},
eslint: {
files: './**/*.{ts,js,vue}'
},
logger: {
infrastructure: 'console'
}
and got
Parse Configuration: 0.06 s
Create Watch Compiler Host: 0.00 s
I/O Read: 0.14 s
Parse: 2.49 s
ResolveTypeReference: 0.06 s
ResolveModule: 1.14 s
Program: 4.02 s
Bind: 2.67 s
Syntactic Diagnostics: 0.23 s
Global Diagnostics: 0.01 s
Check: 7.81 s
transformTime: 307.87 s
Emit: 155.59 s
Semantic Diagnostics: 163.66 s
I cannot find some marks name in the codebase (transformTime
, Emit
, etc) so I guess those comes directly from TS via getDiagnosticsOfBuilderProgram
method calls.
Notice that Declaration Diagnostics
isn't present even if should. Dunno what does this mean.
Any idea on how to proceed further?
I'm exploring TS perf issues world, seems there are quite a bit slowdown problems around. First two I found:
It may be something related to Quasar types? Does this ring any bell? Dunno why the problem appears only on v5 and not v4 tho
Running ./node_modules/.bin/tsc --noEmit false --declaration --emitDeclarationOnly --extendedDiagnostics
finish in 13s only, so I'm pretty sure the problem is in Vue files (which are checked only after webpack transformation)
Fascinating - I hadn't heard of "Quasar types"
I mean, Quasar Framework typings:
(Or was it some pun I didn't get :thinking: )
More specific question: any idea on how I can start profiling TS stuff while is being processed by the plugin (or before, or after, anything), both in v4 and v5?
Although it's primitive - simply hacking in console.log
statements will get you a long way. It's surprisingly effective even if you feel that "there must be a better way"
Hi team,
+1 on the compilation time (but there is so much involved I'm not sure where it comes from).
Once thing I share with the initial issue is that it reports error for .scss
which really should not be parsed by eslint as the default extensions suggest.
I suspect some glob is too greedy.
new ForkTsCheckerWebpackPlugin({
typescript: {
enabled: true,
configFile: 'tsconfig.json',
build: true,
mode: 'readonly',
diagnosticsOptions: false,
compilerOptions: {
skipLibCheck: true,
}
},
eslint: {
enabled: production ? false : true,
files: './src/**/*',
},
})
[...100s of...]
ERROR in src/views/[...]/index.scss
[unknown]: Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: src/views/[...]/index.scss.
The extension for the file (.scss) is non-standard. You should add "parserOptions.extraFileExtensions" to your config.
On Quasar framework part, we decided to wait a bit to see if someone else bump into this, as I'm just running in circles when trying to debug this problem and we must focus on some other features. Will come back to this problem in some months and start debugging again!
Just wanted to chime in and bump this.
This plugin seemed fine on 5.2.0 for a while till my own project grew, and then some kind of threshold occurred and it exploded in compile time.
Seems related to MobxStateTree & MaterialUI, which are known for their complex types.
Edit:
tsc
builds in under 12s, while the plugin takes ~30minutes now (120% cpu).
tsc --watch
also hangs for me, so this could be an upstream issue https://github.com/microsoft/TypeScript/issues/25023
Seems related to MobxStateTree & MaterialUI, which are known for their complex types.
Would be ideal to see if TypeScript@4.1.0's extended perf profiling features can be integrated here to map long
We use the same API as the tsc --watch
so it seems to be a source of the problem
We use the same API as the
tsc --watch
so it seems to be a source of the problem
@piotr-oles have you looked into supporting https://github.com/microsoft/TypeScript/issues/40124 4.1.0's new profiling outputs?
More info here https://github.com/microsoft/TypeScript/pull/40063
A projects file paths could be mapped to the types.json/trace.json output, then rendered as a ordered list or tree based on costs.
Might even make sense to emit a warning based on a threshold for type resolution time to let the user know when a new dependency or interface has a large impact.
@nfour I've added a support for "generateTrace" in 6.0.0-alpha.2 :)
Good! We're working on Quasar v2 (with Vue3 support) which means we'll have to migrate to 5+ version of fork-ts-checker. I'll probably have to come back on this problem in next couple months and check if I can finally find the root cause, any additional tracing tool could be useful!
@nfour I've added a support for "generateTrace" in 6.0.0-alpha.2 :)
https://github.com/nfour/ts-rank whipped this up to quickly parse generateTrace and show some useful numbers. Still early tho but I've used it to fix some perf issues already.
For my setup this slow down seems to mainly come from eslint, I guess it doesn't work fine with webpack 5's cache.
Initial build | Second build | |
---|---|---|
Entire plugin disabled | 54689 ms | 6217 ms |
eslint.enabled: false
| 54045 ms | 16519 ms |
eslint.enabled: true
| 114185 ms | 112230 ms |
@IlCallo The newest TypeScript Beta version contains a fix that could potentially address some of these performance issues. Could you test it?
Hey there, you mean TS 4.3 beta? What fix in particular should be useful in our case?
Also, with are in the verge of releasing Quasar v2 (and @quasar/app
v3) based on Vue3 and webpack 5, we updated this package dependency to v6 directly.
The project I used for this issue reproduction unluckily still have some blockers while migrating to Quasar v2 so I cannot test it right now.
Since we released Quasar v2 beta, only a person reported this same problem, but he too could not pin-point the problem.
Will try to finish my project migration to Quasar v2 and try it out again
@piotr-oles @johnnyreilly , is the latest version of fork-ts-checker-webpack-plugin compatible with webpack 5 ?
yes, we have e2e tests that uses webpack 5
I believe that this is related https://github.com/TypeStrong/fork-ts-checker-webpack-plugin/issues/612
I cannot reproduce anymore the problem after migrating to Quasar v2, which uses Webpack5 and latest version of this package Closing this since my original problem seems to be solved
Current behavior
We are about to release Quasar Framework CLI v2 (
@quasar/app
), and really want to integrate fork-ts-checker new version. We are testing it on real world (private) projects and I noticed an extreme (talking about some minutes, 18s vs 183s) slowdown of production compilation in a particular scenario, for which I cannot pin-point the cause.I could use some guidance, because the behaviour I'm experiencing is pretty random and don't know how do debug it further. Right now my instinct tells me there is something wrong with our configuration of v5 and the tsconfig.json file, probably because we add and configure the plugin into
@quasar/app
and not into a webpack config file into the project root.~Or some kind of incompatibility with
@typescript-eslint
pre v3~ EDIT: nope, upgraded to v3 and problem persist. Also, clean test project didn't had problems with pre v3Enabling
typescript.profile
using the only configuration which avoids the slowdown (see below) produce no output. Enablingtypescript.profile
when the problem is present I got thisReverting to
v4.1.6
fixes the problem, so I'm fairly sure the problem is in the new major version (or our configuration).This is how we internally enable TS support into the Quasar webpack chain: https://github.com/quasarframework/quasar/blob/9133883bb3f2a3764b697bad8ffc5e313502c4ea/app/lib/webpack/create-chain.js#L154-L182
Notice we always include vue ts support into the options via webpack chain as
In Quasar configuration we allow the user to customize your plugin options like
Into our starter kit we automatically setup the configuration depending on initial user choices: https://github.com/quasarframework/quasar-starter-kit/blob/19bd2ec30086d1086b7e44929bed71273d3d41a4/template/quasar.conf.js#L26-L33
Experiments till now
With no eslint configuration, the problem persist
With eslint enabled and this
eslint.files
glob patterns the problem is solved but I get the error below error, no lint error is displayed for Vue and TS files andtypescript.profile
output is not shown. All this stuff makes me think nothing is actually being processed and that's why there's no slowdown.With eslint enabled and this
eslint.files
glob patterns the problem persist and I get an error for any extension@typescript-eslint
cannot process and for all Vue files. This last bit is strange, because Vue files are marked to be processed. One more point on the "there's something strange with tsconfig.json" path.Ex.
With eslint enabled and this
eslint.files
glob patterns the problem persist.Miscellaneous info
The project tsconfig is in the project root folder and extends the preset provided by Quasar (https://github.com/quasarframework/quasar/blob/dev/app/tsconfig-preset.json)
I'm using Vue Composition API package (v0.5 right now), but the clean Quasar project I created uses it too and doesn't seems to be affected.
Expected behavior
Avoid slowdown.
Steps to reproduce the issue
I'm not able to replicate the problem with a fresh Quasar project using latest unreleased packages and starter kit.
Environment