Command Palette

Search for a command to run...

Performance Optimization

Follow these best practices to ensure optimal performance.

Bundle Size Optimization

Use Selective Imports

Treege exposes separate entry points. Import only what you use:

// ✅ Good — only the renderer (~62 KB vs ~117 KB gzip, no ReactFlow)
import { TreegeRenderer } from "treege/renderer"
 
// ✅ Good — only the editor
import { TreegeEditor } from "treege/editor"
 
// ✅ Good — need both, so import everything
import { TreegeEditor, TreegeRenderer } from "treege"
 
// ❌ Bad — only using the renderer, but pulling in everything (incl. the editor)
import { TreegeRenderer } from "treege"

Code Splitting

Lazy-load the editor so its bundle is only fetched when needed. The editor is client-only (it relies on ReactFlow and browser APIs), so the important part is keeping it out of server-side rendering.

Framework-agnostic (Vite, CRA, etc.) — React.lazy + Suspense:

import { lazy, Suspense } from "react"
 
const TreegeEditor = lazy(() =>
  import("treege/editor").then((mod) => ({ default: mod.TreegeEditor }))
)
 
function Editor() {
  return (
    <Suspense fallback={<div>Loading editor…</div>}>
      <TreegeEditor flow={flow} onSave={handleSave} />
    </Suspense>
  )
}

Next.js — prefer next/dynamic with ssr: false:

In Next.js, React.lazy cannot disable SSR on its own, and server-rendering a browser-only component throws. Use next/dynamic with { ssr: false } instead:

import dynamic from "next/dynamic"
 
const TreegeEditor = dynamic(
  () => import("treege/editor").then((mod) => ({ default: mod.TreegeEditor })),
  { ssr: false }
)

React Performance

Memoize Callbacks

import { useCallback, useState } from "react"
 
export default function MyForm({ flow }) {
  const handleSubmit = useCallback(async (data) => {
    await fetch("/api/submit", {
      method: "POST",
      body: JSON.stringify(data)
    })
  }, [])
 
  const handleChange = useCallback((data) => {
    setValues(data)
  }, [])
 
  return (
    <TreegeRenderer
      flow={flow}
      onSubmit={handleSubmit}
      onChange={handleChange}
    />
  )
}

Memoize Flow Data

import { useMemo } from "react"
 
export default function MyForm() {
  const flow = useMemo(() => ({
    nodes: [/* ... */],
    edges: [/* ... */]
  }), [])
 
  return <TreegeRenderer flow={flow} onSubmit={handleSubmit} />
}

Validation Performance

Choose the Right Validation Mode

// ✅ Good for large forms - validates on submit
<TreegeRenderer
  flow={flow}
  onSubmit={handleSubmit}
  validationMode="onSubmit"
/>
 
// ⚠️ Can be slow - validates on every change
<TreegeRenderer
  flow={flow}
  onSubmit={handleSubmit}
  validationMode="onChange"
/>

Best Practices

  1. ✅ Use selective imports (treege/renderer or treege/editor)
  2. ✅ Memoize callbacks with useCallback
  3. ✅ Use validationMode="onSubmit" for large forms
  4. ✅ Keep validation functions simple
  5. ✅ Use code splitting for the editor
  6. ✅ Enable production builds with minification