Skip to content
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

Don't watch node_modules when using the FallbackWatcher #950

Merged
merged 3 commits into from
Apr 18, 2021
Merged

Don't watch node_modules when using the FallbackWatcher #950

merged 3 commits into from
Apr 18, 2021

Conversation

Gelio
Copy link
Contributor

@Gelio Gelio commented Apr 18, 2021

FallbackWatcher used in the language server was watching files in the node_modules and .git directories, which resulted in a V8 heap out of memory and unbearable performance when using the language server standalone, without VSCode (e.g. using neovim LSP).

Investigation

When using the svelte language server in neovim LSP I have noticed very poor performance (when asking for a hover message, I got it after a minute, with the language server crashing right after that).

I checked in ~/.cache/nvim/lsp.log that the language server was initializing a new TS server for each tsconfig.json it found in node_modules:

Logs with a V8 crash at the end
[ START ] 2021-04-18T13:18:21+0200 ] LSP logging initiated
[ ERROR ] 2021-04-18T13:18:22+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Initialize language server at  file:///home/voreny/projects/personal/supreme-trobot\n"
[ ERROR ] 2021-04-18T13:18:22+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Initialize new ts service at  /home/voreny/projects/personal/supreme-trobot/tsconfig.json\n"
[ ERROR ] 2021-04-18T13:18:22+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Trying to load configs for /home/voreny/projects/personal/supreme-trobot\n"
[ ERROR ] 2021-04-18T13:18:22+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Loaded config at  /home/voreny/projects/personal/supreme-trobot/svelte.config.js\n"
[ ERROR ] 2021-04-18T13:18:22+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "SnapshotManager File Statistics:\nProject files: 26\nSvelte files: 0\nFrom node_modules: 0\nTotal: 26\n"
[ ERROR ] 2021-04-18T13:18:23+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Using Svelte v3.37.0 from /home/voreny/projects/personal/supreme-trobot/node_modules/svelte/compiler\n"
[ ERROR ] 2021-04-18T13:18:26+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Using Svelte v3.37.0 from /home/voreny/projects/personal/supreme-trobot/node_modules/svelte/compiler\n"
[ ERROR ] 2021-04-18T13:18:26+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Initialize new ts service at  /home/voreny/projects/personal/supreme-trobot/node_modules/big-integer/tsconfig.json\n"
[ ERROR ] 2021-04-18T13:18:26+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Trying to load configs for /home/voreny/projects/personal/supreme-trobot/node_modules/big-integer\n"
[ ERROR ] 2021-04-18T13:18:26+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "SnapshotManager File Statistics:\nProject files: 7\nSvelte files: 0\nFrom node_modules: 7\nTotal: 7\n"
[ ERROR ] 2021-04-18T13:18:26+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Initialize new ts service at  /home/voreny/projects/personal/supreme-trobot/node_modules/chrome-launcher/tsconfig.json\n"
[ ERROR ] 2021-04-18T13:18:26+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Trying to load configs for /home/voreny/projects/personal/supreme-trobot/node_modules/chrome-launcher\n"
[ ERROR ] 2021-04-18T13:18:26+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "SnapshotManager File Statistics:\nProject files: 0\nSvelte files: 0\nFrom node_modules: 0\nTotal: 0\n"
[ ERROR ] 2021-04-18T13:18:29+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Initialize new ts service at  /home/voreny/projects/personal/supreme-trobot/node_modules/dotenv/types/tsconfig.json\n"
[ ERROR ] 2021-04-18T13:18:29+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Trying to load configs for /home/voreny/projects/personal/supreme-trobot/node_modules/dotenv/types\n"
[ ERROR ] 2021-04-18T13:18:29+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "SnapshotManager File Statistics:\nProject files: 4\nSvelte files: 0\nFrom node_modules: 4\nTotal: 4\n"
[ ERROR ] 2021-04-18T13:18:29+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Initialize new ts service at  /home/voreny/projects/personal/supreme-trobot/node_modules/fastq/test/tsconfig.json\n"
[ ERROR ] 2021-04-18T13:18:29+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Trying to load configs for /home/voreny/projects/personal/supreme-trobot/node_modules/fastq/test\n"
[ ERROR ] 2021-04-18T13:18:29+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "SnapshotManager File Statistics:\nProject files: 4\nSvelte files: 0\nFrom node_modules: 4\nTotal: 4\n"
[ ERROR ] 2021-04-18T13:18:29+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Initialize new ts service at  /home/voreny/projects/personal/supreme-trobot/node_modules/rxjs/src/tsconfig.json\n"
[ ERROR ] 2021-04-18T13:18:29+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Trying to load configs for /home/voreny/projects/personal/supreme-trobot/node_modules/rxjs/src\n"
[ ERROR ] 2021-04-18T13:18:30+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "SnapshotManager File Statistics:\nProject files: 681\nSvelte files: 0\nFrom node_modules: 681\nTotal: 681\n"
[ ERROR ] 2021-04-18T13:18:31+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Initialize new ts service at  /home/voreny/projects/personal/supreme-trobot/node_modules/@nodelib/fs.scandir/tsconfig.json\n"
[ ERROR ] 2021-04-18T13:18:31+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Trying to load configs for /home/voreny/projects/personal/supreme-trobot/node_modules/@nodelib/fs.scandir\n"
[ ERROR ] 2021-04-18T13:18:31+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "SnapshotManager File Statistics:\nProject files: 26\nSvelte files: 0\nFrom node_modules: 0\nTotal: 26\n"
[ ERROR ] 2021-04-18T13:18:31+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Initialize new ts service at  /home/voreny/projects/personal/supreme-trobot/node_modules/@nodelib/fs.stat/tsconfig.json\n"
[ ERROR ] 2021-04-18T13:18:31+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Trying to load configs for /home/voreny/projects/personal/supreme-trobot/node_modules/@nodelib/fs.stat\n"
[ ERROR ] 2021-04-18T13:18:31+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "SnapshotManager File Statistics:\nProject files: 26\nSvelte files: 0\nFrom node_modules: 0\nTotal: 26\n"
[ ERROR ] 2021-04-18T13:18:31+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Initialize new ts service at  /home/voreny/projects/personal/supreme-trobot/node_modules/@nodelib/fs.walk/tsconfig.json\n"
[ ERROR ] 2021-04-18T13:18:31+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Trying to load configs for /home/voreny/projects/personal/supreme-trobot/node_modules/@nodelib/fs.walk\n"
[ ERROR ] 2021-04-18T13:18:31+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "SnapshotManager File Statistics:\nProject files: 26\nSvelte files: 0\nFrom node_modules: 0\nTotal: 26\n"
[ ERROR ] 2021-04-18T13:19:15+0200 ] ...nt_nvimq7tYKQ/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "stylelint-lsp" "stderr"        "internal/modules/cjs/loader.js:883\n  throw err;\n  ^\n\nError: Cannot find module 'tslib'\nRequire stack:\n- /home/voreny/.nvm/versions/node/v14.15.0/lib/node_modules/stylelint-lsp/dist/index.js\n    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)\n    at Function.Module._load (internal/modules/cjs/loader.js:725:27)\n    at Module.require (internal/modules/cjs/loader.js:952:19)\n    at require (internal/modules/cjs/helpers.js:88:18)\n    at Object.<anonymous> (/home/voreny/.nvm/versions/node/v14.15.0/lib/node_modules/stylelint-lsp/dist/index.js:4:17)\n    at Module._compile (internal/modules/cjs/loader.js:1063:30)\n    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)\n    at Module.load (internal/modules/cjs/loader.js:928:32)\n    at Function.Module._load (internal/modules/cjs/loader.js:769:14)\n    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12) {\n  code: 'MODULE_NOT_FOUND',\n  requireStack: [\n    '/home/voreny/.nvm/versions/node/v14.15.0/lib/node_modules/stylelint-lsp/dist/index.js'\n  ]\n}\n"
[ ERROR ] 2021-04-18T13:19:28+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "\n<--- Last few GCs --->\n\n[303014:0x4fd39d0]    63589 ms: Mark-sweep (reduce) 2044.5 (2054.3) -> 2043.8 (2054.8) MB, 879.4 / 0.1 ms  (average mu = 0.104, current mu = 0.009) allocation failure scavenge might not succeed\n[303014:0x4fd39d0]    64830 ms: Mark-sweep (reduce) 2044.9 (2051.8) -> 2044.0 (2052.8) MB, 1234.1 / 0.1 ms  (average mu = 0.049, current mu = 0.006) allocation failure scavenge might not succeed\n\n\n<--- JS stacktrace --->\n\nFATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory\n"
[ ERROR ] 2021-04-18T13:19:28+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        " 1: 0xa03530 node::Abort() [node]\n"
[ ERROR ] 2021-04-18T13:19:28+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        " 2: 0x94e471 node::FatalError(char const*, char const*) [node]\n"
[ ERROR ] 2021-04-18T13:19:28+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        " 3: 0xb7773e v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [node]\n"
[ ERROR ] 2021-04-18T13:19:28+0200 ] ...nt_nvimzcvtFx/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        " 4: 0xb77ab7 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [node]\n"

