Improve performance, efficiency, and code quality#1
Conversation
Backend (Rust): - Implement Tantivy full-text search with indexed queries - Convert file I/O to async using tokio::fs - Replace Mutex with RwLock for settings/cache (better read concurrency) - Fix debounce map memory leak with periodic cleanup - Fix mutex error handling with descriptive expect messages - Remove unused dependencies (uuid, chrono, regex) Frontend (React/TypeScript): - Add useMemo to CommandPalette for filtered items - Memoize NoteList displayItems and wrap NoteItem with React.memo - Wrap FormatBar with React.memo to prevent re-renders on keystrokes - Memoize App.tsx displayItems for stable keyboard handler deps - Split NotesContext into separate data/actions contexts - Optimize FlipText animation with single RAF loop - Fix note selection race condition in Editor - Add Vite build optimizations with manual chunk splitting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughAdds a Tantivy-backed search index and async/Tokio-based I/O to the Tauri backend, refactors AppState to use RWLocks and debounce tracking, converts several backend commands to async, applies memoization across multiple React components, splits NotesContext into data/actions, and adds Vite production build optimizations. Changes
Sequence Diagram(s)sequenceDiagram
participant Frontend as Frontend
participant Handler as Tauri Command
participant FS as FileSystem (async tokio)
participant Index as SearchIndex (Tantivy)
participant Evt as EventEmitter
Frontend->>Handler: save_note(title, content)
Handler->>FS: async write note file
FS-->>Handler: write success
Handler->>Index: index_note(id, title, content, modified)
Index-->>Handler: indexed
Handler->>Evt: emit FileChangeEvent
Evt-->>Frontend: note updated
Frontend->>Handler: delete_note(id)
Handler->>FS: async remove file
FS-->>Handler: remove success
Handler->>Index: delete_note(id)
Index-->>Handler: deleted
Handler->>Evt: emit FileChangeEvent
Evt-->>Frontend: note removed
Frontend->>Handler: rebuild_search_index()
Handler->>FS: async scan notes folder
FS-->>Handler: list of note files
Handler->>Index: rebuild_index(notes_folder)
loop per note
Index->>Index: index_note(...)
end
Index-->>Handler: rebuild complete
Handler-->>Frontend: ready
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src-tauri/src/lib.rs (1)
734-814:⚠️ Potential issue | 🟠 MajorSearch index becomes stale when files are modified externally.
The
file-changeevent triggersrefreshNotes()which reloads the notes list from disk, but the search index (Tantivy) is never updated. The search index is only rebuilt at startup (line 386), or when notes are explicitly created/edited/deleted through the app (lines 554, 588, 638). Files modified outside the app won't be indexed, causing searches to return stale results. Add a call torebuild_search_indexafter debounced external file changes, or selectively re-index changed files instead of refreshing the entire index.
🤖 Fix all issues with AI agents
In `@src/components/editor/Editor.tsx`:
- Around line 313-367: The requestAnimationFrame callback can clear
isLoadingRef.current for a different note if notes switch quickly; capture the
currentNote.id (e.g., const loadingId = loadedNoteIdRef.current) before
scheduling RAF and inside the RAF bail early unless loadedNoteIdRef.current ===
loadingId, so we only set isLoadingRef.current = false and run the
focus/selectAll logic for the same note that initiated the load; update the
useEffect that uses loadedNoteIdRef, isLoadingRef, and requestAnimationFrame
accordingly to avoid clearing the flag for a newer load and prevent onUpdate
from saving the wrong note.
- Line 1: FormatBar is wrapped with React.memo causing its buttons to show stale
state because the editor instance mutates selection/marks without changing
reference; remove the memoization so FormatBar re-renders with the parent Editor
updates: delete the memo import usage and replace any export/default export like
export default memo(FormatBar) with export default FormatBar (or simply export
the component), and remove "memo" from the React import list so FormatBar
receives fresh props and can rely on editor.isActive(...) to reflect current
selection.
In `@vite.config.ts`:
- Around line 34-40: The build.target currently set to "esnext" is too
bleeding-edge for WebView compatibility; update the Vite config's build.target
(in vite.config.ts) to a supported baseline such as "es2021" or implement
platform-specific targets per Tauri guidance (e.g., "chrome105" for Windows
WebView2 and "safari13" for macOS/Linux WebKit) so bundles run on older
WebKitGTK and macOS versions; modify the build.target value accordingly and
refer to the Tauri Vite setup docs for exact target strings.
- Remove React.memo from FormatBar: editor instance is mutable so memo causes stale isActive() state for toolbar buttons - Fix RAF race condition in Editor: capture note ID before scheduling and bail in callback if a different note started loading - Change Vite build.target from "esnext" to ["es2021", "chrome105", "safari14"] for better WebView compatibility across platforms Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Improve performance, efficiency, and code quality Backend (Rust): - Implement Tantivy full-text search with indexed queries - Convert file I/O to async using tokio::fs - Replace Mutex with RwLock for settings/cache (better read concurrency) - Fix debounce map memory leak with periodic cleanup - Fix mutex error handling with descriptive expect messages - Remove unused dependencies (uuid, chrono, regex) Frontend (React/TypeScript): - Add useMemo to CommandPalette for filtered items - Memoize NoteList displayItems and wrap NoteItem with React.memo - Wrap FormatBar with React.memo to prevent re-renders on keystrokes - Memoize App.tsx displayItems for stable keyboard handler deps - Split NotesContext into separate data/actions contexts - Optimize FlipText animation with single RAF loop - Fix note selection race condition in Editor - Add Vite build optimizations with manual chunk splitting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Fix review comments: FormatBar memo, RAF race condition, build target - Remove React.memo from FormatBar: editor instance is mutable so memo causes stale isActive() state for toolbar buttons - Fix RAF race condition in Editor: capture note ID before scheduling and bail in callback if a different note started loading - Change Vite build.target from "esnext" to ["es2021", "chrome105", "safari14"] for better WebView compatibility across platforms Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Summary
Comprehensive performance and code quality improvements across both the Rust backend and React frontend.
Backend (Rust)
tokio::fsfor non-blocking reads/writesMutexwithRwLockfor settings/cache (multiple readers)unwrap()toexpect()with descriptive messagesFrontend (React/TypeScript)
useMemofor commands, filtered notes/commands, and all itemsdisplayItemsand wrappedNoteItemwithReact.memoReact.memoto prevent re-renders on every keystrokedisplayItemsto stabilize keyboard handler dependenciesTest Plan
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Performance
Reliability
Build
✏️ Tip: You can customize this high-level summary in your review settings.