feat: support heap profile and snapshot capture for tsserver

This commit is contained in:
deepak1556
2026-03-04 01:32:36 +09:00
parent 1b92648d63
commit 278032fc75
4 changed files with 124 additions and 0 deletions

View File

@@ -2556,6 +2556,16 @@
"TypeScript"
]
},
"js/ts.tsserver.diagnosticDir": {
"type": "string",
"markdownDescription": "%configuration.tsserver.diagnosticDir%",
"scope": "window",
"keywords": [
"TypeScript",
"diagnostic",
"memory"
]
},
"typescript.tsserver.maxTsServerMemory": {
"type": "number",
"default": 3072,
@@ -2563,6 +2573,48 @@
"markdownDeprecationMessage": "%configuration.tsserver.maxTsServerMemory.unifiedDeprecationMessage%",
"scope": "window"
},
"js/ts.tsserver.heapSnapshot": {
"type": "number",
"default": 0,
"minimum": 0,
"markdownDescription": "%configuration.tsserver.heapSnapshot%",
"scope": "window",
"keywords": [
"TypeScript",
"memory",
"diagnostics"
]
},
"js/ts.tsserver.heapProfile": {
"type": "object",
"default": {
"enabled": false
},
"markdownDescription": "%configuration.tsserver.heapProfile%",
"scope": "window",
"properties": {
"enabled": {
"type": "boolean",
"default": false,
"description": "%configuration.tsserver.heapProfile.enabled%"
},
"dir": {
"type": "string",
"description": "%configuration.tsserver.heapProfile.dir%"
},
"interval": {
"type": "number",
"minimum": 1,
"description": "%configuration.tsserver.heapProfile.interval%"
}
},
"keywords": [
"TypeScript",
"memory",
"heap",
"profile"
]
},
"js/ts.tsserver.watchOptions": {
"description": "%configuration.tsserver.watchOptions%",
"scope": "window",

View File

@@ -126,6 +126,12 @@
"configuration.tsserver.maxTsServerMemory": "The maximum amount of memory (in MB) to allocate to the TypeScript server process. To use a memory limit greater than 4 GB, use `#js/ts.tsserver.node.path#` to run TS Server with a custom Node installation.",
"configuration.tsserver.maxTsServerMemory.unifiedDeprecationMessage": "This setting is deprecated. Use `#js/ts.tsserver.maxMemory#` instead.",
"configuration.tsserver.maxMemory": "The maximum amount of memory (in MB) to allocate to the TypeScript server process. To use a memory limit greater than 4 GB, use `#js/ts.tsserver.node.path#` to run TS Server with a custom Node installation.",
"configuration.tsserver.diagnosticDir": "Directory where TypeScript server writes Node diagnostic output by passing `--diagnostic-dir`.",
"configuration.tsserver.heapSnapshot": "Controls how many near-heap-limit snapshots TypeScript server writes by passing `--heapsnapshot-near-heap-limit`. Set to `0` to disable.",
"configuration.tsserver.heapProfile": "Configures heap profiling for TypeScript server.",
"configuration.tsserver.heapProfile.enabled": "Enable heap profiling for TypeScript server by passing `--heap-prof`.",
"configuration.tsserver.heapProfile.dir": "Directory where TypeScript server writes heap profiles by passing `--heap-prof-dir`.",
"configuration.tsserver.heapProfile.interval": "Sampling interval in bytes for TypeScript server heap profiling by passing `--heap-prof-interval`.",
"configuration.tsserver.experimental.enableProjectDiagnostics": "Enables project wide error reporting.",
"configuration.tsserver.experimental.enableProjectDiagnostics.unifiedDeprecationMessage": "This setting is deprecated. Use `#js/ts.tsserver.experimental.enableProjectDiagnostics#` instead.",
"typescript.locale": "Sets the locale used to report JavaScript and TypeScript errors. Defaults to use VS Code's locale.",

View File

@@ -110,6 +110,12 @@ export class ImplicitProjectConfiguration {
}
}
export interface TsServerHeapProfileConfiguration {
readonly enabled: boolean;
readonly dir: string | undefined;
readonly interval: number | undefined;
}
export interface TypeScriptServiceConfiguration {
readonly locale: string | null;
readonly globalTsdk: string | null;
@@ -126,6 +132,9 @@ export interface TypeScriptServiceConfiguration {
readonly enableDiagnosticsTelemetry: boolean;
readonly enableProjectDiagnostics: boolean;
readonly maxTsServerMemory: number;
readonly diagnosticDir: string | undefined;
readonly heapSnapshot: number;
readonly heapProfile: TsServerHeapProfileConfiguration;
readonly enablePromptUseWorkspaceTsdk: boolean;
readonly useVsCodeWatcher: boolean;
readonly watchOptions: Proto.WatchOptions | undefined;
@@ -168,6 +177,9 @@ export abstract class BaseServiceConfigurationProvider implements ServiceConfigu
enableDiagnosticsTelemetry: this.readEnableDiagnosticsTelemetry(),
enableProjectDiagnostics: this.readEnableProjectDiagnostics(),
maxTsServerMemory: this.readMaxTsServerMemory(),
diagnosticDir: this.readDiagnosticDir(),
heapSnapshot: this.readHeapSnapshot(),
heapProfile: this.readHeapProfileConfiguration(),
enablePromptUseWorkspaceTsdk: this.readEnablePromptUseWorkspaceTsdk(),
useVsCodeWatcher: this.readUseVsCodeWatcher(configuration),
watchOptions: this.readWatchOptions(),
@@ -288,6 +300,42 @@ export abstract class BaseServiceConfigurationProvider implements ServiceConfigu
return Math.max(memoryInMB, minimumMaxMemory);
}
protected readDiagnosticDir(): string | undefined {
const diagnosticDir = readUnifiedConfig<string | undefined>('tsserver.diagnosticDir', undefined, { fallbackSection: 'typescript' });
return typeof diagnosticDir === 'string' && diagnosticDir.length > 0 ? diagnosticDir : undefined;
}
protected readHeapSnapshot(): number {
const defaultNearHeapLimitSnapshotCount = 0;
const nearHeapLimitSnapshotCount = readUnifiedConfig<number>('tsserver.heapSnapshot', defaultNearHeapLimitSnapshotCount, { fallbackSection: 'typescript' });
if (!Number.isSafeInteger(nearHeapLimitSnapshotCount)) {
return defaultNearHeapLimitSnapshotCount;
}
return Math.max(nearHeapLimitSnapshotCount, 0);
}
private readHeapProfileConfiguration(): TsServerHeapProfileConfiguration {
const defaultHeapProfileConfiguration: TsServerHeapProfileConfiguration = {
enabled: false,
dir: undefined,
interval: undefined,
};
const rawConfig = readUnifiedConfig<{ enabled?: unknown; dir?: unknown; interval?: unknown }>('tsserver.heapProfile', defaultHeapProfileConfiguration, { fallbackSection: 'typescript' });
const enabled = typeof rawConfig.enabled === 'boolean' ? rawConfig.enabled : false;
const dir = typeof rawConfig.dir === 'string' && rawConfig.dir.length > 0 ? rawConfig.dir : undefined;
const interval = typeof rawConfig.interval === 'number' && Number.isSafeInteger(rawConfig.interval) && rawConfig.interval > 0
? rawConfig.interval
: undefined;
return {
enabled,
dir,
interval,
};
}
protected readEnablePromptUseWorkspaceTsdk(): boolean {
return readUnifiedConfig<boolean>('tsdk.promptToUseWorkspaceVersion', false, { fallbackSection: 'typescript', fallbackSubSectionNameOverride: 'enablePromptUseWorkspaceTsdk' });
}

View File

@@ -162,6 +162,24 @@ function getExecArgv(kind: TsServerProcessKind, configuration: TypeScriptService
args.push(`--max-old-space-size=${configuration.maxTsServerMemory}`);
}
if (configuration.diagnosticDir) {
args.push(`--diagnostic-dir=${configuration.diagnosticDir}`);
}
if (configuration.heapSnapshot > 0) {
args.push(`--heapsnapshot-near-heap-limit=${configuration.heapSnapshot}`);
}
if (configuration.heapProfile.enabled) {
args.push('--heap-prof');
if (configuration.heapProfile.dir) {
args.push(`--heap-prof-dir=${configuration.heapProfile.dir}`);
}
if (configuration.heapProfile.interval) {
args.push(`--heap-prof-interval=${configuration.heapProfile.interval}`);
}
}
return args;
}