From 91667966f8bee14ea71858699dea1b5dc184b57f Mon Sep 17 00:00:00 2001 From: plebeius Date: Mon, 23 Feb 2026 18:51:42 +0800 Subject: [PATCH] perf(feeds): defer useReplies, Virtuoso for all paths, CLS fixes, memo Defer useReplies to hover-only in CatalogPost. Memo CatalogRow and Post. Remove useWindowWidth and autoUpdate from CatalogPost. Replace display:none with opacity for images. Add width/height to img tags in catalog-row and comment-media. Use Virtuoso for all rendering paths (infinite, finite, pagination). Optimize filteredComments with Set lookup. Add Vite manual chunks for markdown, virtuoso, floating-ui. --- src/components/catalog-row/catalog-row.tsx | 37 +++--- .../comment-media/comment-media.tsx | 32 ++++- src/views/board/board.tsx | 81 +++--------- src/views/catalog/catalog.tsx | 88 +++---------- src/views/post/post.tsx | 123 ++++++++++-------- vite.config.js | 9 ++ 6 files changed, 153 insertions(+), 217 deletions(-) diff --git a/src/components/catalog-row/catalog-row.tsx b/src/components/catalog-row/catalog-row.tsx index c5724b03..21bdeca8 100644 --- a/src/components/catalog-row/catalog-row.tsx +++ b/src/components/catalog-row/catalog-row.tsx @@ -2,7 +2,7 @@ import { memo, useEffect, useMemo, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; import { useTranslation } from 'react-i18next'; import { Link, useLocation, useParams } from 'react-router-dom'; -import { useFloating, offset, size, autoUpdate, Placement } from '@floating-ui/react'; +import { useFloating, offset, size, Placement } from '@floating-ui/react'; import { Comment, useReplies } from '@plebbit/plebbit-react-hooks'; import Plebbit from '@plebbit/plebbit-js'; import { shouldShowSnow } from '../../lib/snow'; @@ -18,7 +18,6 @@ import { useCommentMediaInfo } from '../../hooks/use-comment-media-info'; import useCountLinksInReplies from '../../hooks/use-count-links-in-replies'; import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame'; import useHide from '../../hooks/use-hide'; -import useWindowWidth from '../../hooks/use-window-width'; import { ContentPreview } from '../../views/home/popular-threads-box'; import PostMenuDesktop from '../post-desktop/post-menu-desktop'; import styles from './catalog-row.module.css'; @@ -41,7 +40,7 @@ export const CatalogPostMedia = ({ cid, commentMediaInfo, linkWidth, linkHeight const [hasError, setHasError] = useState(false); const handleLoad = () => setIsLoaded(true); const handleError = () => setHasError(true); - const loadingStyle = { display: isLoaded ? 'block' : 'none' }; + const loadingStyle = { opacity: isLoaded ? 1 : 0 }; const { imageSize } = useCatalogStyleStore(); @@ -62,6 +61,9 @@ export const CatalogPostMedia = ({ cid, commentMediaInfo, linkWidth, linkHeight displayHeight = 'unset'; } + const numericWidth = parseInt(displayWidth) || undefined; + const numericHeight = parseInt(displayHeight) || undefined; + const maxWidth = imageSize === 'Large' ? '250px' : '150px'; const maxHeight = imageSize === 'Large' ? '250px' : '150px'; @@ -75,20 +77,20 @@ export const CatalogPostMedia = ({ cid, commentMediaInfo, linkWidth, linkHeight let thumbnailComponent: React.ReactNode = null; if (type === 'gif' && gifFrameUrl && !hasError) { - thumbnailComponent = ; + thumbnailComponent = ; } else if (type === 'image' && !hasError) { - thumbnailComponent = ; + thumbnailComponent = ; } else if (type === 'video' && !hasError) { thumbnailComponent = thumbnail ? ( - + ) : ( // show first frame of the video, as a workaround for Safari not loading thumbnails