先週、チーム内のレガシーなモノレポ(ファイル数約12万、TypeScript)を新規参画メンバーのMacBook Proにクローンした瞬間、悲劇が起きました。「ファンが離陸しそうです」という報告と共に、VSCode(Visual Studio Code)が応答なしの状態に陥ったのです。アクティビティモニタを確認すると、Code Helper (Renderer)プロセスがCPUを300%以上消費し、メモリもみるみる食いつぶしていました。
通常、小規模なプロジェクトであればデフォルト設定のままでもサクサク動くのがvscodeの魅力ですが、エンタープライズ級の巨大なコードベースを扱う場合、その「親切すぎる」機能が仇となります。この記事では、私が現場で行ったパフォーマンスチューニングの全貌と、Electronベースのエディタが重くなる技術的な背景を共有します。単なるプラグインの紹介ではなく、レンダリングプロセスとLSP(Language Server Protocol)の挙動に基づいた「エンジニアのための」解決策です。
なぜVSCodeは「重く」なるのか:アーキテクチャの深層
根本原因を理解するには、VSCodeのアーキテクチャを理解する必要があります。VSCodeはElectron上で動作しており、UIスレッドと拡張機能ホスト(Extension Host)プロセスが分離されています。しかし、ファイル監視(File Watcher)とIntelliSense(コード補完)のためのインデックス作成は、設定次第でシステムリソースを食い尽くします。
今回のケースでは、以下のスペックのマシンで問題が発生しました。
- OS: macOS Sonoma 14.2
- Hardware: MacBook Pro M2 Pro, 32GB RAM
- Target Project: Next.js + NestJS Monorepo (ファイル数 120,000+)
- Symptoms: 入力遅延が2秒以上、Gitタブの更新が終わらない、保存時のフォーマットがタイムアウトする。
[error] The TypeScript language service died unexpectedly 5 times in the last 5 Minutes.
[warning] File Watcher is consuming high CPU. Consider excluding folders.
多くの開発者が陥る誤解は、「拡張機能を全部無効化すれば直る」というものです。確かに軽くなりますが、それではメモ帳を使っているのと変わりません。私たちはGit管理やLint、補完機能を維持しつつ、vscodeの無駄な処理だけを削ぎ落とす必要があります。
失敗したアプローチ:メモリ割り当ての増加のみ
最初に試みたのは、TypeScriptサーバーへのメモリ割り当てを増やすことでした。"typescript.tsserver.maxTsServerMemory": 8192を設定し、ヒープサイズを増やしました。これによりクラッシュは減りましたが、「重さ」自体は変わりませんでした。なぜなら、ボトルネックはメモリ不足ではなく、大量のファイルを監視し、解析しようとするI/OとCPU負荷にあったからです。巨大なnode_modulesやビルド生成物(dist, .next)まで監視対象になっていたのが最大のミスでした。
解決策:settings.jsonによる徹底的な除外設定
解決の鍵は、VSCodeに「何を見なくていいか」を明示的に教えることです。以下は、実際にパフォーマンスを劇的に改善させたsettings.jsonの設定です。
// .vscode/settings.json
{
// 1. ファイル監視の除外(最も効果が高い)
// システムのファイル監視リソース(inotify/fsevents)を節約します。
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/node_modules/**": true,
"**/dist/**": true,
"**/.next/**": true,
"**/tmp/**": true,
"**/coverage/**": true
},
// 2. 検索対象からの除外
// 全文検索(Cmd+Shift+F)の際にこれらをスキップします。
"search.exclude": {
"**/node_modules": true,
"**/package-lock.json": true,
"**/pnpm-lock.yaml": true,
"**/dist": true,
"**/.next": true
},
// 3. TypeScript/IntelliSenseの最適化
// 実験的な機能ですが、プロジェクト全体の診断を遅延させることで初動を軽くします。
"typescript.tsserver.experimental.enableProjectDiagnostics": false,
"typescript.tsserver.maxTsServerMemory": 4096,
// 4. エクスプローラーの表示除外(視覚的なノイズも減らす)
"files.exclude": {
"**/.DS_Store": true,
"**/.git": true,
"**/node_modules": true // ※注意:エクスプローラーから消えますが、importは可能です
}
}
特に重要なのがfiles.watcherExcludeです。これを設定しない場合、VSCodeはnode_modules内の何万というファイルの変更を常に監視しようとします。これを設定するだけで、CPU負荷は平常時に戻りました。
さらに、ワークスペース固有の設定として、使用していない推奨拡張機能を無効化する設定もextensions.jsonに追加すべきです。不要な拡張機能が裏で起動することを防ぎます。
| メトリクス | 対策前 (Before) | 対策後 (After) |
|---|---|---|
| CPU使用率 (Idle時) | 45% - 80% | 2% - 5% |
| IntelliSense応答速度 | 約 2.5秒 | 0.2秒 (瞬時) |
| 検索 (Cmd+Shift+F) | 15秒以上 (ハングアップ含む) | 0.5秒 |
表の結果を見てください。劇的な改善です。特に「検索」の速度向上は開発体験に直結します。以前はnode_modulesの中まで検索しに行っていたため時間がかかっていましたが、search.excludeを適切に設定することで、本当に探したいソースコードだけを一瞬で検索できるようになりました。
注意点と副作用:やりすぎには注意
設定を詰め込みすぎると、逆に不便になるケースがあります。以下のようなエッジケースに遭遇しました。
- ライブラリの中身が見れない:
files.excludeに**/node_modulesを入れると、ファイルツリーから消えます。「定義へ移動(Go to Definition)」は機能しますが、フォルダ構造を掘ってライブラリのソースを読みたい時に不便です。その場合はfiles.excludeからは外し、search.excludeとfiles.watcherExcludeだけに入れる運用がベストプラクティスです。 - 自動インポートが効かない: TypeScriptのプロジェクト設定(
tsconfig.json)でexclude設定を厳しくしすぎると、エディタが新しい型定義を見つけられなくなることがあります。
結論:道具を磨くこともエンジニアの仕事
「VSCodeが重いからマシンを買い換える」というのは、多くの場合、根本的な解決になりません。エディタが裏で何をしているのか、特にファイル監視とインデックス作成の仕組みを理解すれば、既存のマシンでも十分に快適な環境を作ることができます。
今回のチューニングにより、チーム全体の生産性は目に見えて向上しました。もしあなたのvscodeが悲鳴を上げているなら、まずは拡張機能を疑う前に、files.watcherExcludeの設定を見直してみてください。適切な設定こそが、最強の開発ツールを作る第一歩です。
さらに深いパフォーマンス分析を行いたい場合は、VSCode内のコマンドパレット(Cmd+Shift+P)から「Developer: Open Process Explorer」を開き、どのプロセスがリソースを食っているか特定することをお勧めします。これはシステム標準のアクティビティモニタよりも詳細な情報を提供してくれます。
Post a Comment