Lazy-load comment components

## Issue
~300KB savings in `ui.js` size (production, uncompressed). Mostly coming from the emoji library.

## Notes
Most of the `Comment*` components are under `CommentsList` or `LivestreamComments`, so deferring these 2 covered most of it. The exceptions are Notification and OwnComments.
This commit is contained in:
infinite-persistence 2021-10-18 23:54:59 +08:00 committed by Thomas Zarebczan
parent 0f68bad3eb
commit ef0329e03b
6 changed files with 64 additions and 38 deletions

View file

@ -1,7 +1,9 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import CommentsList from 'component/commentsList';
import Empty from 'component/common/empty'; import Empty from 'component/common/empty';
import { lazyImport } from 'util/lazyImport';
const CommentsList = lazyImport(() => import('component/commentsList' /* webpackChunkName: "comments" */));
type Props = { type Props = {
uri: string, uri: string,
@ -17,7 +19,9 @@ function ChannelDiscussion(props: Props) {
} }
return ( return (
<section className="section"> <section className="section">
<CommentsList uri={uri} linkedCommentId={linkedCommentId} commentsAreExpanded /> <React.Suspense fallback={null}>
<CommentsList uri={uri} linkedCommentId={linkedCommentId} commentsAreExpanded />
</React.Suspense>
</section> </section>
); );
} }

View file

@ -2,8 +2,10 @@
import { LIVESTREAM_EMBED_URL } from 'constants/livestream'; import { LIVESTREAM_EMBED_URL } from 'constants/livestream';
import React from 'react'; import React from 'react';
import FileTitleSection from 'component/fileTitleSection'; import FileTitleSection from 'component/fileTitleSection';
import LivestreamComments from 'component/livestreamComments';
import { useIsMobile } from 'effects/use-screensize'; import { useIsMobile } from 'effects/use-screensize';
import { lazyImport } from 'util/lazyImport';
const LivestreamComments = lazyImport(() => import('component/livestreamComments' /* webpackChunkName: "comments" */));
type Props = { type Props = {
uri: string, uri: string,
@ -54,7 +56,7 @@ export default function LivestreamLayout(props: Props) {
</div> </div>
)} )}
{isMobile && <LivestreamComments uri={uri} />} <React.Suspense fallback={null}>{isMobile && <LivestreamComments uri={uri} />}</React.Suspense>
<FileTitleSection uri={uri} livestream isLive={isLive} /> <FileTitleSection uri={uri} livestream isLive={isLive} />
</div> </div>

View file

