Three related disposable-registration gaps that leak xterm Terminal instances when the host application unmounts a Terminal. Evidence + full writeup at juspay/kolu#606. 1. addon-webgl/WebglRenderer._cursorBlinkStateManager was declared `= new MutableDisposable()` without the `this._register(...)` wrapper that every sibling MutableDisposable in the class uses. CursorBlinkStateManager runs a setInterval for the cursor blink and its `dispose()` correctly clears it — but dispose() was never called because the disposable wasn't registered. The live timer kept the renderer (and thus the Terminal) alive past host unmount. 2. common/TaskQueue.DebouncedIdleTask had no `dispose()` method. Added one that clears the internal IdleTaskQueue (cancelling any pending idle callback). 3. browser/services/RenderService._pausedResizeTask (a DebouncedIdleTask) was not registered. Wrapped with `this._register(...)` so RenderService.dispose propagates. Verified in a downstream app (kolu) with a repro that toggles Focus vs Canvas layout modes: - Pre-fix: 24/28 disposed xterm Terminals retained past host unmount + forced GC. - Post-fix: 0/28 retained. Retention chain (before fix): DOMTimer → ScheduledAction → V8Function → CursorBlinkStateManager._renderCallback → WebglRenderer → Terminal
@xterm/addon-webgl
An addon for xterm.js that enables a WebGL2-based renderer. This addon requires xterm.js v4+.
Install
npm install --save @xterm/addon-webgl
Usage
import { Terminal } from '@xterm/xterm';
import { WebglAddon } from '@xterm/addon-webgl';
const terminal = new Terminal();
terminal.open(element);
terminal.loadAddon(new WebglAddon());
See the full API for more advanced usage.
Handling Context Loss
The browser may drop WebGL contexts for various reasons like OOM or after the system has been suspended. There is an API exposed that fires the webglcontextlost event fired on the canvas so embedders can handle it however they wish. An easy, but suboptimal way, to handle this is by disposing of WebglAddon when the event fires:
const terminal = new Terminal();
const addon = new WebglAddon();
addon.onContextLoss(e => {
addon.dispose();
});
terminal.loadAddon(addon);
Read more about handling WebGL context losses on the Khronos wiki.