Some debugging later, I found out that I was using the FallbackWatcher:

https://github.com/Gelio/language-tools/blob/597cafeaebb30348b787b52bdac61e17ae34f674/packages/language-server/src/server.ts#L103-L105

which in turn used chokidar to watch the whole workspace. AFAIK chokidar does not ignore any directories by default, so it rightfully went over all of node_modules, which ended up initializing multiple unnecessary TS servers

https://github.com/Gelio/language-tools/blob/597cafeaebb30348b787b52bdac61e17ae34f674/packages/language-server/src/plugins/typescript/service.ts#L55

With this change, the logs are more reasonable and I am able to use the language server, with the only TS server being initialized for my own project.

Logs
[ START ] 2021-04-18T13:51:37+0200 ] LSP logging initiated
[ ERROR ] 2021-04-18T13:51:38+0200 ] ...nt_nvim3XcrQN/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Initialize language server at  file:///home/voreny/projects/personal/supreme-trobot\n"
[ ERROR ] 2021-04-18T13:51:38+0200 ] ...nt_nvim3XcrQN/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Initialize new ts service at  /home/voreny/projects/personal/supreme-trobot/tsconfig.json\n"
[ ERROR ] 2021-04-18T13:51:38+0200 ] ...nt_nvim3XcrQN/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Trying to load configs for /home/voreny/projects/personal/supreme-trobot\n"
[ ERROR ] 2021-04-18T13:51:38+0200 ] ...nt_nvim3XcrQN/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Loaded config at  /home/voreny/projects/personal/supreme-trobot/svelte.config.js\n"
[ ERROR ] 2021-04-18T13:51:38+0200 ] ...nt_nvim3XcrQN/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "SnapshotManager File Statistics:\nProject files: 26\nSvelte files: 0\nFrom node_modules: 0\nTotal: 26\n"
[ ERROR ] 2021-04-18T13:51:39+0200 ] ...nt_nvim3XcrQN/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Using Svelte v3.37.0 from /home/voreny/projects/personal/supreme-trobot/node_modules/svelte/compiler\n"
[ ERROR ] 2021-04-18T13:51:42+0200 ] ...nt_nvim3XcrQN/usr/share/nvim/runtime/lua/vim/lsp/rpc.lua:457 ]  "rpc"   "svelteserver"  "stderr"        "Using Svelte v3.37.0 from /home/voreny/projects/personal/supreme-trobot/node_modules/svelte/compiler\n"

