Skip to content

Performance Optimization ​

This guide covers strategies for optimizing Editu editor performance in production applications.

Bundle Size Optimization ​

Disable Unused Features ​

Editu enables all features by default. Disable features you don't use to reduce bundle size and extension processing:

typescript
const editor = useEdituEditor({
  features: {
    mathematics: false,  // KaTeX (~80KB gzipped)
    diagram: false,      // Mermaid (~40KB gzipped, lazy-loaded)
    embed: false,        // oEmbed/OGP processing
    codeBlock: false,    // lowlight/highlight.js (~20KB gzipped)
    table: false,
    dragHandle: false,
  },
});

Feature Size Impact ​

The following table shows approximate sizes (minified + gzipped) of optional features:

FeatureApproximate SizeDependencies
mathematics~80KB gzippedKaTeX
diagram~40KB gzippedMermaid (lazy-loaded); GraphViz via @hpcc-js/wasm-graphviz adds additional size
codeBlock~20KB gzippedlowlight / highlight.js
embed~5KB gzippedBuilt-in oEmbed
table~8KB gzipped@tiptap/extension-table
dragHandle~3KB gzippedBuilt-in
textColor~2KB gzippedBuilt-in
taskList~2KB gzippedBuilt-in
details~2KB gzippedBuilt-in

Measurement

Actual bundle sizes depend on your bundler configuration and tree-shaking. You can use tools like bundlephobia or your bundler's analysis output to measure exact sizes:

bash
# Vite
npx vite-bundle-visualizer

# Webpack
npx webpack-bundle-analyzer

Lazy Loading ​

Editu uses createLazyLoader() internally for optional dependencies like Mermaid. Editu lazy-loads diagram rendering on first use, so simply having the feature enabled does not add to initial load time.

You can also lazy-load optional CSS stylesheets:

typescript
// Only import mathematics CSS when the feature is used
if (useMathematics) {
  import('@editu/core/mathematics.css');
}

Code Block Language Optimization ​

By default, code blocks load all common languages. You can limit this to only the languages you need:

typescript
import { createLowlight } from 'lowlight';
import javascript from 'highlight.js/lib/languages/javascript';
import typescript from 'highlight.js/lib/languages/typescript';
import css from 'highlight.js/lib/languages/css';

const lowlight = createLowlight();
lowlight.register('javascript', javascript);
lowlight.register('typescript', typescript);
lowlight.register('css', css);

const editor = useEdituEditor({
  features: {
    codeBlock: { lowlight },
  },
});

Or use the common subset instead of all:

typescript
import { createLowlight, common } from 'lowlight';

// ~40 common languages instead of all ~190
const lowlight = createLowlight(common);

Large Document Handling ​

Character Count Limits ​

You can use the character count feature to enforce document size limits:

typescript
const editor = useEdituEditor({
  features: {
    characterCount: {
      limit: 50000, // Maximum characters
    },
  },
});

Optimize onUpdate Handlers ​

You should avoid expensive operations on every keystroke:

typescript
// Bad: Expensive serialization on every keystroke
onUpdate: ({ editor }) => {
  setContent(editor.getJSON());        // Triggers re-render
  localStorage.setItem('content',
    JSON.stringify(editor.getJSON())); // Synchronous I/O
},

// Good: Use auto-save with debouncing
const editor = useEdituEditor({
  onUpdate: ({ editor }) => {
    // Only lightweight operations here
  },
});

useEdituAutoSave(() => editor, {
  debounceMs: 2000,
  storage: 'localStorage',
  key: 'my-content',
});

Debounce State Updates ​

When syncing editor state to external state management:

tsx
import { useMemo, useState } from 'react';
import { useEdituEditor } from '@editu/react';

function Editor() {
  const [content, setContent] = useState(null);

  // Debounce content updates
  const debouncedSetContent = useMemo(
    () => {
      let timer: ReturnType<typeof setTimeout>;
      return (json: unknown) => {
        clearTimeout(timer);
        timer = setTimeout(() => setContent(json), 300);
      };
    },
    []
  );

  const editor = useEdituEditor({
    onUpdate: ({ editor }) => {
      debouncedSetContent(editor.getJSON());
    },
  });

  return <EdituEditor editor={editor} />;
}

Auto-Save Configuration ​

Debounce Timing ​

Choose a debounce value that balances responsiveness and performance:

Use CaseRecommended debounceMs
Real-time collaboration500ms
General editing1000ms (default)
Large documents2000–3000ms
Server-side persistence3000–5000ms

Storage Backend Selection ​

BackendBest ForConsiderations
localStorageQuick prototyping~5MB limit, synchronous
sessionStorageTemporary draftsCleared on tab close
Custom (API)Production appsAsync, no size limit

See Auto-Save for detailed configuration.


Framework-Specific Tips ​

React ​

  • Avoid creating a new onUpdate function on every render. Use useCallback or define the function outside the component.
  • Wrap toolbar components that receive the editor instance with React.memo
  • Do not store the entire editor state in React state. Use the useEdituEditorState hook for reactive state tracking.
tsx
import { useEdituEditor, useEdituEditorState } from '@editu/react';

function Editor() {
  const editor = useEdituEditor({});

  // Reactive state without manual onUpdate tracking
  const { characterCount, wordCount } = useEdituEditorState(() => editor);

  return (
    <div>
      <EdituEditor editor={editor} />
      <span>{characterCount} characters, {wordCount} words</span>
    </div>
  );
}

Production Checklist ​

Before deploying to production, verify the following optimizations:

  • [ ] Disable unused features — Remove features your application does not use
  • [ ] Optimize code block languages — Register only the languages you need
  • [ ] Configure auto-save debouncing — Set an appropriate debounceMs for your use case
  • [ ] Debounce onUpdate handlers — Avoid expensive operations on every keystroke
  • [ ] Set character count limits — Prevent excessively large documents if applicable
  • [ ] Lazy load optional CSS — Import mathematics.css only if you use math features
  • [ ] Enable compression — Configure gzip or brotli compression on your server
  • [ ] Analyze bundle size — Use bundle analysis tools to identify optimization opportunities
  • [ ] Test with realistic content — Profile with documents similar to production usage

Next Steps ​

Released under the MIT License.