perf: 优化智能体与工作流幕布渲染性能

- 分阶段加载智能体配置并按需缓存 MCP 工具

- 合并画布状态更新与节点尺寸监听,启用大图可视区域渲染和静态连线

- 隔离 Tinyflow Store 实例并补充数据同步与回归测试
This commit is contained in:
2026-07-27 18:27:01 +08:00
parent dc7e46260b
commit aedefe6b5e
39 changed files with 1349 additions and 408 deletions

View File

@@ -1,6 +1,6 @@
import type {useSvelteFlow} from '@xyflow/svelte';
import {componentName} from './consts';
import {store} from './store/stores.svelte';
import type {TinyflowStore} from './store/stores.svelte';
import type {TinyflowData, TinyflowOptions, TinyflowTheme} from './types';
import {installTinyflowBrowserCompat} from './utils/compat';
import {createTinyflowNodeNormalizer} from './utils/nodeInteraction';
@@ -13,9 +13,13 @@ export class Tinyflow {
private options!: TinyflowOptions;
private rootEl!: Element;
private svelteFlowInstance!: FlowInstance;
private store!: TinyflowStore;
private tinyflowEl!: HTMLElement & {
options: TinyflowOptions;
onInit: (svelteFlowInstance: FlowInstance) => void;
onInit: (
svelteFlowInstance: FlowInstance,
store: TinyflowStore,
) => void;
};
constructor(options: TinyflowOptions) {
@@ -72,7 +76,10 @@ export class Tinyflow {
private _createTinyflowElement() {
const tinyflowEl = document.createElement(componentName) as HTMLElement & {
options: TinyflowOptions;
onInit: (svelteFlowInstance: FlowInstance) => void;
onInit: (
svelteFlowInstance: FlowInstance,
store: TinyflowStore,
) => void;
};
tinyflowEl.style.display = 'block';
tinyflowEl.style.width = '100%';
@@ -80,8 +87,12 @@ export class Tinyflow {
this._applyThemeClass(tinyflowEl, this.options.theme);
tinyflowEl.options = this.options;
tinyflowEl.onInit = (svelteFlowInstance: FlowInstance) => {
tinyflowEl.onInit = (
svelteFlowInstance: FlowInstance,
store: TinyflowStore,
) => {
this.svelteFlowInstance = svelteFlowInstance;
this.store = store;
};
return tinyflowEl;
}
@@ -104,29 +115,29 @@ export class Tinyflow {
return false;
}
const currentViewport = flow.getViewport();
const currentNodes = flow.getNodes();
const normalizeNode = createTinyflowNodeNormalizer(this.options);
const currentNodePositions = new Map(
currentNodes.map((node) => [node.id, node.position]),
);
const nextNodes =
options?.preserveViewport === true
? (data.nodes || currentNodes).map((node) => {
const currentPosition = currentNodePositions.get(node.id);
const nextNode = currentPosition
? { ...node, position: { ...currentPosition } }
: node;
return normalizeNode(nextNode);
})
: (data.nodes || currentNodes).map((node) => normalizeNode(node));
store.setNodes(nextNodes);
store.setEdges(data.edges || flow.getEdges());
if (data.nodes) {
const currentNodePositions =
options?.preserveViewport === true
? new Map(
flow.getNodes().map((node) => [node.id, node.position] as const),
)
: null;
const nextNodes = data.nodes.map((node) => {
const currentPosition = currentNodePositions?.get(node.id);
const nextNode = currentPosition
? { ...node, position: { ...currentPosition } }
: node;
return normalizeNode(nextNode);
});
this.store.setNodes(nextNodes);
}
if (data.edges) {
this.store.setEdges(data.edges);
}
if (data.viewport && options?.preserveViewport !== true) {
flow.setViewport(data.viewport, { duration: 0 });
} else {
flow.setViewport(currentViewport, { duration: 0 });
}
return true;
}