I assume the problem was not found before since the FallbackWatcher was not used extensively, as I assume when using the language server from within VSCode, it leverages VSCode's watcher, which ignored directories such as node_modules, .git, etc.

@dummdidumm
Copy link
Member

Your assumptions are exactly right. I think adding .git is a good idea. Adding node_modules as being anywhere in the file tree is possibly wrong though. Sapper apps use it to reference their files without adding path aliases, so there's src/node_modules. So the regex (or function) should ignore:

  • folders named node_modules, but not those below a src folder
  • .git folders

FallbackWatcher used in the language server was watching files in the
node_modules and .git directories, which resulted in a V8 heap out of
memory and unbearable performance when using the language server
standalone, without VSCode (e.g. using neovim LSP).
@Gelio
Copy link
Contributor Author

Gelio commented Apr 18, 2021

@dummdidumm Thanks, I did not know about such a use of node_modules.

I have modified the code a bit. I could not come up with a regexp that would match node_modules but would not match src/node_modules. I tried using lookbehinds, but I came to the conclusion that a function could be more readable.

The latest commit is still working well for me (neovim's LSP does not crash), but I did not explicitly test whether .git or stuff inside src/node_modules is being watched

@dummdidumm dummdidumm merged commit de1699f into sveltejs:master Apr 18, 2021
@Gelio Gelio deleted the ignore-node_modules-when-watching branch April 18, 2021 15:59
@rchl
Copy link

rchl commented Apr 21, 2021

as I assume when using the language server from within VSCode, it leverages VSCode's watcher, which ignored directories such as node_modules, .git, etc.

Do you know what exactly VSCode's built-in watcher does?

The relevant code from svelte extension is here:

fileEvents: workspace.createFileSystemWatcher('{**/*.js,**/*.ts}', false, false, false)

And the vscode watcher implementation is here: https://github.com/microsoft/vscode/blob/fd88b56ab91ed7f6a43ae98a010fa098226db636/src/vs/workbench/api/common/extHostFileSystemEventService.ts

But I haven't seen any indication that node_modules or such are ignored explicitly.

I'm wondering whether it ignores node_modules specifically or maybe rather git-ignored files...

@Gelio
Copy link
Contributor Author

Gelio commented Apr 21, 2021

@rchl Unfortunately, I don't have any answer for you, as I don't know and did not check that

@jasonlyu123
Copy link
Member

jasonlyu123 commented Apr 21, 2021

VSCode has a files.watcherExclude config. Probably it's related to this.

@rchl
Copy link

rchl commented Apr 21, 2021

VSCode has a files.watcherExclude config. Probably it's related to this.

Thanks!
So then the excluded patterns would be:

Windows: { '**/.git/objects/**': true, '**/.git/subtree-cache/**': true, '**/node_modules/*/**': true, '**/.hg/store/**': true }
Other platforms: { '**/.git/objects/**': true, '**/.git/subtree-cache/**': true, '**/node_modules/**': true, '**/.hg/store/**': true }

https://github.com/microsoft/vscode/blob/fd88b56ab91ed7f6a43ae98a010fa098226db636/src/vs/workbench/contrib/files/browser/files.contribution.ts#L240-L240

But then I wonder how this relates to the comment above as those patterns, I believe, ignore node_modules at any level.

EDIT: here is a glob tester: https://www.digitalocean.com/community/tools/glob?comments=true&glob=%2A%2A%2Fnode_modules%2F%2A%2A&matches=false&tests=%2Fnode_modules%2Ftest.js&tests=%2Fsrc%2Fnode_modules%2Ftest.js&tests=%2Ffoo%2Ftest.js

@dummdidumm
Copy link
Member

Good find. I guess that noone noticed this then yet. Since Sapper is deprecated and SvelteKit will not (ab)use node_modules anymore, it's not very relevant for much longer anyway.

@rchl
Copy link

rchl commented Apr 21, 2021

VSCode has a files.watcherExclude config. Probably it's related to this.

Looking at it a bit more... that setting seems to be related to WorkspaceWatcher and not FileSystemWatcher.

I'm not entirely convinced that those exclude patterns are also used when creating file watcher programmatically like many extensions do.

@jasonlyu123
Copy link
Member

I dig through the vscode codebase. It has a super complex file watching system. And this is what I found:

FileSystemWatcher is just an event emit/subscribe wrapper. It subscribes to the file system event of the extension host(ExtHostFileSystemEventService). Then filter by the provided glob pattern and file event to its consumer.

And the ExtHostFileSystemEventService is also piping the event from another service, IFileService. The default implementation seems to FileService

The WorkspaceWatcher also received FileService from DI. This is probably how it hooks to FileSystemWatcher.

As for the actual file watching, It seems to have multiple implementations in this watcher directory. VSCode also uses chokidar in some cases. I think we can also reference it to optimize our fallback watcher.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants