Hi there,
Since yesterday (I have Apollo GraphQL v1.5.2 and I think it is released since yesterday) my VS Code is really slow, like 10-20 seconds, when I use "Go to Definition" by ctrl + clicking, F12 or right-click -> "Go to Definition". I am using ubuntu, but my coworker with osx has the same problem.
If I disable Apollo GraphQL it's fast again, so I am pretty sure the performance leads back to this extension.
Can you reproduce the bug? If you need more details I am happy to help.
Version:
Apollo GraphQL 1.5.2
My VS Code:
Version: 1.31.1
Commit: 1b8e8302e405050205e69b59abb3559592bb9e60
Date: 2019-02-12T02:19:29.629Z
Electron: 3.1.2
Chrome: 66.0.3359.181
Node.js: 10.2.0
V8: 6.6.346.32
OS: Linux x64 4.15.0-45-generic
Noticed this as well over the past couple days - more broadly: all intellisense suggestions in typescript files, all go to definition commands, even find references are all excruciatingly slow. Disabling the Apollo GraphQL extension restores performance.
Tried profiling extensions before I realized this one was the culprit - here is a profile trying multiple times to get an intellisense suggestion to show up (with this extension enabled, version 1.5.2):
Interesting... I can't seem to reproduce this in 1.5.2. We also have some people with a huge number of types/fields in their projects that aren't seeing this, so I'm curious as to what could be causing it. Have either of you seen this happening in specific projects, or is it in any project of any size?
Actually our graph is not too big maybe 10 types and 50 fields (have to look at it tomorrow). Maybe it's because we have a lerna project and the apollo config file (for vs code) is in the root? @thearrow do you have lerna as well?
Happens to me as well. All autocomplete results are slow when this plugin is active.
Have to keep it disabled and only enable when actually working with graphql queries...
No lerna, single project, not a particularly large or complex graph. apollo.config.js is in the root of the project and it looks like this:
module.exports = {
client: {
name: "project_name",
service: {
url: "http://localhost:4000/graphql"
},
includes: ["frontend/src/**/*.{ts,tsx,js,jsx,graphql}"]
}
};
Yarn workspaces - the same issue. Go to definition and autocomplete in any TypeScript code can take ages when plugin is enabled.
Same issue here, go to definition and autocomplete become very slow (10-30 seconds) with the extension enabled, currently happening across two unrelated projects, both with quite small / simple graphs. My apollo.config.js:
module.exports = {
client: {
service: {
name: 'ProjectName',
url: 'http://localhost:3000/graphql',
},
includes: [
'**/*.tsx',
'./myproj/src/**/*.tsx'
],
},
}
Happy to share any logs etc which could be useful.
I have been debugging very slow "Go to Definition" and IntelliSense. I found out that another extension (Angular language service) was inflicting my results. So If the Angular extension was running _together_ with the Apollo extension, everything is painfully slow. But if only one of them is running at the time, everything is super fast. So maybe people in this thread can try to disable all other extensions in VS Code (>Extensions: Disable All Installed Extensions), enable Apollo, and then report the results?
I'm also having this issue. Go to definition takes about 10-15 seconds and if I hover any value that has a type I get ...loading. If I remove my apollo config it goes back to normal.
Here is my config:
module.exports = {
client: {
service: {
name: 'Our app',
url: 'http://local.company.xyz:3000/api/graphql',
},
includes: ['**/*.gql.ts', '**/*.graphql'],
},
};
I disabled all extensions and everything worked as expected. I then enabled Apollo the problems came back up.
I'm using Apollo GraphQL v1.7.1
I upgraded to TS v3.5.1 but that did not address the issue for me.
I have a private project (400K lines of JS, 40K lines of TypeScript) where this is happening, and the delay on Intellisense popup is specific to the number of files which exist in the includes glob.
Environment is MacOS 10.14.6, MacBook Pro 15" 2019, Node 12.13.
We have a backend, but it's not relevant - local schema (or invalid graphql URL) has the same effect.
module.exports = {
client: {
includes: [
"./src/**/*.graphql", // 5005 files, 4 second delay
"./src/apps/**/*.graphql", // 3005 files, 3 second delay
"./src/apps/used/**/*.graphql", // 450 files, <1 second delay
"./src/apps/used/landingPage.graphql", // no perceptible delay
"./src/does-not-exist.graphql",
],
service: {
url: "http://example.com/graphql",
},
},
};
I believe I've tracked it down to here:
https://github.com/apollographql/apollo-tooling/blob/master/packages/apollo-language-server/src/fileSet.ts#L37-L49
I stuck a couple console.logs in here. On each keystroke, this runs 4-8 times, at a cost of 300-320ms each time, which matches up pretty well with the total delay I'm seeing.
Could this be replaced with a dedicated file watching package like chokidar (or whatever the kids are using nowadays)?
Oh wow @threehams yeah that鈥檚 unacceptable. Good work here! I didn鈥檛 know this would be called that frequently. That鈥檚 definitely not good
Are you accepting PRs for this? Our workaround (select individual files in config) really isn't working out as we scale to more .graphql files across the project.
We're seeing this problem too.
I had assumed that we had just started to push VSCode to the limits, since our project is quite large. But after someone on my team pointed out this issue, I tried running without this extension enabled, and suddenly VSCode is vastly more responsive.
It would be great if this could get some attention ASAP. As this extension is currently the only viable solution that I know of for getting intellisense in gql statements.
Sorry for the non-response on this @threehams @mvestergaard. I'm the only one maintaining this right now, and I haven't had the time to devote to this (although I agree it's important). If either of you have any ideas as to how we can work on this, I'd love to discuss and review PRs
Hi all - just confirming that this is a real issue even with relatively small projects. Only workaround has been disabling and re-enabling the extension
All right, I took some time and figured it out, and it makes sense that this was harder to reproduce depending on configuration.
For at least one source of slowdown, the poor performance comes in only when a file you're working in has not been included / has been explicitly excluded from the project in apollo.config.js. The bug is here:
https://github.com/apollographql/apollo-tooling/blob/master/packages/apollo-language-server/src/workspace.ts#L241-L255
Since getting the full list of included files is very expensive, there's a cache set up in _projectForFileCache. This means that if the file you're working in is included in apollo.config.js, things are reasonably fast. If the file isn't, every keystroke runs projectForFile, misses the cache, and goes off and hits the filesystem to get a list of every file in the project multiple times. The bigger the project, the worse the delay.
Workaround: This is counterintuitive, but instead of narrowing the number of files included, make it as wide as possible. src/**/*.{tsx,graphql} is currently much quicker than src/**/*.graphql. This cleared up the performance problem in our (large) project.
Fix: I don't know the best way to fix this. The easiest solution is to cache "no project found" to make sure that "no project found" is cached when the file isn't part of the Apollo project. However, the solution could also be to move this cache to FileSet#allFiles() so there isn't a need for multiple levels of caching.
The problem is that I don't know how to correctly invalidate this cache (yet, I'm still looking). Any opinions / advice would be appreciated.
Workaround: This is counterintuitive, but instead of narrowing the number of files included, make it as wide as possible.
src/**/*.{tsx,graphql}is currently much quicker thansrc/**/*.graphql. This cleared up the performance problem in our (large) project.
This doesn't appear to be the only/primary reason for the slowness. Our project is configured the way you describe, and the editor is still significantly less responsive whenever this plugin is enabled.
Briefly looking over the code, I'm thinking the main culprit is the file globbing happening in FileSet each time something asks if a file is included, which is probably often.
This code should probably be changed to use a file system watcher instead. Caching won't really help, since you need to know about new files.
EDIT:
Yea that's definitely where things are happening. I added a simple console.log statement in that method, and it's hit about 8 times when the editor starts up, and when i trigger intellisense it's hit at least 8 more times. It's also hit once each time i move my cursor inside the editor, or hover my cursor over something.
I've added a PR that uses chokidar to watch for changes, and only perform the globbing the first time the FileSet is asked for files.
In my quick testing this cleared up all the issues for me.
I'm not sure if there are better approaches to this, but it's at least a suggestion.
@JakeDawkins Please take a look when you have the time. It would be great to get this issue resolved soon :)
Changing config was just a hopeful workaround for some people before the next release.
There's a file watcher available from vscode at workspace.createFileSystemWatcher, but you're going to have to be careful with setup/teardown of the watcher. FileSet gets recreated on the reload schema command, so just setting up the watcher inside that class will leak.
I tracked down the cause of this issue after wondering why includesFile was hitting the filesystem at all instead of using minimatch: https://github.com/apollographql/apollo-tooling/pull/1007/files#diff-4063d03ddad36e861a6924a3621e276cL30-L36.
Because of how we were using glob/minimatch on the includes/excludes, there were some issues:
includes/excludes that were relative (i.e. ./src/__tests__) would not work with FileSet.includesFile. To fix, includesFile now uses the results of allFiles (#1002)
excludes wasn't properly being filtered out in FileSet.allFiles, and wouldn't allow proper filtering if the glob was relative (the same issue that originally was in includesFile
Figuring out how to make minimatch work with relative globs would fix this without having to use file watching, because includesFile is the method that's getting hit over and over in the editor. allFiles only gets hit twice on start / config reload.
@threehams Yea I was thinking that something like that could be a problem when using file system watching.
Looking at the PR you linked, I'm kinda wondering whether that shouldn't just be reverted.
If the only point of that PR was to add a warning if no files were matched by the configured includes, then it's definitely not worth the performance hit involved.
It'll need a few changes, but yeah, I think we should go back to that behavior.
Can you test this change out locally? I'm on Windows at the moment, and this works.
includesFile(filePath: string): boolean {
filePath = `./${relative(this.rootURI.fsPath, normalizeURI(filePath))}`;
return (
this.includes.some(include => minimatch(filePath, include)) &&
!this.excludes.some(exclude => minimatch(filePath, exclude))
);
}
edit to support includes/excludes not starting with "./":
includesFile(filePath: string): boolean {
filePath = normalizeURI(filePath);
return (
this.includes.some(include => {
return minimatch(filePath, resolve(this.rootURI.fsPath, include));
}) &&
!this.excludes.some(exclude => {
return minimatch(filePath, resolve(this.rootURI.fsPath, exclude));
})
);
}
Yea, that appears to work. I'm on windows too though.
I'm fine with taking on this change, unless you want to. Based on some strange behavior of minimatch around ./ paths, and the amount of churn in includesFile, it's probably going to take a lot of testing.
@threehams No you go ahead, it's a better solution than the file system watcher :)
PR is out. I'll publish a fork of the extension - as soon as I figure out how to do that - since the Apollo team seems very busy with Apollo Client 3.0.
(edit: Hitting a bunch of errors trying to build before publish. Can't seem to find instructions for this, I'll struggle with it a bit more tomorrow.)
@threehams, @mvestergaard, @JakeDawkins - any updates? there seems to be a PR up - #1937 / #1938 - so wanted to check whether we could get a review for that, or a fork?
This has been significantly affecting my team for at least a month, and while I'm excited to finally understand the source, the workaround of "disable the extension when not in use" isn't very satisfying.
To give a bit more information on our setup:
[Trace - 12:02:03 PM] Sending notification 'textDocument/didClose'.
Params: {
"textDocument": {
"uri": "file:///<project path>/node_modules/typescript/lib/lib.dom.d.ts"
}
}
[Trace - 12:02:09 PM] Sending notification 'textDocument/didOpen'.
Params: {
"textDocument": {
"uri": "file:///<project path>/node_modules/typescript/lib/lib.dom.d.ts",
"languageId": "typescript",
"version": 1,
"text": <full text>
Our apollo.config.js's includes points to a subdirectory that doesn't have the node_modules, and I've tried adding node_modules/**/* to the excludes though that didn't help.
I think #1938 is probably a better solution than #1937, but will let whoever decides to take a look at this decide.
Supposedly they are too busy finishing up apollo client 3 atm to care about this. The extension is unusable until this is taken care of though.
My coworker published a fork of the extension under sunny-mittal.vscode-apollo:
Apollo VSCode
This contains two changes:
const query = gql<SearchQuery>`
query search {
...
}
`
The first is what you're looking for, and the second shouldn't affect you. So, it's available for now.
That's great, thank you! The second actually looks rather appealing. 馃槃
Republished as sunny-mittal.vscode-artemis since the last one looked way too close to the original extension. This one definitely won't be mistaken for anything official.
https://marketplace.visualstudio.com/items?itemName=sunny-mittal.vscode-artemis
馃敟 !! @threehams
Great name BTW 馃槃
Thanks for publishing that @threehams 馃檹 Did you get the minimatch issue resolved on that fork? It'd be great to get that fix updated in your PR if possible :)
There should be no minimatch issues in my PR.
Thanks! @threehams. It's definitely faster.
But I'm wondering if it could be a tad faster.
Our schema consists of 900 something types, and takes 5 seconds or so to get a field suggestion on a type. Might be because we're using VSCode server. Will report back.
This fork just fixes a specific performance issue: the filesystem is hit multiple times per second. That causes slowdown based on the size of the project, independent of the number of types.
Fixing this is likely going to expose other perf issues in other parts of the extension. There's a lot going on in there.
If you have problems outisde VS Code server, I can publish a version next week with trace output - that should help track down the new problem.
Oh right. You had this comment here about an issue you needed to fix? https://github.com/apollographql/apollo-tooling/pull/1938#issuecomment-625854479
Oh yeah, right. I have no idea how to make the test pass, and could use some advice there from the maintainers. It doesn't affect the functionality of the extension outside the tests, though.
+1
We need a fix for this.
Whenever the Apollo Extension is enabled, we can't save any files because code actions on save takes 30+ seconds to run. Without the extension, it's a breeze.
We're running a rather small project, but on Windows and with a Live Virus Scan going rampage through the project folders. This probably slows down stuff even more with the consistent filesystem accesss of the plugin.
@codepunkt In the meantime I'd recommend using the forked extension linked by threehams above https://marketplace.visualstudio.com/items?itemName=sunny-mittal.vscode-artemis
it drives me insane. No indication what is wrong with apollo. Hope a fix is released ASAP.
Its really a productivity killer.
threehams's solution is great.
Just here to say that this is definitely still an issue on the official version.
Even a small React project runs extremely poorly on my laptop when the official extension is enabled.
Most helpful comment
PR is out. I'll publish a fork of the extension - as soon as I figure out how to do that - since the Apollo team seems very busy with Apollo Client 3.0.
(edit: Hitting a bunch of errors trying to build before publish. Can't seem to find instructions for this, I'll struggle with it a bit more tomorrow.)