@ -1,4 +1,5 @@
// @flow // @flow
import { lazyImport } from 'util/lazyImport';
import { formatLbryUrlForWeb } from 'util/url'; import { formatLbryUrlForWeb } from 'util/url';
import { Menu, MenuList, MenuButton, MenuItem } from '@reach/menu-button'; import { Menu, MenuList, MenuButton, MenuItem } from '@reach/menu-button';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
@ -12,9 +13,6 @@ import * as PAGES from 'constants/pages';
import Button from 'component/button'; import Button from 'component/button';
import ChannelThumbnail from 'component/channelThumbnail'; import ChannelThumbnail from 'component/channelThumbnail';
import classnames from 'classnames'; import classnames from 'classnames';
import CommentCreate from 'component/commentCreate';
import CommentReactions from 'component/commentReactions';
import CommentsReplies from 'component/commentsReplies';
import DateTime from 'component/dateTime'; import DateTime from 'component/dateTime';
import FileThumbnail from 'component/fileThumbnail'; import FileThumbnail from 'component/fileThumbnail';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
@ -24,6 +22,10 @@ import OptimizedImage from 'component/optimizedImage';
import React from 'react'; import React from 'react';
import UriIndicator from 'component/uriIndicator'; import UriIndicator from 'component/uriIndicator';
const CommentCreate = lazyImport(() => import('component/commentCreate' /* webpackChunkName: "comments" */));
const CommentReactions = lazyImport(() => import('component/commentReactions' /* webpackChunkName: "comments" */));
const CommentsReplies = lazyImport(() => import('component/commentsReplies' /* webpackChunkName: "comments" */));
type Props = { type Props = {
menuButton: boolean, menuButton: boolean,
notification: WebNotification, notification: WebNotification,
@ -267,16 +269,18 @@ export default function Notification(props: Props) {
</div> </div>
{isReplying && ( {isReplying && (
<CommentCreate <React.Suspense fallback={null}>
isReply <CommentCreate
uri={notificationTarget} isReply
parentId={notification_parameters.dynamic.hash} uri={notificationTarget}
onDoneReplying={() => setReplying(false)} parentId={notification_parameters.dynamic.hash}
onCancelReplying={() => setReplying(false)} onDoneReplying={() => setReplying(false)}
setQuickReply={setQuickReply} onCancelReplying={() => setReplying(false)}
supportDisabled setQuickReply={setQuickReply}
shouldFetchComment supportDisabled
/> shouldFetchComment
/>
</React.Suspense>
)} )}
{quickReply && ( {quickReply && (

View file

@ -11,11 +11,11 @@ import FileRenderInline from 'component/fileRenderInline';
import FileRenderDownload from 'component/fileRenderDownload'; import FileRenderDownload from 'component/fileRenderDownload';
import RecommendedContent from 'component/recommendedContent'; import RecommendedContent from 'component/recommendedContent';
import CollectionContent from 'component/collectionContentSidebar'; import CollectionContent from 'component/collectionContentSidebar';
import CommentsList from 'component/commentsList';
import Button from 'component/button'; import Button from 'component/button';
import I18nMessage from 'component/i18nMessage'; import I18nMessage from 'component/i18nMessage';
import Empty from 'component/common/empty'; import Empty from 'component/common/empty';
const CommentsList = lazyImport(() => import('component/commentsList' /* webpackChunkName: "comments" */));
const PostViewer = lazyImport(() => import('component/postViewer' /* webpackChunkName: "postViewer" */)); const PostViewer = lazyImport(() => import('component/postViewer' /* webpackChunkName: "postViewer" */));
export const PRIMARY_PLAYER_WRAPPER_CLASS = 'file-page__video-container'; export const PRIMARY_PLAYER_WRAPPER_CLASS = 'file-page__video-container';
@ -209,7 +209,9 @@ function FilePage(props: Props) {
)} )}
{RENDER_MODES.FLOATING_MODES.includes(renderMode) && <FileTitleSection uri={uri} />} {RENDER_MODES.FLOATING_MODES.includes(renderMode) && <FileTitleSection uri={uri} />}
{commentsDisabled && <Empty text={__('The creator of this content has disabled comments.')} />} {commentsDisabled && <Empty text={__('The creator of this content has disabled comments.')} />}
{!commentsDisabled && <CommentsList uri={uri} linkedCommentId={linkedCommentId} />} <React.Suspense fallback={null}>
{!commentsDisabled && <CommentsList uri={uri} linkedCommentId={linkedCommentId} />}
</React.Suspense>
</div> </div>
{!collection && !isMarkdown && videoTheaterMode && <RecommendedContent uri={uri} />} {!collection && !isMarkdown && videoTheaterMode && <RecommendedContent uri={uri} />}
{collection && !isMarkdown && videoTheaterMode && <CollectionContent id={collectionId} uri={uri} />} {collection && !isMarkdown && videoTheaterMode && <CollectionContent id={collectionId} uri={uri} />}
@ -220,7 +222,9 @@ function FilePage(props: Props) {
{!collection && !isMarkdown && !videoTheaterMode && <RecommendedContent uri={uri} />} {!collection && !isMarkdown && !videoTheaterMode && <RecommendedContent uri={uri} />}
{isMarkdown && ( {isMarkdown && (
<div className="file-page__post-comments"> <div className="file-page__post-comments">
<CommentsList uri={uri} linkedCommentId={linkedCommentId} commentsAreExpanded /> <React.Suspense fallback={null}>
<CommentsList uri={uri} linkedCommentId={linkedCommentId} commentsAreExpanded />
</React.Suspense>
</div> </div>
)} )}
</Page> </Page>

View file

@ -1,12 +1,14 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import { lazyImport } from 'util/lazyImport';
import Page from 'component/page'; import Page from 'component/page';
import LivestreamLayout from 'component/livestreamLayout'; import LivestreamLayout from 'component/livestreamLayout';
import LivestreamComments from 'component/livestreamComments';
import analytics from 'analytics'; import analytics from 'analytics';
import Lbry from 'lbry'; import Lbry from 'lbry';
import watchLivestreamStatus from '$web/src/livestreaming/long-polling'; import watchLivestreamStatus from '$web/src/livestreaming/long-polling';
const LivestreamComments = lazyImport(() => import('component/livestreamComments' /* webpackChunkName: "comments" */));
type Props = { type Props = {
uri: string, uri: string,
claim: StreamClaim, claim: StreamClaim,
@ -90,7 +92,13 @@ export default function LivestreamPage(props: Props) {
noFooter noFooter
livestream livestream
chatDisabled={chatDisabled} chatDisabled={chatDisabled}
rightSide={!chatDisabled && <LivestreamComments uri={uri} />} rightSide={
!chatDisabled && (
<React.Suspense fallback={null}>
<LivestreamComments uri={uri} />
</React.Suspense>
)
}
> >
<LivestreamLayout uri={uri} isLive={isLive} /> <LivestreamLayout uri={uri} isLive={isLive} />
</Page> </Page>

View file

@ -3,7 +3,6 @@ import React from 'react';
import Button from 'component/button'; import Button from 'component/button';
import ChannelSelector from 'component/channelSelector'; import ChannelSelector from 'component/channelSelector';
import ClaimPreview from 'component/claimPreview'; import ClaimPreview from 'component/claimPreview';
import Comment from 'component/comment';
import Card from 'component/common/card'; import Card from 'component/common/card';
import Empty from 'component/common/empty'; import Empty from 'component/common/empty';
import Page from 'component/page'; import Page from 'component/page';
@ -12,6 +11,9 @@ import { COMMENT_PAGE_SIZE_TOP_LEVEL } from 'constants/comment';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import useFetched from 'effects/use-fetched'; import useFetched from 'effects/use-fetched';
import debounce from 'util/debounce'; import debounce from 'util/debounce';
import { lazyImport } from 'util/lazyImport';
const Comment = lazyImport(() => import('component/comment' /* webpackChunkName: "comments" */));
function scaleToDevicePixelRatio(value) { function scaleToDevicePixelRatio(value) {
const devicePixelRatio = window.devicePixelRatio || 1.0; const devicePixelRatio = window.devicePixelRatio || 1.0;
@ -77,21 +79,23 @@ export default function OwnComments(props: Props) {
)} )}
{!contentClaim && <Empty text={__('Content or channel was deleted.')} />} {!contentClaim && <Empty text={__('Content or channel was deleted.')} />}
</div> </div>
<Comment <React.Suspense fallback={null}>
isTopLevel <Comment
hideActions isTopLevel
authorUri={comment.channel_url} hideActions
author={comment.channel_name} authorUri={comment.channel_url}
commentId={comment.comment_id} author={comment.channel_name}
message={comment.comment} commentId={comment.comment_id}
timePosted={comment.timestamp * 1000} message={comment.comment}
commentIsMine timePosted={comment.timestamp * 1000}
supportAmount={comment.support_amount} commentIsMine
numDirectReplies={0} // Don't show replies here supportAmount={comment.support_amount}
isModerator={comment.is_moderator} numDirectReplies={0} // Don't show replies here
isGlobalMod={comment.is_global_mod} isModerator={comment.is_moderator}
isFiat={comment.is_fiat} isGlobalMod={comment.is_global_mod}
/> isFiat={comment.is_fiat}
/>
</React.Suspense>
</div> </div>
</div> </div>
); );