diff --git a/package-lock.json b/package-lock.json
index 825690b..5d0fba2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"@capacitor/status-bar": "^5.0.6",
"@xterm/addon-fit": "^0.10.0",
"@xterm/addon-web-links": "^0.11.0",
+ "@xterm/addon-webgl": "^0.19.0",
"@xterm/xterm": "^5.5.0",
"electron-store": "^8.1.0",
"framer-motion": "^10.16.16",
@@ -5866,6 +5867,12 @@
"@xterm/xterm": "^5.0.0"
}
},
+ "node_modules/@xterm/addon-webgl": {
+ "version": "0.19.0",
+ "resolved": "https://registry.npmmirror.com/@xterm/addon-webgl/-/addon-webgl-0.19.0.tgz",
+ "integrity": "sha512-b3fMOsyLVuCeNJWxolACEUED0vm7qC0cy4wRvf3oURSzDTYVQiGPhTnhWZwIHdvC48Y+oLhvYXnY4XDXPoJo6A==",
+ "license": "MIT"
+ },
"node_modules/@xterm/xterm": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
diff --git a/package.json b/package.json
index 13a5e0b..9a13151 100644
--- a/package.json
+++ b/package.json
@@ -76,6 +76,7 @@
"@capacitor/status-bar": "^5.0.6",
"@xterm/addon-fit": "^0.10.0",
"@xterm/addon-web-links": "^0.11.0",
+ "@xterm/addon-webgl": "^0.19.0",
"@xterm/xterm": "^5.5.0",
"electron-store": "^8.1.0",
"framer-motion": "^10.16.16",
diff --git a/src/components/Terminal.js b/src/components/Terminal.js
index a136eb3..f710098 100644
--- a/src/components/Terminal.js
+++ b/src/components/Terminal.js
@@ -3,6 +3,7 @@ import { motion } from 'framer-motion';
import { Terminal as XTerm } from '@xterm/xterm';
import { FitAddon } from '@xterm/addon-fit';
import { WebLinksAddon } from '@xterm/addon-web-links';
+import { WebglAddon } from '@xterm/addon-webgl';
import '@xterm/xterm/css/xterm.css';
import { FiCommand, FiRefreshCw, FiInfo, FiFolder, FiActivity, FiZap } from 'react-icons/fi';
@@ -19,6 +20,8 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT
const hasConnectedRef = useRef(false);
const resizeObserverRef = useRef(null);
const contextMenuHandlerRef = useRef(null);
+ const resizeTimeoutRef = useRef(null);
+ const webglAddonRef = useRef(null);
const onConnectionChangeRef = useRef(onConnectionChange);
onConnectionChangeRef.current = onConnectionChange;
@@ -154,8 +157,12 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT
cursorStyle: 'bar',
fontSize: 14,
fontFamily: "'JetBrains Mono', 'Fira Code', Consolas, monospace",
- lineHeight: 1.5,
- scrollback: 2000,
+ lineHeight: 1.4,
+ scrollback: 1000, // 减少滚动缓冲区提升性能
+ fastScrollModifier: 'alt', // 快速滚动
+ fastScrollSensitivity: 5,
+ smoothScrollDuration: 0, // 禁用平滑滚动提升性能
+ scrollSensitivity: 1,
theme: {
// 赛博朋克主题配色
background: '#050810',
@@ -195,6 +202,19 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT
xtermRef.current = term;
fitAddonRef.current = fitAddon;
+ // 尝试加载 WebGL 渲染器提升性能
+ try {
+ const webglAddon = new WebglAddon();
+ webglAddon.onContextLoss(() => {
+ webglAddon.dispose();
+ webglAddonRef.current = null;
+ });
+ term.loadAddon(webglAddon);
+ webglAddonRef.current = webglAddon;
+ } catch (e) {
+ console.warn('WebGL 渲染器不可用,使用默认渲染器:', e);
+ }
+
setTimeout(() => {
fitAddon.fit();
}, 0);
@@ -229,8 +249,14 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT
};
container.addEventListener('contextmenu', contextMenuHandlerRef.current);
+ // 使用防抖的 ResizeObserver 避免频繁调用
resizeObserverRef.current = new ResizeObserver(() => {
- fitTerminal();
+ if (resizeTimeoutRef.current) {
+ clearTimeout(resizeTimeoutRef.current);
+ }
+ resizeTimeoutRef.current = setTimeout(() => {
+ fitTerminal();
+ }, 100); // 100ms 防抖
});
resizeObserverRef.current.observe(container);
@@ -268,6 +294,10 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT
clearTimeout(initTimerRef.current);
}
+ if (resizeTimeoutRef.current) {
+ clearTimeout(resizeTimeoutRef.current);
+ }
+
if (resizeObserverRef.current) {
resizeObserverRef.current.disconnect();
resizeObserverRef.current = null;
@@ -289,6 +319,12 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT
connectionIdRef.current = null;
}
+ // 清理 WebGL 渲染器
+ if (webglAddonRef.current) {
+ webglAddonRef.current.dispose();
+ webglAddonRef.current = null;
+ }
+
if (xtermRef.current) {
xtermRef.current.dispose();
xtermRef.current = null;
@@ -329,15 +365,13 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT
setTimeout(() => connect(), 100);
}, [connect]);
- // 工具栏按钮组件
+ // 工具栏按钮组件 - 简化动画提升性能
const ToolButton = ({ onClick, disabled, active, title, children }) => (
-