From 1ae1f24c41af838264cf5ca6c6629c3d7eff56a4 Mon Sep 17 00:00:00 2001 From: Silberengel Date: Tue, 28 Oct 2025 21:09:48 +0100 Subject: [PATCH] more performance fixes --- src/PageManager.tsx | 38 +- src/components/Embedded/EmbeddedNote.tsx | 6 +- src/components/NoteList/index.tsx | 112 +- src/components/NoteOptions/useMenuActions.tsx | 24 +- src/components/NotificationList/index.tsx | 51 +- .../Profile/ProfileBookmarksAndHashtags.tsx | 18 +- src/components/SimpleNoteFeed/index.tsx | 22 +- src/lib/logger.ts | 38 +- src/pages/primary/NoteListPage/RelaysFeed.tsx | 6 +- src/pages/secondary/NotePage/NotFound.tsx | 4 +- src/providers/BookmarksProvider.tsx | 5 +- src/providers/FeedProvider.tsx | 10 +- src/providers/InterestListProvider.tsx | 35 +- src/providers/NostrProvider/index.tsx | 8 +- src/providers/NotificationProvider.tsx | 16 +- src/services/client.service.ts | 1106 ++++------------- src/services/note-stats.service.ts | 1 + 17 files changed, 471 insertions(+), 1029 deletions(-) diff --git a/src/PageManager.tsx b/src/PageManager.tsx index 42704d1..0464e82 100644 --- a/src/PageManager.tsx +++ b/src/PageManager.tsx @@ -614,15 +614,18 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { const pushSecondaryPage = (url: string, index?: number) => { - console.log('pushSecondaryPage called with:', url) + logger.component('PageManager', 'pushSecondaryPage called', { url }) setSecondaryStack((prevStack) => { - console.log('Current secondary stack length:', prevStack.length) + logger.component('PageManager', 'Current secondary stack length', { length: prevStack.length }) // For relay pages, clear the stack and start fresh to avoid confusion if (url.startsWith('/relays/')) { - console.log('Clearing stack for relay navigation') + logger.component('PageManager', 'Clearing stack for relay navigation') const { newStack, newItem } = pushNewPageToStack([], url, maxStackSize, 0) - console.log('New stack length:', newStack.length, 'New item:', !!newItem) + logger.component('PageManager', 'New stack created', { + newStackLength: newStack.length, + hasNewItem: !!newItem + }) if (newItem) { window.history.pushState({ index: newItem.index, url }, '', url) } @@ -630,7 +633,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { } if (isCurrentPage(prevStack, url)) { - console.log('Page already exists, scrolling to top') + logger.component('PageManager', 'Page already exists, scrolling to top') const currentItem = prevStack[prevStack.length - 1] if (currentItem?.ref?.current) { currentItem.ref.current.scrollToTop('instant') @@ -638,9 +641,12 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { return prevStack } - console.log('Creating new page for URL:', url) + logger.component('PageManager', 'Creating new page for URL', { url }) const { newStack, newItem } = pushNewPageToStack(prevStack, url, maxStackSize, index) - console.log('New stack length:', newStack.length, 'New item:', !!newItem) + logger.component('PageManager', 'New page created', { + newStackLength: newStack.length, + hasNewItem: !!newItem + }) if (newItem) { window.history.pushState({ index: newItem.index, url }, '', url) } @@ -715,7 +721,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { {!!secondaryStack.length && secondaryStack.map((item, index) => { const isLast = index === secondaryStack.length - 1 - console.log('Rendering secondary stack item:', { + logger.component('PageManager', 'Rendering secondary stack item', { index, isLast, url: item.url, @@ -788,7 +794,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
{secondaryStack.map((item, index) => { const isLast = index === secondaryStack.length - 1 - console.log('Rendering desktop secondary stack item:', { + logger.component('PageManager', 'Rendering desktop secondary stack item', { index, isLast, url: item.url, @@ -861,21 +867,21 @@ function isCurrentPage(stack: TStackItem[], url: string) { const currentPage = stack[stack.length - 1] if (!currentPage) return false - console.log('isCurrentPage check:', { currentUrl: currentPage.url, newUrl: url, match: currentPage.url === url }) + logger.component('PageManager', 'isCurrentPage check', { currentUrl: currentPage.url, newUrl: url, match: currentPage.url === url }) return currentPage.url === url } function findAndCreateComponent(url: string, index: number) { const path = url.split('?')[0].split('#')[0] - console.log('findAndCreateComponent called with:', { url, path, routes: routes.length }) + logger.component('PageManager', 'findAndCreateComponent called', { url, path, routes: routes.length }) for (const { matcher, element } of routes) { const match = matcher(path) - console.log('Trying route matcher, match result:', !!match) + logger.component('PageManager', 'Trying route matcher', { matchResult: !!match }) if (!match) continue if (!element) { - console.log('No element for this route') + logger.component('PageManager', 'No element for this route') return {} } const ref = createRef() @@ -884,13 +890,13 @@ function findAndCreateComponent(url: string, index: number) { const params = { ...match.params } if (params.url && typeof params.url === 'string') { params.url = decodeURIComponent(params.url) - console.log('Decoded URL parameter:', params.url) + logger.component('PageManager', 'Decoded URL parameter', { url: params.url }) } - console.log('Creating component with params:', params) + logger.component('PageManager', 'Creating component with params', params) return { component: cloneElement(element, { ...params, index, ref } as any), ref } } - console.log('No matching route found for:', path) + logger.component('PageManager', 'No matching route found', { path }) return {} } diff --git a/src/components/Embedded/EmbeddedNote.tsx b/src/components/Embedded/EmbeddedNote.tsx index 67d6448..1db5793 100644 --- a/src/components/Embedded/EmbeddedNote.tsx +++ b/src/components/Embedded/EmbeddedNote.tsx @@ -25,12 +25,12 @@ export function EmbeddedNote({ noteId, className }: { noteId: string; className? setRetryCount(prev => prev + 1) client.fetchEventForceRetry(noteId) - .then((retryResult) => { + .then((retryResult: any) => { if (retryResult) { setRetryEvent(retryResult) } }) - .catch((error) => { + .catch((error: any) => { console.warn(`Retry ${retryCount + 1}/${maxRetries} failed for event:`, noteId, error) }) .finally(() => { @@ -137,7 +137,7 @@ function EmbeddedNoteNotFound({ setIsSearchingExternal(true) try { - const event = await client.fetchEventWithExternalRelays(noteId) + const event = await client.fetchEventWithExternalRelays(noteId, []) if (event && onEventFound) { onEventFound(event) } diff --git a/src/components/NoteList/index.tsx b/src/components/NoteList/index.tsx index 2633076..48cb871 100644 --- a/src/components/NoteList/index.tsx +++ b/src/components/NoteList/index.tsx @@ -83,22 +83,8 @@ const NoteList = forwardRef( // Check if this is a profile feed const isProfileFeed = subRequests.some(req => req.filter.authors && req.filter.authors.length === 1) - console.log('🔍 [NoteList] Checking shouldHideEvent for:', { - id: evt.id, - kind: evt.kind, - pubkey: evt.pubkey.substring(0, 8), - isDeleted: isEventDeleted(evt), - isReply: isReplyNoteEvent(evt), - isTrusted: isUserTrusted(evt.pubkey), - isMuted: mutePubkeySet.has(evt.pubkey), - hideReplies, - hideUntrustedNotes, - filterMutedNotes, - isProfileFeed - }) - if (isEventDeleted(evt)) { - console.log('❌ [NoteList] Event deleted:', evt.id) + logger.component('NoteList', 'Event filtered: deleted', { id: evt.id, kind: evt.kind }) return true } @@ -109,20 +95,24 @@ const NoteList = forwardRef( // For profile feeds, show all zaps from the profile owner // For timeline feeds, filter by threshold if (!isProfileFeed && zapInfo && zapInfo.amount < zapReplyThreshold) { - console.log('❌ [NoteList] Zap below threshold:', { id: evt.id, amount: zapInfo.amount, threshold: zapReplyThreshold }) + logger.component('NoteList', 'Event filtered: zap below threshold', { + id: evt.id, + amount: zapInfo.amount, + threshold: zapReplyThreshold + }) return true } } else if (hideReplies && isReplyNoteEvent(evt)) { - console.log('❌ [NoteList] Reply hidden:', evt.id) + logger.component('NoteList', 'Event filtered: reply hidden', { id: evt.id, kind: evt.kind }) return true } if (hideUntrustedNotes && !isUserTrusted(evt.pubkey)) { - console.log('❌ [NoteList] Untrusted user:', evt.id) + logger.component('NoteList', 'Event filtered: untrusted user', { id: evt.id, pubkey: evt.pubkey.substring(0, 8) }) return true } if (filterMutedNotes && mutePubkeySet.has(evt.pubkey)) { - console.log('❌ [NoteList] Muted user:', evt.id) + logger.component('NoteList', 'Event filtered: muted user', { id: evt.id, pubkey: evt.pubkey.substring(0, 8) }) return true } if ( @@ -130,11 +120,10 @@ const NoteList = forwardRef( hideContentMentioningMutedUsers && isMentioningMutedUsers(evt, mutePubkeySet) ) { - console.log('❌ [NoteList] Mentions muted users:', evt.id) + logger.component('NoteList', 'Event filtered: mentions muted users', { id: evt.id, kind: evt.kind }) return true } - console.log('✅ [NoteList] Event passed all filters:', evt.id) return false }, [hideReplies, hideUntrustedNotes, mutePubkeySet, isEventDeleted, zapReplyThreshold, subRequests] @@ -142,34 +131,30 @@ const NoteList = forwardRef( const filteredEvents = useMemo(() => { const idSet = new Set() - - console.log('🔍 [NoteList] Filtering events:', { - totalEvents: events.length, - showCount, - eventKinds: events.map(e => e.kind).slice(0, 10) - }) + const startTime = performance.now() const filtered = events.slice(0, showCount).filter((evt) => { if (shouldHideEvent(evt)) { - console.log('❌ [NoteList] Event hidden:', { id: evt.id, kind: evt.kind, reason: 'shouldHideEvent' }) return false } const id = isReplaceableEvent(evt.kind) ? getReplaceableCoordinateFromEvent(evt) : evt.id if (idSet.has(id)) { - console.log('❌ [NoteList] Event hidden:', { id: evt.id, kind: evt.kind, reason: 'duplicate' }) + logger.component('NoteList', 'Event filtered: duplicate', { id: evt.id, kind: evt.kind }) return false } idSet.add(id) return true }) - - console.log('✅ [NoteList] Filtered events result:', { - total: events.length, - filtered: filtered.length, - showCount + + const endTime = performance.now() + logger.perfComponent('NoteList', 'Event filtering completed', { + totalEvents: events.length, + filteredEvents: filtered.length, + showCount, + duration: `${(endTime - startTime).toFixed(2)}ms` }) - + return filtered }, [events, showCount, shouldHideEvent]) @@ -200,7 +185,7 @@ const NoteList = forwardRef( scrollToTop() // Clear relay connection state to force fresh connections const relayUrls = subRequests.flatMap(req => req.urls) - client.clearRelayConnectionState(relayUrls) + relayUrls.forEach(url => client.clearRelayConnectionState(url)) setTimeout(() => { setRefreshCount((count) => count + 1) }, 500) @@ -209,32 +194,32 @@ const NoteList = forwardRef( useImperativeHandle(ref, () => ({ scrollToTop, refresh }), []) useEffect(() => { - console.log('🚀 [NoteList] useEffect triggered:', { + logger.component('NoteList', 'useEffect triggered', { subRequests: subRequests.length, showKinds: showKinds.length, refreshCount }) - logger.debug('NoteList useEffect:', { subRequests, subRequestsLength: subRequests.length }) + if (!subRequests.length) { - console.log('❌ [NoteList] No subRequests, returning early') + logger.component('NoteList', 'No subRequests, returning early') return } // Don't initialize if showKinds is empty (still loading from provider) if (showKinds.length === 0) { - console.log('⏳ [NoteList] showKinds is empty, waiting for provider to initialize') + logger.component('NoteList', 'showKinds is empty, waiting for provider to initialize') return } async function init() { - console.log('🔄 [NoteList] Initializing feed...') + logger.component('NoteList', 'Initializing feed') setLoading(true) setEvents([]) setNewEvents([]) setHasMore(true) if (showKinds.length === 0) { - logger.warn('NoteList: showKinds is empty, no events will be displayed') + logger.component('NoteList', 'showKinds is empty, no events will be displayed') setLoading(false) setHasMore(false) return () => {} @@ -249,24 +234,17 @@ const NoteList = forwardRef( } })) - console.log('[NoteList] Subscribing to timeline with:', finalFilters) - console.log('[NoteList] showKinds:', showKinds) - const { closer, timelineKey } = await client.subscribeTimeline( finalFilters, { onEvents: (events, eosed) => { - console.log('📥 [NoteList] Received events:', { + logger.component('NoteList', 'Received events from relay', { eventsCount: events.length, eosed, - loading, - hasMore, - eventKinds: events.map(e => e.kind).slice(0, 10), // First 10 event kinds - showKinds + eventKinds: [...new Set(events.map(e => e.kind))].slice(0, 5) }) - logger.debug('NoteList received events:', { eventsCount: events.length, eosed }) + if (events.length > 0) { - console.log('✅ [NoteList] Accumulating events from relay') setEvents(prevEvents => { // For profile feeds, accumulate events from all relays // For timeline feeds, replace events @@ -276,16 +254,19 @@ const NoteList = forwardRef( // Accumulate events, removing duplicates const existingIds = new Set(prevEvents.map(e => e.id)) const newEvents = events.filter(e => !existingIds.has(e.id)) - const combined = [...prevEvents, ...newEvents] - console.log('📊 [NoteList] Profile feed - accumulated:', { - previous: prevEvents.length, - new: events.length, + logger.component('NoteList', 'Profile feed - accumulating events', { + previous: prevEvents.length, + new: events.length, unique: newEvents.length, - total: combined.length + total: prevEvents.length + newEvents.length }) - return combined + return [...prevEvents, ...newEvents] } else { // Timeline feed - replace events + logger.component('NoteList', 'Timeline feed - replacing events', { + previous: prevEvents.length, + new: events.length + }) return events } }) @@ -296,7 +277,10 @@ const NoteList = forwardRef( setHasMore(false) } if (eosed) { - console.log('🏁 [NoteList] EOSED - setting loading false, hasMore:', events.length > 0) + logger.component('NoteList', 'EOSED - all relays finished', { + eventsCount: events.length, + hasMore: events.length > 0 + }) setLoading(false) setHasMore(events.length > 0) } @@ -315,7 +299,7 @@ const NoteList = forwardRef( } }, onClose: (url, reason) => { - logger.debug('Relay connection closed:', { url, reason }) + logger.component('NoteList', 'Relay connection closed', { url, reason }) if (!showRelayCloseReason) return // ignore reasons from nostr-tools if ( @@ -344,7 +328,7 @@ const NoteList = forwardRef( const fallbackTimeout = setTimeout(() => { if (loading) { setLoading(false) - logger.debug('NoteList loading timeout - stopping after 15 seconds') + logger.component('NoteList', 'Loading timeout - stopping after 15 seconds') } }, 15000) @@ -419,7 +403,7 @@ const NoteList = forwardRef( }, 0) } - console.log('🎨 [NoteList] Rendering with state:', { + logger.component('NoteList', 'Rendering with state', { eventsCount: events.length, filteredEventsCount: filteredEvents.length, loading, @@ -447,10 +431,10 @@ const NoteList = forwardRef( ) : (