- Implemented a help system for different node types (config, render, variable, function) with detailed usage instructions. - Created a node registry to manage node types, including registration, retrieval, and validation of connections between nodes. - Defined central node and edge types for the application to streamline state management. - Added Nunjucks autocomplete functionality to enhance user experience in template editing. - Developed a syntax highlighting parser for PlantUML and Nunjucks within the CodeMirror editor. - Registered built-in node types at application startup, including their default configurations and help entries. - Introduced a theme context provider to manage light/dark mode preferences across the application. - Created utility functions for class name management using clsx and tailwind-merge. - Set up Tailwind CSS for styling with custom themes and responsive design. - Configured Vite for development with proxy settings for backend API calls and Kroki diagram service.
49 lines
3.5 KiB
Markdown
49 lines
3.5 KiB
Markdown
# Performance notes
|
||
|
||
## Already in place
|
||
|
||
- **Throttled node updates during drag** – `onNodesChange` merges changes and flushes at most once per animation frame (~60 fps) so dragging doesn’t trigger hundreds of re-renders per second.
|
||
- **`nodeDragThreshold={1}`** – Avoids treating small pointer moves as drags and reduces noisy change events.
|
||
- **Memoized React Flow props** – `nodeTypes`, `edgeTypes`, `defaultEdgeOptions`, and `flowContextValue` are memoized so their references don’t change every render.
|
||
- **Custom `nodePropsAreEqual`** – Node components use `React.memo(..., nodePropsAreEqual)` so a node only re-renders when its own `id`, `data`, `width`, `height`, or `selected` change (e.g. dragging one node doesn’t force others to re-render when the library keeps their props reference stable).
|
||
- **ConfigNode derived data** – `incomingEdges`, `incomingIds`, and `connected*` are wrapped in `useMemo` so they aren’t recomputed on every render.
|
||
|
||
## Further improvements you can try
|
||
|
||
### 1. Split context (medium effort)
|
||
|
||
Right now every component that uses `useContext(FlowContext)` re-renders whenever `nodes` or `edges` change. You can split into:
|
||
|
||
- **FlowDataContext** – `nodes`, `edges` (changes often).
|
||
- **FlowActionsContext** – `setNodes`, `setEdges`, `isValidConnection`, etc. (stable).
|
||
|
||
Components that only need actions (e.g. menus, buttons) subscribe to `FlowActionsContext` and won’t re-render on graph updates.
|
||
|
||
### 2. Avoid reading full `nodes`/`edges` where possible
|
||
|
||
React Flow’s docs recommend not depending on the full `nodes`/`edges` arrays when you only need a small slice (e.g. “selected ids”). If you add features like selection state, keep that in a separate store or state (e.g. `selectedNodeIds`) and have components depend on that instead of filtering `nodes` everywhere.
|
||
|
||
### 3. Lighter node content
|
||
|
||
- **CodeMirror** – Config and function nodes use CodeMirror; it’s heavy. Options: lazy-initialize the editor (mount only when the node is focused or visible), or use a plain `<textarea>` for very small/simple flows.
|
||
- **Resize** – `NodeResizeControl` and `useResizeHeight` add work. If you don’t need resize everywhere, make it optional or only on certain node types.
|
||
|
||
### 4. CSS
|
||
|
||
- **Containment** – `BaseNode` already uses `contain: layout` where dimensions are set. Keeping layout/paint contained per node helps.
|
||
- **Simpler styles** – For many nodes, avoid heavy shadows, blur, or complex animations on the node container; they can cost a lot during pan/zoom/drag.
|
||
|
||
### 5. RenderingNode pipeline
|
||
|
||
The render node runs Nunjucks + Kroki on signatures (config, edges, variables, functions). It already avoids re-running when irrelevant data changes. If you add more inputs, keep them in the signature pattern so the effect only runs when something that affects the result actually changes.
|
||
|
||
### 6. Large graphs
|
||
|
||
- **Hide/collapse** – For big trees, use the `hidden` property (or similar) so only expanded nodes are rendered.
|
||
- **Virtualization** – React Flow doesn’t virtualize by default. For 100+ nodes, consider only rendering nodes in view (e.g. with `onlyRenderVisibleElements` if/when available in your version) or a custom viewport-based filter.
|
||
|
||
### 7. Build / runtime
|
||
|
||
- **Production build** – Use `vite build` and test with the production build; React and Vite are much faster without dev mode and source maps.
|
||
- **React DevTools Profiler** – Record while dragging or editing to see which components re-render and how often; that will guide where to add more memoization or split context.
|